Subversion Repositories general

Rev

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