Subversion Repositories general

Rev

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