Subversion Repositories general

Rev

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