Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
936 | dev | 1 | package ak.photoalbum.webapp; |
2 | |||
3 | import java.util.List; |
||
4 | import java.util.ArrayList; |
||
5 | import java.util.Arrays; |
||
6 | import java.util.Comparator; |
||
7 | import java.util.StringTokenizer; |
||
8 | import java.io.File; |
||
9 | import java.io.IOException; |
||
10 | import java.io.FileInputStream; |
||
11 | import java.io.OutputStream; |
||
12 | import java.io.UnsupportedEncodingException; |
||
13 | import java.io.FileNotFoundException; |
||
14 | import java.net.URLEncoder; |
||
15 | import org.apache.log4j.Logger; |
||
16 | import ak.photoalbum.images.Thumbnailer; |
||
17 | import ak.photoalbum.images.ThumbnailPosition; |
||
18 | import ak.photoalbum.util.FileUtils; |
||
19 | import ak.photoalbum.util.FileNameComparator; |
||
20 | import ak.photoalbum.util.ImagesFilter; |
||
21 | |||
22 | public class Logic |
||
23 | { |
||
24 | protected static final int DEFAULT_COLUMNS = 4; |
||
25 | protected static final String URL_ENCODING = "UTF-8"; |
||
26 | |||
27 | protected Logger logger; |
||
28 | protected Thumbnailer thumbnailer; |
||
29 | protected File imagesRoot; |
||
30 | protected int columns = DEFAULT_COLUMNS; |
||
31 | protected ImagesFilter imagesFilter; |
||
32 | protected Comparator fileNameComparator = new FileNameComparator(true); |
||
33 | |||
34 | protected Logic() |
||
35 | { |
||
36 | this.logger = Logger.getLogger(this.getClass()); |
||
37 | } |
||
38 | |||
39 | public void init(String imagesRoot, String imagesMask, |
||
40 | String cacheDir, String thumbnailFormat, |
||
41 | Integer smallWidth, Integer smallHeight, |
||
42 | Integer mediumWidth, Integer mediumHeight, Integer columns, |
||
43 | String dirTemplate, String dirThumbnailPositions) |
||
44 | { |
||
45 | this.imagesRoot = new File(imagesRoot); |
||
46 | this.imagesFilter = new ImagesFilter(imagesMask); |
||
47 | if(columns != null) this.columns = columns.intValue(); |
||
48 | |||
49 | this.thumbnailer = new Thumbnailer(); |
||
50 | this.thumbnailer.setImagesRoot(this.imagesRoot); |
||
51 | this.thumbnailer.setCacheDir(new File(cacheDir)); |
||
52 | |||
53 | if(thumbnailFormat != null) |
||
54 | this.thumbnailer.setFormat(thumbnailFormat); |
||
55 | if(smallWidth != null) |
||
56 | this.thumbnailer.setSmallWidth(smallWidth.intValue()); |
||
57 | if(smallHeight != null) |
||
58 | this.thumbnailer.setSmallHeight(smallHeight.intValue()); |
||
59 | if(mediumWidth != null) |
||
60 | this.thumbnailer.setMediumWidth(mediumWidth.intValue()); |
||
61 | if(mediumHeight != null) |
||
62 | this.thumbnailer.setMediumHeight(mediumHeight.intValue()); |
||
63 | |||
64 | thumbnailer.setResizer(new ak.photoalbum.images.jiu.JiuResizer()); |
||
65 | thumbnailer.setImagesFilter(this.imagesFilter); |
||
66 | thumbnailer.setDirTemplate(new File(dirTemplate)); |
||
67 | thumbnailer.setDirThumbnailPositions( |
||
68 | parseThumbnailPositions(dirThumbnailPositions)); |
||
69 | |||
70 | try { |
||
71 | thumbnailer.startup(); |
||
72 | } |
||
73 | catch(Exception ex) { |
||
74 | logger.error("init thumbnailer", ex); |
||
75 | } |
||
76 | |||
77 | logger.info("started"); |
||
78 | } |
||
79 | |||
80 | public void buildCache() |
||
81 | throws IOException |
||
82 | { |
||
83 | thumbnailer.buildCache(); |
||
84 | } |
||
85 | |||
86 | public void getEntry(String path, IndexEntry page, |
||
87 | IndexEntry index, IndexEntry prev, IndexEntry current, IndexEntry next) |
||
88 | throws IOException, LogicException |
||
89 | { |
||
90 | File file = new File(imagesRoot, path); |
||
91 | |||
92 | securePath(imagesRoot, file); |
||
93 | |||
94 | if(!file.exists()) |
||
95 | throw new FileNotFoundException( |
||
96 | "[" + file.getCanonicalPath() + "] not found"); |
||
97 | |||
98 | File dir = file.getParentFile(); |
||
99 | File[] children = dir.listFiles(imagesFilter); |
||
100 | int pos; |
||
101 | |||
102 | Arrays.sort(children, fileNameComparator); |
||
103 | pos = Arrays.binarySearch(children, file, fileNameComparator); |
||
104 | |||
105 | if(pos < 0) |
||
106 | throw new FileNotFoundException("[" + file.getCanonicalPath() |
||
107 | + "] not found in [" + dir.getCanonicalPath() + "]"); |
||
108 | |||
109 | setEntryInfo(page, file, false); |
||
110 | setEntryInfo(current, file, true); |
||
111 | setEntryInfo(index, dir, true); |
||
112 | if(pos > 0) setEntryInfo(prev, children[pos-1], true); |
||
113 | if(pos < children.length-1) setEntryInfo(next, children[pos+1], true); |
||
114 | } |
||
115 | |||
116 | protected void setEntryInfo(IndexEntry entry, File file, boolean small) |
||
117 | throws IOException |
||
118 | { |
||
119 | String title = file.getName(); |
||
120 | int[] size; |
||
121 | String path = getPath(file); |
||
122 | |||
123 | if(file.isDirectory()) { |
||
124 | size = thumbnailer.getDirSize(file); |
||
125 | } |
||
126 | else { |
||
127 | title = FileUtils.extractFileName(title); |
||
128 | |||
129 | if(small) |
||
130 | size = thumbnailer.getSmallSize(file); |
||
131 | else |
||
132 | size = thumbnailer.getMediumSize(file); |
||
133 | } |
||
134 | |||
135 | entry.setFile(file); |
||
136 | entry.setPath(path == null ? null : URLEncoder.encode(path, URL_ENCODING)); |
||
137 | entry.setTitle(title); |
||
138 | entry.setIsDir(file.isDirectory()); |
||
139 | entry.setWidth(size[0]); |
||
140 | entry.setHeight(size[1]); |
||
141 | } |
||
142 | |||
143 | public String getThumbnailMime() |
||
144 | { |
||
145 | return thumbnailer.getMime(); |
||
146 | } |
||
147 | |||
148 | public String getOriginMime(String path) |
||
149 | throws IOException, LogicException |
||
150 | { |
||
151 | File file = new File(imagesRoot, path); |
||
152 | |||
153 | if(!file.exists()) return null; |
||
154 | securePath(imagesRoot, file); |
||
155 | |||
156 | return FileUtils.getMime(FileUtils.extractFileExt(path)); |
||
157 | } |
||
158 | |||
159 | public void writeDir(String path, OutputStream out) |
||
160 | throws IOException, LogicException |
||
161 | { |
||
162 | File file = new File(imagesRoot, path); |
||
163 | |||
164 | securePath(imagesRoot, file); |
||
165 | thumbnailer.writeDir(file, out); |
||
166 | } |
||
167 | |||
168 | public void writeSmall(String path, OutputStream out) |
||
169 | throws IOException, LogicException |
||
170 | { |
||
171 | File file = new File(imagesRoot, path); |
||
172 | |||
173 | securePath(imagesRoot, file); |
||
174 | thumbnailer.writeSmall(file, out); |
||
175 | } |
||
176 | |||
177 | public void writeMedium(String path, OutputStream out) |
||
178 | throws IOException, LogicException |
||
179 | { |
||
180 | File file = new File(imagesRoot, path); |
||
181 | |||
182 | securePath(imagesRoot, file); |
||
183 | thumbnailer.writeMedium(file, out); |
||
184 | } |
||
185 | |||
186 | public void writeOrigin(String path, OutputStream out) |
||
187 | throws IOException, LogicException |
||
188 | { |
||
189 | FileInputStream in = null; |
||
190 | File file = new File(imagesRoot, path); |
||
191 | |||
192 | securePath(imagesRoot, file); |
||
193 | |||
194 | try { |
||
195 | in = new FileInputStream(file); |
||
196 | FileUtils.copyStreams(in, out); |
||
197 | } |
||
198 | finally { |
||
199 | if(in != null) in.close(); |
||
200 | } |
||
201 | } |
||
202 | |||
203 | public List listDirectory(String dirName) |
||
204 | throws UnsupportedEncodingException, IOException, LogicException |
||
205 | { |
||
206 | File dir = new File(imagesRoot, dirName); |
||
207 | |||
208 | securePath(imagesRoot, dir); |
||
209 | if(!dir.exists()) return null; |
||
210 | |||
211 | File[] children = dir.listFiles(imagesFilter); |
||
212 | List rows = new ArrayList(); |
||
213 | int pos = 0; |
||
214 | |||
215 | Arrays.sort(children, fileNameComparator); |
||
216 | |||
217 | while(pos < children.length) { |
||
218 | List row = new ArrayList(); |
||
219 | int rowPos = 0; |
||
220 | |||
221 | rows.add(row); |
||
222 | |||
223 | while(rowPos < columns && pos < children.length) { |
||
224 | String path = getPath(children[pos]); |
||
225 | String title = children[pos].getName(); |
||
226 | int[] size; |
||
227 | |||
228 | if(children[pos].isDirectory()) { |
||
229 | size = thumbnailer.getDirSize(children[pos]); |
||
230 | } |
||
231 | else { |
||
232 | size = thumbnailer.getSmallSize(children[pos]); |
||
233 | title = FileUtils.extractFileName(title); |
||
234 | } |
||
235 | |||
236 | row.add(new IndexEntry(children[pos], |
||
237 | URLEncoder.encode(path, URL_ENCODING), |
||
238 | title, children[pos].isDirectory(), size[0], size[1])); |
||
239 | rowPos++; |
||
240 | pos++; |
||
241 | } |
||
242 | |||
243 | while(rowPos < columns) { |
||
244 | row.add(null); |
||
245 | rowPos++; |
||
246 | } |
||
247 | } |
||
248 | |||
249 | return rows; |
||
250 | } |
||
251 | |||
252 | protected String getPath(File file) |
||
253 | throws IOException |
||
254 | { |
||
255 | String path = file.getCanonicalPath(); |
||
256 | String rootPath = imagesRoot.getCanonicalPath(); |
||
257 | |||
258 | if(path.equals(rootPath)) return ""; |
||
259 | if(!rootPath.endsWith(File.separator)) rootPath += File.separator; |
||
260 | |||
261 | if(!path.startsWith(rootPath)) |
||
262 | return null; |
||
263 | |||
264 | return path.substring(rootPath.length()); |
||
265 | } |
||
266 | |||
267 | protected ThumbnailPosition[] parseThumbnailPositions(String str) |
||
268 | { |
||
269 | List list = new ArrayList(); |
||
270 | StringTokenizer tokenizer = new StringTokenizer(str, ";"); |
||
271 | |||
272 | while(tokenizer.hasMoreTokens()) { |
||
273 | StringTokenizer tokenParser |
||
274 | = new StringTokenizer(tokenizer.nextToken(), ","); |
||
275 | int x = Integer.parseInt(tokenParser.nextToken().trim()); |
||
276 | int y = Integer.parseInt(tokenParser.nextToken().trim()); |
||
277 | int width = Integer.parseInt(tokenParser.nextToken().trim()); |
||
278 | int height = Integer.parseInt(tokenParser.nextToken().trim()); |
||
279 | String horAlignStr = tokenParser.nextToken().trim().toLowerCase(); |
||
280 | String vertAlignStr = tokenParser.nextToken().trim().toLowerCase(); |
||
281 | int horAlign; |
||
282 | int vertAlign; |
||
283 | |||
284 | if("l".equals(horAlignStr)) |
||
285 | horAlign = ThumbnailPosition.ALIGN_HOR_LEFT; |
||
286 | else if("r".equals(horAlignStr)) |
||
287 | horAlign = ThumbnailPosition.ALIGN_HOR_RIGHT; |
||
288 | else if("c".equals(horAlignStr)) |
||
289 | horAlign = ThumbnailPosition.ALIGN_HOR_CENTER; |
||
290 | else |
||
291 | throw new RuntimeException( |
||
292 | "Cannot parse " + horAlignStr + " as horizontal alignment"); |
||
293 | |||
294 | if("t".equals(vertAlignStr)) |
||
295 | vertAlign = ThumbnailPosition.ALIGN_VERT_TOP; |
||
296 | else if("b".equals(vertAlignStr)) |
||
297 | vertAlign = ThumbnailPosition.ALIGN_VERT_BOTTOM; |
||
298 | else if("c".equals(vertAlignStr)) |
||
299 | vertAlign = ThumbnailPosition.ALIGN_VERT_CENTER; |
||
300 | else |
||
301 | throw new RuntimeException( |
||
302 | "Cannot parse " + vertAlignStr + " as vertical alignment"); |
||
303 | |||
304 | list.add(new ThumbnailPosition(x, y, width, height, horAlign, vertAlign)); |
||
305 | } |
||
306 | |||
307 | ThumbnailPosition[] res = new ThumbnailPosition[list.size()]; |
||
308 | |||
309 | for(int i = 0; i < res.length; i++) |
||
310 | res[i] = (ThumbnailPosition)list.get(i); |
||
311 | |||
312 | return res; |
||
313 | } |
||
314 | |||
315 | protected static final Logic instance = new Logic(); |
||
316 | |||
317 | public static Logic getLogic() |
||
318 | { |
||
319 | return instance; |
||
320 | } |
||
321 | |||
322 | /** |
||
323 | * checks if given file is really under the parent directory |
||
324 | */ |
||
325 | protected void securePath(File parentDir, File file) |
||
326 | throws IOException, LogicException |
||
327 | { |
||
328 | if(parentDir == null || file == null) return; |
||
329 | |||
330 | File partFile = file.getCanonicalFile(); |
||
331 | |||
332 | parentDir = parentDir.getCanonicalFile(); |
||
333 | while(partFile != null) { |
||
334 | if(partFile.equals(parentDir)) return; |
||
335 | partFile = partFile.getParentFile(); |
||
336 | } |
||
337 | |||
338 | throw new LogicSecurityException( |
||
339 | "[" + file.getCanonicalPath() + "] is outside of directory [" |
||
340 | + parentDir.getCanonicalPath() + "]"); |
||
341 | } |
||
342 | } |