Subversion Repositories general

Rev

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