Subversion Repositories general

Rev

Rev 1251 | Rev 1257 | 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
 
1249 dev 133
  public void getEntry(String uri, String path, IndexEntry page,
936 dev 134
      IndexEntry index, IndexEntry prev, IndexEntry current, IndexEntry next)
1242 dev 135
    throws IOException, SAXException, LogicException
936 dev 136
  {
1249 dev 137
    Branch branch = getBranch(uri);
138
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 139
 
1249 dev 140
    securePath(branch.getImagesRoot(), file);
936 dev 141
 
142
    if(!file.exists())
143
      throw new FileNotFoundException(
144
        "[" + file.getCanonicalPath() + "] not found");
145
 
146
    File   dir      = file.getParentFile();
1249 dev 147
    File[] children = dir.listFiles(branch.getImagesFilter());
936 dev 148
    int    pos;
149
 
1249 dev 150
    Arrays.sort(children, branch.getFileNameComparator());
151
    pos = Arrays.binarySearch(children, file, branch.getFileNameComparator());
936 dev 152
 
153
    if(pos < 0)
154
      throw new FileNotFoundException("[" + file.getCanonicalPath()
155
        + "] not found in [" + dir.getCanonicalPath() + "]");
156
 
1249 dev 157
    branch.getMetaInfos().clear();     // FIXME make this more intelligent
1250 dev 158
    setEntryInfo(branch, page,    file, false);
159
    setEntryInfo(branch, current, file, true);
160
    setEntryInfo(branch, index,   dir,  true);
161
    if(pos > 0)                 setEntryInfo(branch, prev, children[pos-1], true);
162
    if(pos < children.length-1) setEntryInfo(branch, next, children[pos+1], true);
936 dev 163
  }
164
 
1249 dev 165
  protected void setEntryInfo(Branch branch, IndexEntry entry, File file, boolean small)
1242 dev 166
    throws IOException, SAXException
936 dev 167
  {
168
    String title = file.getName();
169
    int[]  size;
1250 dev 170
    String path  = getPath(branch, file);
936 dev 171
 
172
    if(file.isDirectory()) {
1249 dev 173
      size = branch.getThumbnailer().getDirSize(file);
936 dev 174
    }
175
    else {
1242 dev 176
      title = FileUtils.extractFileName(title);
936 dev 177
 
178
      if(small)
1249 dev 179
        size = branch.getThumbnailer().getSmallSize(file);
1242 dev 180
      else
1249 dev 181
        size = branch.getThumbnailer().getMediumSize(file);
936 dev 182
    }
183
 
184
    entry.setFile(file);
185
    entry.setPath(path == null ? null : URLEncoder.encode(path, URL_ENCODING));
186
    entry.setTitle(title);
187
    entry.setIsDir(file.isDirectory());
188
    entry.setWidth(size[0]);
189
    entry.setHeight(size[1]);
1242 dev 190
 
1250 dev 191
    MetaInfoItem meta = findMetaInfo(branch, branch.getImagesRoot(), file);
1242 dev 192
    if(meta != null) {
193
      if(meta.getTitle() != null) {
194
        entry.setTitle(meta.getTitle());
195
      }
196
      if(meta.getSubtitle() != null) {
197
        entry.setSubtitle(meta.getSubtitle());
198
        entry.setSubtitleMime(meta.getSubtitleMime());
199
      }
200
      if(meta.getComment() != null) {
201
        entry.setComment(meta.getComment());
202
        entry.setCommentMime(meta.getCommentMime());
203
      }
204
    }
936 dev 205
  }
206
 
1249 dev 207
  public String getThumbnailMime(String uri)
1251 dev 208
    throws LogicException
936 dev 209
  {
1249 dev 210
    return getBranch(uri).getThumbnailer().getMime();
936 dev 211
  }
212
 
1249 dev 213
  public String getOriginMime(String uri, String path)
936 dev 214
    throws IOException, LogicException
215
  {
1249 dev 216
    Branch branch = getBranch(uri);
217
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 218
 
219
    if(!file.exists()) return null;
1249 dev 220
    securePath(branch.getImagesRoot(), file);
936 dev 221
 
222
    return FileUtils.getMime(FileUtils.extractFileExt(path));
223
  }
