Subversion Repositories general

Rev

Rev 1257 | Rev 1272 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1249 dev 1
package ak.photoalbum.logic;
936 dev 2
 
3
import java.util.List;
4
import java.util.ArrayList;
5
import java.util.Arrays;
1242 dev 6
import java.util.Map;
7
import java.util.Hashtable;
1250 dev 8
import java.util.Iterator;
936 dev 9
import java.io.File;
10
import java.io.IOException;
11
import java.io.FileInputStream;
1242 dev 12
import java.io.BufferedReader;
13
import java.io.InputStreamReader;
936 dev 14
import java.io.OutputStream;
15
import java.io.FileNotFoundException;
16
import java.net.URLEncoder;
1249 dev 17
 
1242 dev 18
import org.xml.sax.SAXException;
19
import org.apache.commons.digester.Digester;
936 dev 20
import org.apache.log4j.Logger;
1249 dev 21
 
936 dev 22
import ak.photoalbum.util.FileUtils;
1250 dev 23
import ak.photoalbum.util.ResourceFactory;
1249 dev 24
import ak.photoalbum.config.ConfigRoot;
25
import ak.photoalbum.config.ConfigBranch;
26
import ak.photoalbum.config.ConfigDirThumbnail;
936 dev 27
 
28
public class Logic
29
{
30
  protected static final String URL_ENCODING    = "UTF-8";
1242 dev 31
  protected static final String META_FILE_NAME  = "meta.xml"; // FIXME make configurable (?)
936 dev 32
 
33
  protected Logger       logger;
1247 dev 34
  protected ConfigRoot   config;
1249 dev 35
  protected Map          branches           = new Hashtable(); // <String, Branch>
1247 dev 36
  protected Digester     configDigester     = createConfigDigester();
1242 dev 37
  protected Digester     metaDigester       = createMetaDigester();
936 dev 38
 
39
  protected Logic()
40
  {
41
    this.logger = Logger.getLogger(this.getClass());
42
  }
43
 
1247 dev 44
  protected Digester createConfigDigester()
936 dev 45
  {
1247 dev 46
    Digester digester = new Digester();
47
    digester.setValidating(false);
48
 
1251 dev 49
    digester.addObjectCreate(      "photos",                                ConfigRoot.class);
50
    digester.addBeanPropertySetter("photos/default-branch",                 "defaultBranch");
1247 dev 51
 
1251 dev 52
    digester.addObjectCreate(      "photos/branch",                         ConfigBranch.class);
53
    digester.addBeanPropertySetter("photos/branch/uri");
54
    digester.addBeanPropertySetter("photos/branch/images-root",             "imagesRoot");
55
    digester.addBeanPropertySetter("photos/branch/cache-dir",               "cacheDir");
56
    digester.addBeanPropertySetter("photos/branch/thumbnail-format",        "thumbnailFormat");
57
    digester.addBeanPropertySetter("photos/branch/columns");
58
    digester.addBeanPropertySetter("photos/branch/rows");
59
    digester.addCallMethod(        "photos/branch/images-mask",             "addImagesMask",
60
      0, new Class[] { String.class });
61
    digester.addBeanPropertySetter("photos/branch/dir-thumbnail/template",  "dirTemplate");
1247 dev 62
 
1251 dev 63
    digester.addObjectCreate(      "photos/branch/dir-thumbnail/thumbnail", ConfigDirThumbnail.class);
64
    digester.addBeanPropertySetter("photos/branch/dir-thumbnail/thumbnail/left");
65
    digester.addBeanPropertySetter("photos/branch/dir-thumbnail/thumbnail/top");
66
    digester.addBeanPropertySetter("photos/branch/dir-thumbnail/thumbnail/width");
67
    digester.addBeanPropertySetter("photos/branch/dir-thumbnail/thumbnail/height");
68
    digester.addBeanPropertySetter("photos/branch/dir-thumbnail/thumbnail/align");
69
    digester.addBeanPropertySetter("photos/branch/dir-thumbnail/thumbnail/valign");
1255 dev 70
    digester.addSetNext(           "photos/branch/dir-thumbnail/thumbnail", "addDirThumbnail");
1247 dev 71
 
1251 dev 72
    digester.addSetNext(           "photos/branch",                         "addBranch");
73
 
1247 dev 74
    return digester;
75
  }
76
 
77
  protected Digester createMetaDigester()
78
  {
79
    Digester digester = new Digester();
80
    digester.setValidating(false);
81
 
82
    digester.addObjectCreate("meta", MetaInfo.class);
83
 
84
    digester.addObjectCreate("meta/item", MetaInfoItem.class);
85
    digester.addSetProperties("meta/item", "id", "id");
86
    digester.addBeanPropertySetter("meta/item/title", "title");
87
    digester.addBeanPropertySetter("meta/item/subtitle", "subtitle");
88
    digester.addSetProperties("meta/item/subtitle", "mime", "subtitleMime");
89
    digester.addBeanPropertySetter("meta/item/comment", "comment");
90
    digester.addSetProperties("meta/item/comment", "mime", "commentMime");
91
    digester.addSetNext("meta/item", "addItem");
92
 
93
    return digester;
94
  }
95
 
96
  public void init(ResourceFactory resourceFactory, String configPath)
1249 dev 97
    throws IOException, SAXException, LogicException
1247 dev 98
  {
99
    logger.info("starting");
100
    config = (ConfigRoot)configDigester.parse(resourceFactory.getAsStream(configPath));
936 dev 101
 
1250 dev 102
    for(Iterator i = config.getBranches().iterator(); i.hasNext(); ) {
103
      Branch branch = new Branch(resourceFactory, (ConfigBranch)i.next());
104
      branches.put(branch.getUri(), branch);
1249 dev 105
    }
936 dev 106
 
107
    logger.info("started");
108
  }
109
 
1249 dev 110
  public Branch getBranch(String uri)
1251 dev 111
    throws LogicException
1249 dev 112
  {
1251 dev 113
    if(uri == null || uri.equals("")) {
114
      uri = config.getDefaultBranch();
115
      if(uri == null)
116
        throw new LogicException("No default branch configured");
117
    }
118
 
119
    Branch branch = (Branch)branches.get(uri);
120
 
121
    if(branch == null) 
122
      throw new LogicException("Branch not found");
123
 
124
    return branch;
1249 dev 125
  }
126
 
127
  public void buildCache(String uri)
1251 dev 128
    throws IOException, LogicException
936 dev 129
  {
1249 dev 130
    getBranch(uri).getThumbnailer().buildCache();
936 dev 131
  }
132
 
1257 dev 133
  public void rebuildCache(String uri)
134
    throws IOException, LogicException
135
  {
136
    getBranch(uri).getThumbnailer().rebuildCache();
137
  }
138
 
139
  public void deleteCache(String uri)
140
    throws IOException, LogicException
141
  {
142
    getBranch(uri).getThumbnailer().deleteCache();
143
  }
144
 
145
  public void reloadCache(String uri)
146
    throws IOException, LogicException
147
  {
148
    getBranch(uri).getThumbnailer().reloadCache();
149
  }
150
 
1249 dev 151
  public void getEntry(String uri, String path, IndexEntry page,
936 dev 152
      IndexEntry index, IndexEntry prev, IndexEntry current, IndexEntry next)
1242 dev 153
    throws IOException, SAXException, LogicException
936 dev 154
  {
1249 dev 155
    Branch branch = getBranch(uri);
156
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 157
 
1249 dev 158
    securePath(branch.getImagesRoot(), file);
936 dev 159
 
160
    if(!file.exists())
161
      throw new FileNotFoundException(
162
        "[" + file.getCanonicalPath() + "] not found");
163
 
164
    File   dir      = file.getParentFile();
1249 dev 165
    File[] children = dir.listFiles(branch.getImagesFilter());
936 dev 166
    int    pos;
167
 
1249 dev 168
    Arrays.sort(children, branch.getFileNameComparator());
169
    pos = Arrays.binarySearch(children, file, branch.getFileNameComparator());
936 dev 170
 
171
    if(pos < 0)
172
      throw new FileNotFoundException("[" + file.getCanonicalPath()
173
        + "] not found in [" + dir.getCanonicalPath() + "]");
174
 
1267 dev 175
    // calc page number in index
176
    index.setPage(pos / branch.getColumns() / branch.getRows());
177
 
1249 dev 178
    branch.getMetaInfos().clear();     // FIXME make this more intelligent
1250 dev 179
    setEntryInfo(branch, page,    file, false);
180
    setEntryInfo(branch, current, file, true);
181
    setEntryInfo(branch, index,   dir,  true);
182
    if(pos > 0)                 setEntryInfo(branch, prev, children[pos-1], true);
183
    if(pos < children.length-1) setEntryInfo(branch, next, children[pos+1], true);
936 dev 184
  }
185
 
1249 dev 186
  protected void setEntryInfo(Branch branch, IndexEntry entry, File file, boolean small)
1242 dev 187
    throws IOException, SAXException
936 dev 188
  {
189
    String title = file.getName();
190
    int[]  size;
1250 dev 191
    String path  = getPath(branch, file);
936 dev 192
 
193
    if(file.isDirectory()) {
1249 dev 194
      size = branch.getThumbnailer().getDirSize(file);
936 dev 195
    }
196
    else {
1242 dev 197
      title = FileUtils.extractFileName(title);
936 dev 198
 
199
      if(small)
1249 dev 200
        size = branch.getThumbnailer().getSmallSize(file);
1242 dev 201
      else
1249 dev 202
        size = branch.getThumbnailer().getMediumSize(file);
936 dev 203
    }
204
 
205
    entry.setFile(file);
206
    entry.setPath(path == null ? null : URLEncoder.encode(path, URL_ENCODING));
207
    entry.setTitle(title);
208
    entry.setIsDir(file.isDirectory());
209
    entry.setWidth(size[0]);
210
    entry.setHeight(size[1]);
1242 dev 211
 
1250 dev 212
    MetaInfoItem meta = findMetaInfo(branch, branch.getImagesRoot(), file);
1242 dev 213
    if(meta != null) {
214
      if(meta.getTitle() != null) {
215
        entry.setTitle(meta.getTitle());
216
      }
217
      if(meta.getSubtitle() != null) {
218
        entry.setSubtitle(meta.getSubtitle());
219
        entry.setSubtitleMime(meta.getSubtitleMime());
220
      }
221
      if(meta.getComment() != null) {
222
        entry.setComment(meta.getComment());
223
        entry.setCommentMime(meta.getCommentMime());
224
      }
225
    }
936 dev 226
  }
227
 
1249 dev 228
  public String getThumbnailMime(String uri)
1251 dev 229
    throws LogicException
936 dev 230
  {
1249 dev 231
    return getBranch(uri).getThumbnailer().getMime();
936 dev 232
  }
233
 
1249 dev 234
  public String getOriginMime(String uri, String path)
936 dev 235
    throws IOException, LogicException
236
  {
1249 dev 237
    Branch branch = getBranch(uri);
238
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 239
 
240
    if(!file.exists()) return null;
1249 dev 241
    securePath(branch.getImagesRoot(), file);
936 dev 242
 
243
    return FileUtils.getMime(FileUtils.extractFileExt(path));
244
  }
245
 
1249 dev 246
  public void writeDir(String uri, String path, OutputStream out)
936 dev 247
    throws IOException, LogicException
248
  {
1249 dev 249
    Branch branch = getBranch(uri);
250
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 251
 
1249 dev 252
    securePath(branch.getImagesRoot(), file);
253
    branch.getThumbnailer().writeDir(file, out);
936 dev 254
  }
255
 
1249 dev 256
  public void writeSmall(String uri, String path, OutputStream out)
936 dev 257
    throws IOException, LogicException
258
  {
1249 dev 259
    Branch branch = getBranch(uri);
260
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 261
 
1249 dev 262
    securePath(branch.getImagesRoot(), file);
263
    branch.getThumbnailer().writeSmall(file, out);
936 dev 264
  }
265
 
1249 dev 266
  public void writeMedium(String uri, String path, OutputStream out)
936 dev 267
    throws IOException, LogicException
268
  {
1249 dev 269
    Branch branch = getBranch(uri);
270
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 271
 
1249 dev 272
    securePath(branch.getImagesRoot(), file);
273
    branch.getThumbnailer().writeMedium(file, out);
936 dev 274
  }
275
 
1249 dev 276
  public void writeOrigin(String uri, String path, OutputStream out)
936 dev 277
    throws IOException, LogicException
278
  {
1249 dev 279
    Branch          branch = getBranch(uri);
280
    FileInputStream in     = null;
281
    File            file   = new File(branch.getImagesRoot(), path);
936 dev 282
 
1249 dev 283
    securePath(branch.getImagesRoot(), file);
936 dev 284
 
285
    try {
286
      in  = new FileInputStream(file);
287
      FileUtils.copyStreams(in, out);
288
    }
289
    finally {
290
      if(in != null) in.close();
291
    }
292
  }
293
 
1249 dev 294
  protected MetaInfo getMetaInfo(Branch branch, File dir)
1242 dev 295
    throws IOException, SAXException
296
  {
1249 dev 297
    MetaInfo meta = (MetaInfo)branch.getMetaInfos().get(dir);
1242 dev 298
    if(meta != null) return meta;
299
 
300
    File metaFile = new File(dir, META_FILE_NAME);
301
    if(!metaFile.exists()) return null;
302
 
303
    meta = (MetaInfo)metaDigester.parse(new FileInputStream(metaFile));
304
    meta.setDir(dir);
1249 dev 305
    branch.getMetaInfos().put(dir, meta);
1242 dev 306
 
307
    return meta;
308
  }
309
 
1250 dev 310
  protected MetaInfoItem findMetaInfo(Branch branch, File rootDir, File file)
1242 dev 311
    throws IOException, SAXException
312
  {
313
    file    = file.getCanonicalFile();
314
    rootDir = rootDir.getCanonicalFile();
315
 
316
    File dir = file;
317
    if(!dir.isDirectory())
318
      dir = dir.getParentFile();
319
 
320
    MetaInfoItem metaItem = null;
321
    for(; metaItem == null; dir = dir.getParentFile()) {
322
      if(dir == null) break;
323
 
1250 dev 324
      MetaInfo meta = getMetaInfo(branch, dir);
1242 dev 325
      if(meta != null) {
326
        metaItem = meta.findItem(file);
327
      }
328
      if(rootDir.equals(dir)) break;
329
    }
330
 
331
    return metaItem;
332
  }
333
 
1249 dev 334
  public boolean listDirectory(String uri, String dirName, int page, List table, List pages)
1242 dev 335
    throws IOException, LogicException, SAXException
336
  {
1249 dev 337
    Branch branch = getBranch(uri);
338
    File   dir    = new File(branch.getImagesRoot(), dirName);
936 dev 339
 
1249 dev 340
    securePath(branch.getImagesRoot(), dir);
1242 dev 341
    if(!dir.exists()) return false;
936 dev 342
 
1249 dev 343
    File[] children  = dir.listFiles(branch.getImagesFilter());
344
    int    pos       = page * branch.getColumns() * branch.getRows();
936 dev 345
 
1249 dev 346
    Arrays.sort(children, branch.getFileNameComparator());
347
    branch.getMetaInfos().clear();           // FIXME do this more intelligent (?)
936 dev 348
 
1242 dev 349
    // the pages list
350
    pages.clear();
1249 dev 351
    for(int i = 0; i < (int)Math.ceil((double)children.length / branch.getColumns() / branch.getRows()); i++) {
1242 dev 352
      pages.add(new PageItem(i, i == page));
353
    }
354
 
355
    // the main table
356
    table.clear();
1249 dev 357
    while(pos < children.length && pos < (page+1) * branch.getColumns() * branch.getRows()) {
936 dev 358
      List row    = new ArrayList();
359
      int  rowPos = 0;
360
 
1242 dev 361
      table.add(row);
936 dev 362
 
1249 dev 363
      while(rowPos < branch.getColumns() && pos < children.length) {
1250 dev 364
        String path  = getPath(branch, children[pos]);
936 dev 365
        String title = children[pos].getName();
366
        int[]  size;
367
 
368
        if(children[pos].isDirectory()) {
1249 dev 369
          size  = branch.getThumbnailer().getDirSize(children[pos]);
936 dev 370
        }
371
        else {
1249 dev 372
          size  = branch.getThumbnailer().getSmallSize(children[pos]);
936 dev 373
          title = FileUtils.extractFileName(title);
374
        }
375
 
1242 dev 376
        IndexEntry entry = new IndexEntry(children[pos],
936 dev 377
          URLEncoder.encode(path, URL_ENCODING),
1242 dev 378
          title, children[pos].isDirectory(), size[0], size[1]);
379
 
1250 dev 380
        MetaInfoItem meta = findMetaInfo(branch, branch.getImagesRoot(), children[pos]);
1242 dev 381
        if(meta != null) {
382
          if(meta.getTitle() != null) {
383
            entry.setTitle(meta.getTitle());
384
          }
385
          if(meta.getSubtitle() != null) {
386
            entry.setSubtitle(meta.getSubtitle());
387
            entry.setSubtitleMime(meta.getSubtitleMime());
388
          }
389
          if(meta.getComment() != null) {
390
            entry.setComment(meta.getComment());
391
            entry.setCommentMime(meta.getCommentMime());
392
          }
393
        }
394
 
395
        row.add(entry);
936 dev 396
        rowPos++;
397
        pos++;
398
      }
399
 
1249 dev 400
      while(rowPos < branch.getColumns()) {
936 dev 401
        row.add(null);
402
        rowPos++;
403
      }
404
    }
405
 
1242 dev 406
    return true;
936 dev 407
  }
408
 
1249 dev 409
  protected String getPath(Branch branch, File file)
936 dev 410
    throws IOException
411
  {
412
    String path     = file.getCanonicalPath();
1249 dev 413
    String rootPath = branch.getImagesRoot().getCanonicalPath();
936 dev 414
 
415
    if(path.equals(rootPath)) return "";
416
    if(!rootPath.endsWith(File.separator)) rootPath += File.separator;
417
 
418
    if(!path.startsWith(rootPath))
419
      return null;
420
 
421
    return path.substring(rootPath.length());
422
  }
423
 
424
  protected static final Logic instance = new Logic();
425
 
426
  public static Logic getLogic()
427
  {
428
    return instance;
429
  }
430
 
431
  /**
432
   * checks if given file is really under the parent directory
433
   */
434
  protected void securePath(File parentDir, File file)
435
    throws IOException, LogicException
436
  {
437
    if(parentDir == null || file == null) return;
438
 
439
    File partFile = file.getCanonicalFile();
440
 
441
    parentDir = parentDir.getCanonicalFile();
442
    while(partFile != null) {
443
      if(partFile.equals(parentDir)) return;
444
      partFile = partFile.getParentFile();
445
    }
446
 
447
    throw new LogicSecurityException(
448
      "[" + file.getCanonicalPath() + "] is outside of directory ["
449
      + parentDir.getCanonicalPath() + "]");
450
  }
451
}