Subversion Repositories general

Rev

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