224
 
1249 dev 225
  public void writeDir(String uri, String path, OutputStream out)
936 dev 226
    throws IOException, LogicException
227
  {
1249 dev 228
    Branch branch = getBranch(uri);
229
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 230
 
1249 dev 231
    securePath(branch.getImagesRoot(), file);
232
    branch.getThumbnailer().writeDir(file, out);
936 dev 233
  }
234
 
1249 dev 235
  public void writeSmall(String uri, String path, OutputStream out)
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
 
1249 dev 241
    securePath(branch.getImagesRoot(), file);
242
    branch.getThumbnailer().writeSmall(file, out);
936 dev 243
  }
244
 
1249 dev 245
  public void writeMedium(String uri, String path, OutputStream out)
936 dev 246
    throws IOException, LogicException
247
  {
1249 dev 248
    Branch branch = getBranch(uri);
249
    File   file   = new File(branch.getImagesRoot(), path);
936 dev 250
 
1249 dev 251
    securePath(branch.getImagesRoot(), file);
252
    branch.getThumbnailer().writeMedium(file, out);
936 dev 253
  }
254
 
1249 dev 255
  public void writeOrigin(String uri, String path, OutputStream out)
936 dev 256
    throws IOException, LogicException
257
  {
1249 dev 258
    Branch          branch = getBranch(uri);
259
    FileInputStream in     = null;
260
    File            file   = new File(branch.getImagesRoot(), path);
936 dev 261
 
1249 dev 262
    securePath(branch.getImagesRoot(), file);
936 dev 263
 
264
    try {
265
      in  = new FileInputStream(file);
266
      FileUtils.copyStreams(in, out);
267
    }
268
    finally {
269
      if(in != null) in.close();
270
    }
271
  }
272
 
1249 dev 273
  protected MetaInfo getMetaInfo(Branch branch, File dir)
1242 dev 274
    throws IOException, SAXException
275
  {
1249 dev 276
    MetaInfo meta = (MetaInfo)branch.getMetaInfos().get(dir);
1242 dev 277
    if(meta != null) return meta;
278
 
279
    File metaFile = new File(dir, META_FILE_NAME);
280
    if(!metaFile.exists()) return null;
281
 
282
    meta = (MetaInfo)metaDigester.parse(new FileInputStream(metaFile));
283
    meta.setDir(dir);
1249 dev 284
    branch.getMetaInfos().put(dir, meta);
1242 dev 285
 
286
    return meta;
287
  }
288
 
1250 dev 289
  protected MetaInfoItem findMetaInfo(Branch branch, File rootDir, File file)
1242 dev 290
    throws IOException, SAXException
291
  {
292
    file    = file.getCanonicalFile();
293
    rootDir = rootDir.getCanonicalFile();
294
 
295
    File dir = file;
296
    if(!dir.isDirectory())
297
      dir = dir.getParentFile();
298
 
299
    MetaInfoItem metaItem = null;
300
    for(; metaItem == null; dir = dir.getParentFile()) {
301
      if(dir == null) break;
302
 
1250 dev 303
      MetaInfo meta = getMetaInfo(branch, dir);
1242 dev 304
      if(meta != null) {
305
        metaItem = meta.findItem(file);
306
      }
307
      if(rootDir.equals(dir)) break;
308
    }
309
 
310
    return metaItem;
311
  }
312
 
1249 dev 313
  public boolean listDirectory(String uri, String dirName, int page, List table, List pages)
1242 dev 314
    throws IOException, LogicException, SAXException
