Coverage Report - org.paneris.bibliomania.Chapter
 
Classes in this File Line Coverage Branch Coverage Complexity
Chapter
62%
105/167
44%
17/38
1.726
Chapter$1
83%
5/6
N/A
1.726
Chapter$PageBody
40%
4/10
N/A
1.726
 
 1  
 package org.paneris.bibliomania;
 2  
 
 3  
 import java.io.BufferedOutputStream;
 4  
 import java.io.BufferedWriter;
 5  
 import java.io.File;
 6  
 import java.io.FileInputStream;
 7  
 import java.io.FileOutputStream;
 8  
 import java.io.FileWriter;
 9  
 import java.io.IOException;
 10  
 import java.io.InputStream;
 11  
 import java.io.InputStreamReader;
 12  
 import java.io.Reader;
 13  
 import java.io.Writer;
 14  
 import java.sql.Timestamp;
 15  
 import java.util.Enumeration;
 16  
 import java.util.Hashtable;
 17  
 import java.util.Map;
 18  
 
 19  
 import org.melati.Melati;
 20  
 import org.melati.admin.AdminSpecialised;
 21  
 import org.melati.poem.AccessPoemException;
 22  
 import org.melati.poem.CachedSelection;
 23  
 import org.melati.poem.Capability;
 24  
 import org.melati.poem.PoemThread;
 25  
 import org.melati.poem.Table;
 26  
 import org.melati.template.MarkupLanguage;
 27  
 import org.melati.poem.util.EmptyEnumeration;
 28  
 import org.melati.poem.util.IntegerEnumeration;
 29  
 import org.melati.util.IoUtils;
 30  
 import org.melati.poem.Treeable;
 31  
 import org.melati.util.UnexpectedExceptionException;
 32  
 import org.paneris.bibliomania.fti.FTIException;
 33  
 import org.paneris.bibliomania.fti.Text;
 34  
 import org.paneris.bibliomania.generated.ChapterBase;
 35  
 import org.paneris.bibliomania.pagination.Pagination;
 36  
 import org.webmacro.WebMacroException;
 37  
 
 38  
 import com.sleepycat.db.DatabaseException;
 39  
 
 40  
 public class Chapter extends ChapterBase implements Text, AdminSpecialised {
 41  7
   public Chapter() {
 42  7
   }
 43  
 
 44  
   private int pageNumber;
 45  
 
 46  
   public int getPageNumber() {
 47  8
     return pageNumber;
 48  
   }
 49  
   public int getPreviousPageNumber() {
 50  1
     return pageNumber - 1;
 51  
   }
 52  
   public int getNextPageNumber() {
 53  1
     return pageNumber + 1;
 54  
   }
 55  7
   private CachedSelection previous = null;
 56  
 
 57  
   public Chapter getPrevious() {
 58  4
     if (previous == null) {
 59  1
       ChapterTable t = getChapterTable();
 60  
 
 61  1
       String whereClause =
 62  
         t.getBookColumn().eqClause(getBook().troid())
 63  
           + " AND "
 64  
           + t.getSequenceColumn().eqClause(
 65  
             new Integer(getSequence().intValue() - 1));
 66  
 
 67  1
       previous = new CachedSelection(t, whereClause, null);
 68  
     }
 69  
 
 70  4
     return (Chapter)previous.firstObject();
 71  
   }
 72  
 
 73  7
   private CachedSelection next = null;
 74  
 
 75  
   public Chapter getNext() {
 76  8
     if (next == null) {
 77  1
       ChapterTable t = getChapterTable();
 78  
 
 79  1
       String whereClause =
 80  
         t.getBookColumn().eqClause(getBook().troid())
 81  
           + " AND "
 82  
           + t.getSequenceColumn().eqClause(
 83  
             new Integer(getSequence().intValue() + 1));
 84  
 
 85  1
       next = new CachedSelection(t, whereClause, null);
 86  
     }
 87  
 
 88  8
     return (Chapter)next.firstObject();
 89  
   }
 90  
 
 91  
   public Advert getAdvert() {
 92  0
     return getBook().getAdvert();
 93  
   }
 94  
   public Layout getLayout() {
 95  4
     return getBook().getLayout();
 96  
   }
 97  
 
 98  
   public Boolean getPaginated() {
 99  0
     return getBook().getPaginated();
 100  
   }
 101  
 
 102  
   public String getFilepath() {
 103  11
     return getPath() + getFilename();
 104  
   }
 105  
 
 106  
   public void setFilepath(String path, String filename) {
 107  5
     setPath(path.charAt(path.length() - 1) == '/' ? path : path + '/');
 108  5
     setFilename(filename);
 109  5
   }
 110  
 
 111  
   public File originalBodyFile() {
 112  1
     return new File(
 113  
       getBibliomaniaDatabase().getContentRootDir(),
 114  
       getFilepath());
 115  
   }
 116  
 
 117  
   public InputStream originalBody() throws IOException {
 118  0
     InputStream it = new FileInputStream(originalBodyFile());
 119  0
     PoemThread.toTidy().add(it);
 120  0
     return it;
 121  
   }
 122  
 
 123  
   public void appendCacheSubpath(StringBuffer buffer) {
 124  6
     getBook().appendCacheSubpath(buffer);
 125  6
     buffer.append('/');
 126  6
     buffer.append(troid());
 127  6
   }
 128  
 
 129  
   public String getCachePath(int pageP) {
 130  2
     StringBuffer buffer = new StringBuffer();
 131  2
     appendCachePath(buffer);
 132  2
     buffer.append('/');
 133  2
     buffer.append(pageP);
 134  2
     buffer.append(".html");
 135  2
     return buffer.toString();
 136  
   }
 137  
 
 138  
   public File allPagedFile() {
 139  4
     return new File(getCachePath(), "all.html");
 140  
   }
 141  
 
 142  
   public InputStream bodyUnsafe() throws IOException {
 143  3
     InputStream it = new FileInputStream(allPagedFile());
 144  3
     PoemThread.toTidy().add(it);
 145  3
     return it;
 146  
   }
 147  
 
 148  
   public InputStream body() throws IOException {
 149  3
     Capability canReadContent = getBook().getCanReadContent();
 150  3
     if (canReadContent != null
 151  
       && !PoemThread.accessToken().givesCapability(canReadContent))
 152  0
       throw new ContentAccessPoemException(
 153  
         getBook(),
 154  
         PoemThread.accessToken(),
 155  
         canReadContent);
 156  
 
 157  3
     return bodyUnsafe();
 158  
   }
 159  
 
 160  
   public InputStream bodyForFragment() throws IOException {
 161  0
     return bodyUnsafe();
 162  
   }
 163  
 
 164  
   public String bodyText() throws IOException {
 165  0
     return new String(IoUtils.slurp(body(), 4096));
 166  
   }
 167  
 
 168  
   public static final int ftiTextID_section_shift = 32,
 169  
     ftiTextID_section_limit = 256,
 170  
     ftiTextID_author_shift = 21,
 171  
     ftiTextID_author_limit = 2048,
 172  
     ftiTextID_book_shift = 10,
 173  
     ftiTextID_book_limit = 2048,
 174  
     ftiTextID_sequence_shift = 0,
 175  
     ftiTextID_chapter_limit = 1024;
 176  
 
 177  
   public static final long ftiTextID_section_mask =
 178  
     ~((1l << ftiTextID_section_shift) - 1),
 179  
     ftiTextID_author_mask =
 180  
       ((1l << ftiTextID_section_shift) - 1)
 181  
         & ~((1l << ftiTextID_author_shift) - 1),
 182  
     ftiTextID_book_mask =
 183  
       ((1l << ftiTextID_author_shift) - 1)
 184  
         & ~((1l << ftiTextID_book_shift) - 1),
 185  
     ftiTextID_sequence_mask = (1l << ftiTextID_book_shift) - 1;
 186  
 
 187  
   public static long ftiTextID(int section, int author, int book, int seq) {
 188  
 
 189  
     // section author book seq
 190  
     //    8      11    11   10
 191  
 
 192  22
     return (((long)section) << ftiTextID_section_shift)
 193  
       | (((long)author) << ftiTextID_author_shift)
 194  
       | (((long)book) << ftiTextID_book_shift)
 195  
       | (((long)seq) << ftiTextID_sequence_shift);
 196  
   }
 197  
 
 198  
   public long ftiTextID() {
 199  22
     return ftiTextID(
 200  
       getBook().getSectionTroid().intValue(),
 201  
       getBook().getAuthorTroid().intValue(),
 202  
       getBook().getAuthorsequence().intValue(),
 203  
       sequence.intValue());
 204  
   }
 205  
 
 206  
   public long ftiTextID_start() {
 207  0
     return ftiTextID();
 208  
   }
 209  
 
 210  
   public long ftiTextID_limit() {
 211  0
     return ftiTextID() + (1L << ftiTextID_sequence_shift);
 212  
   }
 213  
 
 214  
   public Unit getParentUnit() {
 215  4
     return getBook();
 216  
   }
 217  
 
 218  
   void notifyChangedTextID() {
 219  10
     Long textidL = this.textid;
 220  10
     if (book != null && sequence != null && textidL != null) {
 221  10
       if (textidL.longValue() != ftiTextID()) {
 222  
         try {
 223  0
           getBibliomaniaDatabase().fti().unIndex(textidL.longValue());
 224  0
         } catch (Exception e) {
 225  0
           throw new FTIException(e);
 226  0
         }
 227  
 
 228  0
         setTextid(null);
 229  
       }
 230  
     }
 231  10
   }
 232  
 
 233  
   public void setBook(Book book) throws AccessPoemException {
 234  5
     super.setBook(book);
 235  5
     notifyChangedTextID();
 236  5
   }
 237  
 
 238  
   public class TooManyChaptersException extends SequenceFTILimitsException {
 239  
     private static final long serialVersionUID = 1L;
 240  
 
 241  
     public TooManyChaptersException(int seq, int limit) {
 242  
       super(seq, limit);
 243  
     }
 244  
 
 245  
     public Table getTable() {
 246  
       return getChapterTable();
 247  
     }
 248  
 
 249  
     public String getParentTable() {
 250  
       return "book";
 251  
     }
 252  
   }
 253  
 
 254  
   public void setSequence(Integer sequence) throws AccessPoemException {
 255  5
     if (sequence != null && sequence.intValue() >= ftiTextID_chapter_limit)
 256  0
       throw new TooManyChaptersException(
 257  
         sequence.intValue(),
 258  
         ftiTextID_chapter_limit);
 259  5
     super.setSequence(sequence);
 260  5
     notifyChangedTextID();
 261  5
   }
 262  
 
 263  
   public static class PageBody {
 264  
     public Object textStringOrReader;
 265  
     public Integer nextPage;
 266  
 
 267  0
     public PageBody(Reader text, Integer nextPage) {
 268  0
       textStringOrReader = text;
 269  0
       this.nextPage = nextPage;
 270  0
     }
 271  
 
 272  
     public PageBody(InputStream text, Integer nextPage) {
 273  0
       this(new InputStreamReader(text), nextPage);
 274  0
     }
 275  
 
 276  2
     public PageBody(String text, Integer nextPage) {
 277  2
       textStringOrReader = text;
 278  2
       this.nextPage = nextPage;
 279  2
     }
 280  
   }
 281  
 
 282  
   public PageBody bodyTextOfPage(Pagination.PageSpan span) throws IOException {
 283  2
     InputStream whole = body();
 284  2
     whole.skip(span.startOffset);
 285  2
     byte[] stuff = new byte[span.endOffset - span.startOffset];
 286  
 
 287  2
     return new PageBody(
 288  
       new String(stuff, 0, whole.read(stuff, 0, stuff.length)),
 289  
       span.number + 2 > span.totalPages ? null : new Integer(span.number + 2));
 290  
   }
 291  
 
 292  
   public Pagination.PageSpan spanOfPage(int pageP) {
 293  
     try {
 294  2
       return getBibliomaniaDatabase()
 295  
         .pagination()
 296  
         .new PageFinder()
 297  
         .pageOfNumber(
 298  
         ftiTextID(),
 299  
         pageP - 1);
 300  0
     } catch (DatabaseException e) {
 301  0
       throw new UnexpectedExceptionException(e);
 302  
     }
 303  
   }
 304  
 
 305  
   public Pagination.PageSpan spanOfPage(Integer pageP) {
 306  0
     return spanOfPage(pageP.intValue());
 307  
   }
 308  
 
 309  
   public PageBody bodyTextOfPage(Integer pageP) throws IOException {
 310  0
     if (pageP == null || Boolean.FALSE.equals(getPaginated()))
 311  0
       return new PageBody(body(), null);
 312  
     else {
 313  0
       Pagination.PageSpan span = spanOfPage(pageP);
 314  0
       return span == null ? new PageBody(body(), null) : bodyTextOfPage(span);
 315  
     }
 316  
   }
 317  
 
 318  
   public int totalPages() {
 319  
     try {
 320  7
       return getBibliomaniaDatabase().pagination().new PageFinder().totalPages(ftiTextID());
 321  0
     } catch (NullPointerException e) {
 322  0
       return 1; //FIXME Sticking plaster, I have no idea what is going on here, just stop the bleeding 
 323  0
     } catch (Exception e) {
 324  0
       throw new UnexpectedExceptionException(e);
 325  
     }
 326  
   }
 327  
 
 328  
   public Enumeration pageNumbers() {
 329  0
     return new IntegerEnumeration(1, totalPages());
 330  
   }
 331  
 
 332  
   public Enumeration getMembersSlowly() {
 333  1
     return new EmptyEnumeration();
 334  
   }
 335  
 
 336  
   public String getDisplayName() {
 337  0
     return getTitle();
 338  
   }
 339  
 
 340  
   public void index() throws IOException {
 341  
     try {
 342  1
       setTextid(ftiTextID()); // this does an assertCanWrite
 343  1
       getBibliomaniaDatabase().fti().index(this);
 344  0
     } catch (IOException e) {
 345  0
       throw e;
 346  0
     } catch (Exception e) {
 347  0
       throw new FTIException(e);
 348  1
     }
 349  1
   }
 350  
 
 351  
   public void unIndex() {
 352  0
     Long tid = getTextid();
 353  0
     if (tid != null)
 354  
       try {
 355  0
         getBibliomaniaDatabase().fti().unIndex(tid.longValue());
 356  0
       } catch (Exception e) {
 357  0
         throw new UnexpectedExceptionException(e);
 358  0
       }
 359  0
   }
 360  
 
 361  
   public void delete_unsafe_butCleanFTI() {
 362  0
     unIndex();
 363  0
     super.delete_unsafe();
 364  0
   }
 365  
 
 366  
   public void delete(Map integrityFixOfColumn) {
 367  0
     unIndex();
 368  0
     super.delete(integrityFixOfColumn);
 369  0
   }
 370  
 
 371  
   public void splitOutPages()
 372  
     throws WebMacroException, IOException {
 373  
 
 374  
     // this isn't as efficient as it could be but doesn't happen often
 375  
 
 376  3
     for (int p = 1; p <= totalPages(); ++p) {
 377  2
       pageNumber = p;
 378  2
       File file = new File(getCachePath(p));
 379  2
       file.getParentFile().mkdirs();
 380  2
       BufferedOutputStream w =
 381  
         new BufferedOutputStream(new FileOutputStream(file));
 382  
       try {
 383  2
         Hashtable<String, Object> extras = new Hashtable<String, Object>();
 384  2
         extras.put("pageNumber", new Integer(p));
 385  2
         extras.put("content", bodyTextOfPage(spanOfPage(p)).textStringOrReader);
 386  2
         getBibliomaniaDatabase().interpolateTemplateToFile("page.wm", file, this, extras);
 387  
       } finally {
 388  0
         try {
 389  2
           w.close();
 390  0
         } catch (Exception e) {
 391  0
           throw new RuntimeException(e);        
 392  2
         }
 393  
       }
 394  
 
 395  2
       BibliomaniaDatabase.notifyNewContentFile(file);
 396  
     }
 397  1
   }
 398  
 
 399  
   public void paginate() throws Exception {
 400  1
     System.err.println("Paginating chapter");
 401  1
     assertCanWrite();
 402  
 
 403  1
     BibliomaniaDatabase db = getBibliomaniaDatabase();
 404  
 
 405  1
     File allPaged = allPagedFile();
 406  1
     allPaged.getParentFile().mkdirs();
 407  
 
 408  1
     final File temp = File.createTempFile("Chapter.encache", null, null);
 409  
 
 410  
     try {
 411  1
       db.interpolateAsTemplate(originalBodyFile(), temp, this);
 412  
 
 413  1
       final long textID = ftiTextID();
 414  
 
 415  1
       Text unpaged = new Text() {
 416  
         public InputStream body() throws IOException {
 417  2
           FileInputStream it = new FileInputStream(temp);
 418  2
           PoemThread.toTidy().add(it);
 419  2
           return it;
 420  
         }
 421  
 
 422  
         public InputStream bodyForFragment() throws IOException {
 423  0
           return body();
 424  
         }
 425  
 
 426  
         public long ftiTextID() {
 427  1
           return textID;
 428  
         }
 429  
       };
 430  
 
 431  1
       Writer allPagedW = null;
 432  
       try {
 433  1
         allPagedW = new BufferedWriter(new FileWriter(allPaged));
 434  1
         db.pagination().paginate(
 435  
           unpaged,
 436  
           db.getPaginationTexHeader(),
 437  
           allPagedW,
 438  
           db.getFootnoteTemplate(),
 439  
           db.getWebMacro(),
 440  
           db.getContentEncoding());
 441  
       } finally {
 442  0
         try {
 443  1
           allPagedW.close();
 444  0
         } catch (Exception e) {
 445  0
           throw new RuntimeException(e);
 446  1
         }
 447  
       }
 448  
     } finally {
 449  1
       temp.delete();
 450  1
     }
 451  1
   }
 452  
 
 453  
   public void encache() throws Exception {
 454  1
     assertCanWrite();
 455  1
     splitOutPages();
 456  1
     setLastencached(new Timestamp(System.currentTimeMillis()));
 457  1
   }
 458  
 
 459  
   public String getMetatag_description() {
 460  3
     return getBook().getMetatag_description();
 461  
   }
 462  
 
 463  
   public String getMetatag_keywords() {
 464  3
     return getBook().getMetatag_keywords();
 465  
   }
 466  
   public String getLongTitle() {
 467  25
     String titleCandidate = getLongtitle();
 468  25
     return titleCandidate == null ? getTitle() : titleCandidate;
 469  
   }
 470  
 
 471  
   public Integer pageOfAnchor(String anchor) {
 472  
     try {
 473  0
       BibliomaniaDatabase db = getBibliomaniaDatabase();
 474  
 
 475  0
       String blockmarker =
 476  
         db.fti().blockmarkerBeforeFirstOccurrence(ftiTextID(), '#' + anchor);
 477  
 
 478  0
       return blockmarker == null ? null : db.pageFromAnchor(blockmarker);
 479  0
     } catch (DatabaseException e) {
 480  0
       throw new UnexpectedExceptionException(e);
 481  
     }
 482  
   }
 483  
 
 484  
   public String adminHandle(Melati melati, MarkupLanguage markupLanguage)
 485  
     throws Exception {
 486  0
     return null;
 487  
   }
 488  
 
 489  
   public String adminSpecialFacilities(
 490  
     Melati melatiContext,
 491  
     MarkupLanguage markupLanguage)
 492  
     throws Exception {
 493  0
     return getBibliomaniaDatabase().getWMTemplet("Chapter-specials");
 494  
   }
 495  
 
 496  
   public SectionGroup getReadArea() {
 497  5
     return getBook().getReadArea();
 498  
   }
 499  
 
 500  
   public Enumeration<ProductAssociation> getProductAssociations() {
 501  0
     return new EmptyEnumeration<ProductAssociation>();
 502  
   }
 503  
   
 504  
   /* 
 505  
    * @see org.melati.util.Treeable#getChildren()
 506  
    */
 507  7
   public Treeable[] children = null;
 508  
    
 509  
   public Treeable[] getChildren() {
 510  0
     return children;
 511  
   }
 512  
   /* 
 513  
    * @see org.melati.util.Treeable#getName()
 514  
    */
 515  
   public String getName() {
 516  0
     return getDisplayName();
 517  
   }
 518  
 
 519  
 }