315
  {
1249 dev 316
    Branch branch = getBranch(uri);
317
    File   dir    = new File(branch.getImagesRoot(), dirName);
936 dev 318
 
1249 dev 319
    securePath(branch.getImagesRoot(), dir);
1242 dev 320
    if(!dir.exists()) return false;
936 dev 321
 
1249 dev 322
    File[] children  = dir.listFiles(branch.getImagesFilter());
323
    int    pos       = page * branch.getColumns() * branch.getRows();
936 dev 324
 
1249 dev 325
    Arrays.sort(children, branch.getFileNameComparator());
326
    branch.getMetaInfos().clear();           // FIXME do this more intelligent (?)
936 dev 327
 
1242 dev 328
    // the pages list
329
    pages.clear();
1249 dev 330
    for(int i = 0; i < (int)Math.ceil((double)children.length / branch.getColumns() / branch.getRows()); i++) {
1242 dev 331
      pages.add(new PageItem(i, i == page));
332
    }
333
 
334
    // the main table
335
    table.clear();
1249 dev 336
    while(pos < children.length && pos < (page+1) * branch.getColumns() * branch.getRows()) {
936 dev 337
      List row    = new ArrayList();
338
      int  rowPos = 0;
339
 
1242 dev 340
      table.add(row);
936 dev 341
 
1249 dev 342
      while(rowPos < branch.getColumns() && pos < children.length) {
1250 dev 343
        String path  = getPath(branch, children[pos]);
936 dev 344
        String title = children[pos].getName();
345
        int[]  size;
346
 
347
        if(children[pos].isDirectory()) {
1249 dev 348
          size  = branch.getThumbnailer().getDirSize(children[pos]);
936 dev 349
        }
350
        else {
1249 dev 351
          size  = branch.getThumbnailer().getSmallSize(children[pos]);
936 dev 352
          title = FileUtils.extractFileName(title);
353
        }
354
 
1242 dev 355
        IndexEntry entry = new IndexEntry(children[pos],
936 dev 356
          URLEncoder.encode(path, URL_ENCODING),
1242 dev 357
          title, children[pos].isDirectory(), size[0], size[1]);
358
 
1250 dev 359
        MetaInfoItem meta = findMetaInfo(branch, branch.getImagesRoot(), children[pos]);
1242 dev 360
        if(meta != null) {
361
          if(meta.getTitle() != null) {
362
            entry.setTitle(meta.getTitle());
363
          }
364
          if(meta.getSubtitle() != null) {
365
            entry.setSubtitle(meta.getSubtitle());
366
            entry.setSubtitleMime(meta.getSubtitleMime());
367
          }
368
          if(meta.getComment() != null) {
369
            entry.setComment(meta.getComment());
370
            entry.setCommentMime(meta.getCommentMime());
371
          }
372
        }
373
 
374
        row.add(entry);
936 dev 375
        rowPos++;
376
        pos++;
377
      }
378
 
1249 dev 379
      while(rowPos < branch.getColumns()) {
936 dev 380
        row.add(null);
381
        rowPos++;
382
      }
383
    }
384
 
1242 dev 385
    return true;
936 dev 386
  }
387
 
1249 dev 388
  protected String getPath(Branch branch, File file)
936 dev 389
    throws IOException
390
  {
391
    String path     = file.getCanonicalPath();
1249 dev 392
    String rootPath = branch.getImagesRoot().getCanonicalPath();
936 dev 393
 
394
    if(path.equals(rootPath)) return "";
395
    if(!rootPath.endsWith(File.separator)) rootPath += File.separator;
396
 
397
    if(!path.startsWith(rootPath))
398
      return null;
399
 
400
    return path.substring(rootPath.length());
401
  }
402
 
403
  protected static final Logic instance = new Logic();
404
 
405
  public static Logic getLogic()
406
  {
407
    return instance;
408
  }
409
 
410
  /**
411
   * checks if given file is really under the parent directory
412
   */
413
  protected void securePath(File parentDir, File file)
414
    throws IOException, LogicException
415
  {
416
    if(parentDir == null || file == null) return;
417
 
418
    File partFile = file.getCanonicalFile();
419
 
420
    parentDir = parentDir.getCanonicalFile();
421
    while(partFile != null) {
422
      if(partFile.equals(parentDir)) return;
423
      partFile = partFile.getParentFile();
424
    }
425
 
426
    throw new LogicSecurityException(
427
      "[" + file.getCanonicalPath() + "] is outside of directory ["
428
      + parentDir.getCanonicalPath() + "]");
429
  }
430
}