Coverage Report - org.paneris.bibliomania.BibliomaniaDatabase
 
Classes in this File Line Coverage Branch Coverage Complexity
BibliomaniaDatabase
62%
146/234
44%
31/70
1.8
BibliomaniaDatabase$1
75%
101/133
57%
8/14
1.8
BibliomaniaDatabase$2
10%
1/10
0%
0/2
1.8
BibliomaniaDatabase$BackgroundStockingsChecker
0%
0/12
N/A
1.8
BibliomaniaDatabase$BackgroundStockingsChecker$1
0%
0/27
0%
0/12
1.8
 
 1  
 package org.paneris.bibliomania;
 2  
 
 3  
 
 4  
 import java.io.BufferedOutputStream;
 5  
 import java.io.BufferedReader;
 6  
 import java.io.File;
 7  
 import java.io.FileOutputStream;
 8  
 import java.io.FileReader;
 9  
 import java.io.IOException;
 10  
 import java.io.OutputStream;
 11  
 import java.io.Reader;
 12  
 import java.io.StringReader;
 13  
 import java.net.InetAddress;
 14  
 import java.sql.PreparedStatement;
 15  
 import java.sql.ResultSet;
 16  
 import java.sql.Timestamp;
 17  
 import java.util.Enumeration;
 18  
 import java.util.Hashtable;
 19  
 import java.util.List;
 20  
 import java.util.Locale;
 21  
 import java.util.Properties;
 22  
 import java.util.Vector;
 23  
 
 24  
 import org.melati.Melati;
 25  
 import org.melati.MelatiConfig;
 26  
 import org.melati.poem.AccessToken;
 27  
 import org.melati.poem.Capability;
 28  
 import org.melati.poem.Group;
 29  
 import org.melati.poem.NoSuchRowPoemException;
 30  
 import org.melati.poem.PoemTask;
 31  
 import org.melati.poem.PoemThread;
 32  
 import org.melati.poem.PreparedStatementFactory;
 33  
 import org.melati.poem.Setting;
 34  
 import org.melati.poem.TableInfo;
 35  
 import org.melati.template.webmacro.MelatiFastWriter;
 36  
 import org.melati.util.Email;
 37  
 import org.melati.util.FileUtils;
 38  
 import org.melati.util.IoUtils;
 39  
 import org.melati.util.MelatiRuntimeException;
 40  
 import org.melati.util.UnexpectedExceptionException;
 41  
 import org.paneris.bibliomania.fti.FTIException;
 42  
 import org.paneris.bibliomania.fti.IndexOther;
 43  
 import org.paneris.bibliomania.fti.Library;
 44  
 import org.paneris.bibliomania.fti.Text;
 45  
 import org.paneris.bibliomania.generated.BibliomaniaDatabaseBase;
 46  
 import org.paneris.bibliomania.metasearch.BookshopBackend;
 47  
 import org.paneris.bibliomania.metasearch.BookshopBackendFactory;
 48  
 import org.paneris.bibliomania.pagination.Pagination;
 49  
 import org.webmacro.Context;
 50  
 import org.webmacro.InitException;
 51  
 import org.webmacro.WM;
 52  
 import org.webmacro.WebMacro;
 53  
 import org.webmacro.WebMacroException;
 54  
 import org.webmacro.engine.FileTemplate;
 55  
 import org.webmacro.engine.StreamTemplate;
 56  
 
 57  
 /**
 58  
  * Melati POEM generated, programmer modifiable stub.
 59  
  */
 60  263
 public class BibliomaniaDatabase extends BibliomaniaDatabaseBase
 61  
                             implements BibliomaniaDatabaseTables {
 62  
   // programmer's domain-specific code here
 63  2
    private IndexOther fti = null, infoFTI = null;
 64  
    private Properties ftiConfig;
 65  2
    private Pagination pagination = null;
 66  
 
 67  
    public static final int defaultDefaultSearchHitsPerText = 5,
 68  
      defaultSearchHitsPerPage = 20,
 69  
      defaultBookStockingsCheckIntervalDays = 7,
 70  
      defaultBibBookBookshopSearchTimeoutSeconds = 120,
 71  
      defaultBookStockingsCheckConcurrentMax = 2,
 72  
      defaultBookStockingsOutputStartOffset = 25,
 73  
      defaultBookStockingsCacheSizeMax = 10000;
 74  
 
 75  
    public static final String defaultPasswordReminderMessage =
 76  
      "defaultPasswordReminderMessage.wm",
 77  
      defaultPasswordReminderFrom = "help",
 78  
      defaultOrderEmailFrom = "orders@bibliomania.com",
 79  
      defaultConfirmationEmailFrom = "customercare@bibliomania.com",
 80  
      defaultOrderEmailTo = "purchases@bibliomania.com",
 81  
      defaultStratusEmailTo = "info@houseofstratus.com",
 82  
      defaultContentEncoding = "ISO-8859-1",
 83  
      defaultUploadDir = "/usr/local/bibliomania/books/",
 84  
      defaultUploadURL = "/",
 85  
      defaultDomainUrl = "www.bibliomania.com";
 86  
    //  defaultContentEncoding = "UTF8";
 87  
 
 88  
    private Setting workspaceDir,
 89  
      contentRootDir,
 90  
      staticRootURL,
 91  
      contentStaticRootURL,
 92  
      cacheRootURL,
 93  
      homepageURL,
 94  
      orderEmailFrom,
 95  
      confirmationEmailFrom,
 96  
      orderEmailTo,
 97  
      stratusEmailTo,
 98  
      defaultSearchHitsPerText,
 99  
      searchHitsPerPage,
 100  
      paginationTexHeader,
 101  
      bookStockingsCheckIntervalDays,
 102  
      bookStockingsCheckConcurrentMax,
 103  
      bookStockingsInBackground,
 104  
      bibBookBookshopSearchTimeoutSeconds,
 105  
      smtpServer,
 106  
      passwordReminderMessage,
 107  
      passwordReminderFrom,
 108  
      infoFTIDir,
 109  
      bannerURLPath,
 110  
      bookStockingsOutputStartOffset,
 111  
      bookStockingsCacheDir,
 112  
      bookStockingsCacheSizeMax,
 113  
      contentEncoding,
 114  
      uploadDir,
 115  
      uploadURL;
 116  
 
 117  
    private Currency UKCurrency;
 118  
    //private Currency USCurrency;
 119  
 
 120  
    private Group registeredUserGroup;
 121  
 
 122  
    private Capability registeredUserCapability,
 123  
      contentModificationCapability,
 124  
      contentAdditionCapability;
 125  
 
 126  
    private User templateRegisterUser;
 127  
 
 128  2
    private Bookshop[] bookshops = null;
 129  
 
 130  
    private SectionGroup readSectionGroup,
 131  
      studySectionGroup,
 132  
      researchSectionGroup,
 133  
      shopSectionGroup,
 134  
      searchSectionGroup;
 135  
 
 136  
    private boolean bookStockingsInBackgroundAppropriate, openBerkeleyDBs;
 137  
 
 138  
    private Section drama;
 139  
    private Author shakespeare;
 140  
    private Book macbeth;
 141  
    
 142  
    public BibliomaniaDatabase() {
 143  0
      this(false);
 144  0
    }
 145  
 
 146  
    public BibliomaniaDatabase(boolean bookStockingsInBackgroundAppropriate) {
 147  1
      this(bookStockingsInBackgroundAppropriate, true);  // Turn on BerkeleyDB
 148  1
    }
 149  
 
 150  
    public BibliomaniaDatabase(
 151  
        boolean bookStockingsInBackgroundAppropriate,
 152  
        boolean openAuxDBs) {
 153  1
      this(bookStockingsInBackgroundAppropriate, openAuxDBs, null);
 154  1
    }
 155  
 
 156  
    public BibliomaniaDatabase(
 157  
        boolean bookStockingsInBackgroundAppropriate,
 158  
        boolean openAuxDBs,
 159  2
        Properties ftiConfig) {
 160  2
      this.bookStockingsInBackgroundAppropriate =
 161  
        bookStockingsInBackgroundAppropriate;
 162  2
      this.openBerkeleyDBs = openAuxDBs;
 163  2
      this.ftiConfig = ftiConfig;
 164  2
    }
 165  
 
 166  
    public boolean debug() {
 167  0
      return false;
 168  
    }
 169  
 
 170  
    public Capability getCanAdminister() {
 171  0
      return administerCapability();
 172  
    }
 173  
 
 174  
    public void connect(
 175  
      String name,
 176  
      String dbmsclass,
 177  
      String url,
 178  
      String username,
 179  
      String password,
 180  
      int maxConnections) {
 181  2
      super.connect(name, dbmsclass, url, username, password, maxConnections);
 182  
 
 183  2
      inSession(AccessToken.root, new PoemTask() {
 184  
        public void run() {
 185  2
          String root = "/usr/local/bibliomania";
 186  2
          ((UserTable)getUserTable()).setBoardManager(
 187  
              ((UserTable)getUserTable()).ensure(
 188  
                  "_manager_","FIXME",
 189  
                  "board_manager@paneris.co.uk",
 190  
                  "Bibliomania Board Manager"));
 191  
 
 192  
 
 193  2
          readSectionGroup =
 194  
            getSectionGroupTable().ensure(
 195  
              "#ff9900",
 196  
              "read",
 197  
              "read.gif",
 198  
              "readg.gif",
 199  
              "1",
 200  
              "read",
 201  
              "",
 202  
              false,
 203  
              null);
 204  
 
 205  2
          studySectionGroup =
 206  
            getSectionGroupTable().ensure(
 207  
              "#9999ff",
 208  
              "study",
 209  
              "study.gif",
 210  
              "studyg.gif",
 211  
              "4",
 212  
              "study",
 213  
              "",
 214  
              false,
 215  
              null);
 216  
 
 217  2
          researchSectionGroup =
 218  
            getSectionGroupTable().ensure(
 219  
              "#cc9966",
 220  
              "research",
 221  
              "researchb.gif",
 222  
              "researcha.gif",
 223  
              "6",
 224  
              "research",
 225  
              "",
 226  
              false,
 227  
              null);
 228  
          /*
 229  
          shopSectionGroup = 
 230  
            getSectionGroupTable().ensure(
 231  
              "#00cc99", 
 232  
              "shop", 
 233  
              "shop.gif", 
 234  
              "shopg.gif", 
 235  
              "3",
 236  
              "shop", 
 237  
              "<a href=/b/org.paneris.melati.shopping.Trolley/bibliomania/View target=main>Your Basket</a>", 
 238  
              false, 
 239  
              null);
 240  
          */
 241  2
          searchSectionGroup =
 242  
            getSectionGroupTable().ensure(
 243  
              "#ff0000",
 244  
              "search",
 245  
              "search.gif",
 246  
              "searchg.gif",
 247  
              "2",
 248  
              "search",
 249  
              "",
 250  
              true,
 251  
              "/b/Search");
 252  
 
 253  
          
 254  2
          drama = getSectionTable().ensure("Drama", readSectionGroup);
 255  2
          shakespeare = getAuthorTable().ensure("William Shakespeare", drama);
 256  2
          macbeth = getBookTable().ensure("Macbeth", shakespeare, drama);
 257  
          
 258  2
          registeredUserGroup = getGroupTable().ensure("Registered users");
 259  2
          registeredUserCapability =
 260  
            getCapabilityTable().ensure("Access study material");
 261  2
          contentModificationCapability =
 262  
            getCapabilityTable().ensure("Edit content database");
 263  2
          contentAdditionCapability =
 264  
            getCapabilityTable().ensure("Add to content database");
 265  
          
 266  2
          getGroupCapabilityTable().ensure(
 267  
              getGroupTable().administratorsGroup(),
 268  
            contentModificationCapability);
 269  
              
 270  2
          getGroupCapabilityTable().ensure(
 271  
              getGroupTable().administratorsGroup(),
 272  
              contentAdditionCapability);
 273  
 
 274  
          
 275  2
          templateRegisterUser =
 276  
            (User)getUserTable().getLoginColumn().firstWhereEq(
 277  
              "_registerTemplate_");
 278  
 
 279  2
          if (templateRegisterUser == null) {
 280  0
            templateRegisterUser = (User)getUserTable().newPersistent();
 281  0
            templateRegisterUser.setLogin("_registerTemplate_");
 282  0
            templateRegisterUser.setPassword("0.804461358580738");
 283  0
            templateRegisterUser.setEmail("none@bogus");
 284  0
            templateRegisterUser.setFulltimeeducation(false);
 285  0
            templateRegisterUser.setWantspam(false);
 286  0
            templateRegisterUser.setWantemailalerts(false);
 287  0
            templateRegisterUser.setDodgeyemail(false);
 288  0
            templateRegisterUser.setName(
 289  
              "<Template for newly registering users>");
 290  0
            getUserTable().create(templateRegisterUser);
 291  
          }
 292  
 
 293  2
          workspaceDir =
 294  
            getSettingTable().ensure(
 295  
              "WorkspaceDir",
 296  
              root + "/workspace",
 297  
              "Workspace directory",
 298  
              "Where the system should store its working files");
 299  
 
 300  2
          infoFTIDir =
 301  
            getSettingTable().ensure(
 302  
              "InfoFTIDir",
 303  
              "/infoFTI",
 304  
              "Info-FTI directory",
 305  
              "Where the system should store the info-page index, relative "
 306  
                + "to WorkspaceDir");
 307  
 
 308  2
          contentRootDir =
 309  
            getSettingTable().ensure(
 310  
              "ContentRootDir",
 311  
              root + "/books",
 312  
              "Content root directory",
 313  
              "Where (in the local filesystem) the system should look for "
 314  
                + "the book content files");
 315  
 
 316  2
          staticRootURL =
 317  
            getSettingTable().ensure(
 318  
              "StaticRootURL",
 319  
              "/bibliomania-static",
 320  
              "Static root URL",
 321  
              "Where the browser can find the Bibliomania chrome, "
 322  
                + "relative to the server root URL");
 323  
 
 324  2
          contentStaticRootURL =
 325  
            getSettingTable().ensure(
 326  
              "ContentStaticRootURL",
 327  
              "/bibliomania-content-static",
 328  
              "Content static root URL",
 329  
              "Where the browser can find the Bibliomania static content, "
 330  
                + "relative to the server root URL");
 331  
 
 332  2
          bannerURLPath =
 333  
            getSettingTable().ensure(
 334  
              "BannerURLPath",
 335  
              "/bibliomania-content-static",
 336  
              "Banner URL Path",
 337  
              "Where the browser can find the Bibliomania static content, "
 338  
                + "relative to the server root URL");
 339  
 
 340  2
          cacheRootURL =
 341  
            getSettingTable().ensure(
 342  
              "CacheRootURL",
 343  
              "",
 344  
              "Cache root URL",
 345  
              "Where the web server should look for the banner ad, "
 346  
                + "relative to the server root URL");
 347  
 
 348  2
          homepageURL =
 349  
            getSettingTable().ensure(
 350  
              "HomepageURL",
 351  
              "http://www.bibliomania.com",
 352  
              "Home page URL",
 353  
              "A full URL for the front page of bibliomania");
 354  
 
 355  2
          defaultSearchHitsPerText =
 356  
            getSettingTable().ensure(
 357  
              "DefaultSearchHitsPerText",
 358  
              defaultDefaultSearchHitsPerText,
 359  
              "Default search hits per text",
 360  
              "The default number of search hits to return from each text");
 361  
 
 362  2
          searchHitsPerPage =
 363  
            getSettingTable().ensure(
 364  
              "SearchHitsPerPage",
 365  
              defaultSearchHitsPerPage,
 366  
              "Search hits per page",
 367  
              "The number of search hits to return on each results page");
 368  
 
 369  2
          bookStockingsCheckIntervalDays =
 370  
            getSettingTable().ensure(
 371  
              "StockingsCheckIntervalDays",
 372  
              defaultBookStockingsCheckIntervalDays,
 373  
              "Bookshop search refresh days",
 374  
              "The number of days for which a cached bookshop search "
 375  
                + "remains valid");
 376  
 
 377  2
          bibBookBookshopSearchTimeoutSeconds =
 378  
            getSettingTable().ensure(
 379  
              "BibBookSearchTimeoutSecs",
 380  
              defaultBibBookBookshopSearchTimeoutSeconds,
 381  
              "Timeout for shop search for Bib book",
 382  
              "The number of seconds which a bookshop search for a "
 383  
                + "Bibliomania book is allowed to continue before being "
 384  
                + "cut short");
 385  
 
 386  2
          bookStockingsInBackground =
 387  
            getSettingTable().ensure(
 388  
              "StockingsCheckInBackground",
 389  
              false,
 390  
              "Background bookshop search",
 391  
              "Whether to run continual bookshop searches in the background");
 392  
 
 393  2
          bookStockingsOutputStartOffset =
 394  
            getSettingTable().ensure(
 395  
              "StockingsOutputStartOffset",
 396  
              defaultBookStockingsOutputStartOffset,
 397  
              "Start Offset for Shop DHTML",
 398  
              "How far down the page to start DHTML output");
 399  
 
 400  2
          bookStockingsCacheDir =
 401  
            getSettingTable().ensure(
 402  
              "StockingsCacheDir",
 403  
              root + "/stockings",
 404  
              "Book stockings cache directory",
 405  
              "Where the system should store cached results of bookshop "
 406  
                + "searches");
 407  
 
 408  2
          bookStockingsCacheSizeMax =
 409  
            getSettingTable().ensure(
 410  
              "StockingsCacheMax",
 411  
              defaultBookStockingsCacheSizeMax,
 412  
              "Max cached book stockings",
 413  
              "How many bookshop search results the system should cache");
 414  
 
 415  2
          bookStockingsCheckConcurrentMax =
 416  
            getSettingTable().ensure(
 417  
              "StockingsCheckConcurrentMax",
 418  
              defaultBookStockingsCheckConcurrentMax,
 419  
              "Max concurrent bookshop searches",
 420  
              "The maximum number of bookshop searches to allow "
 421  
                + "at once (including the background search)");
 422  
 
 423  2
          UKCurrency =
 424  
            getCurrencyTable().ensure("UK Pound Sterling", 1d, Locale.UK);
 425  
          //USCurrency = getCurrencyTable().ensure("US Dollar", 1.43, Locale.US);
 426  
 
 427  2
          if (openBerkeleyDBs) {
 428  
            try {
 429  1
              fti = new IndexOther(new File(getWorkspaceDir()), ftiConfig);
 430  1
              infoFTI = new IndexOther(new File(getInfoFTIDir()));
 431  0
            } catch (Exception e) {
 432  0
              throw new FTIException(e);
 433  1
            }
 434  
          }
 435  
          try{ 
 436  2
            pagination = new Pagination(new File(getWorkspaceDir()));
 437  0
          } catch (Exception e) { 
 438  0
            throw new RuntimeException(e);
 439  2
          }
 440  
           
 441  2
          paginationTexHeader =
 442  
            (Setting)getSettingTable().getNameColumn().firstWhereEq(
 443  
              "PaginationTexHeader");
 444  2
          if (paginationTexHeader == null) {
 445  0
            paginationTexHeader =
 446  
              getSettingTable().ensure(
 447  
                "PaginationTexHeader",
 448  
                pagination.defaultTexHeader(),
 449  
                "TeX header for pagination",
 450  
                "The header to be prepended to the TeX version of a "
 451  
                  + "chapter when TeX is run to determine page breaks");
 452  0
            paginationTexHeader.setWidth(60);
 453  0
            paginationTexHeader.setHeight(5);
 454  
          }
 455  
          
 456  2
          Vector<Bookshop> bookshopsList = new Vector<Bookshop>();
 457  
 
 458  2
          Bookshop bol = getBookshopTable().ensure("BOLUK", "BOL UK", "uk.gif");
 459  2
          if (!Boolean.TRUE.equals(bol.getDisabled())) {
 460  0
            bol.backend = bookshopBackendNamed("bol");
 461  0
            bookshopsList.addElement(bol);
 462  
          }
 463  
 
 464  2
          Bookshop bob =
 465  
            getBookshopTable().ensure(
 466  
              "BOB",
 467  
              "Blackwells Online Bookshop",
 468  
              "uk.gif");
 469  2
          if (!Boolean.TRUE.equals(bob.getDisabled())) {
 470  0
            bob.backend = bookshopBackendNamed("bob");
 471  0
            bookshopsList.addElement(bob);
 472  
          }
 473  
 
 474  2
          Bookshop amazon =
 475  
            getBookshopTable().ensure("AMAZON", "amazon.com", "us.gif");
 476  2
          if (!Boolean.TRUE.equals(amazon.getDisabled())) {
 477  0
            amazon.backend = bookshopBackendNamed("amazon");
 478  0
            bookshopsList.addElement(amazon);
 479  
          }
 480  
 
 481  2
          bookshops = new Bookshop[bookshopsList.size()];
 482  2
          bookshopsList.copyInto(bookshops);
 483  
 
 484  
          String defaultSmtpServer;
 485  
          try {
 486  2
            defaultSmtpServer = InetAddress.getLocalHost().toString();
 487  0
          } catch (Exception e) {
 488  0
            defaultSmtpServer = "www.bibliomania.com";
 489  2
          }
 490  
 
 491  2
            smtpServer =
 492  
              getSettingTable().ensure(Email.SMTPSERVER,
 493  
    defaultSmtpServer,
 494  
      "SMTP server",
 495  
      "The SMTP server through which auto-generated mail " + "should be sent");
 496  
 
 497  2
          passwordReminderMessage =
 498  
            (Setting)getSettingTable().getNameColumn().firstWhereEq(
 499  
              "PasswordReminderMessage");
 500  2
          if (passwordReminderMessage == null) {
 501  
            String it;
 502  
            try {
 503  0
              it =
 504  
                new String(
 505  
                  IoUtils.slurp(
 506  
                    this.getClass().getResource(defaultPasswordReminderMessage),
 507  
                    4096));
 508  0
            } catch (Exception e) {
 509  0
              throw new UnexpectedExceptionException(
 510  
                "Didn't find resource " + defaultPasswordReminderMessage,
 511  
                e);
 512  0
            }
 513  
 
 514  0
            passwordReminderMessage =
 515  
              getSettingTable().ensure(
 516  
                "PasswordReminderMessage",
 517  
                it,
 518  
                "Password reminder message",
 519  
                "The text of the message sent to users to remind them of "
 520  
                  + "their password (actually a WebMacro template)");
 521  0
            passwordReminderMessage.setWidth(80);
 522  0
            passwordReminderMessage.setHeight(30);
 523  
          }
 524  
 
 525  2
          passwordReminderFrom =
 526  
            getSettingTable().ensure(
 527  
              "PasswordReminderFrom",
 528  
              defaultPasswordReminderFrom,
 529  
              "Password reminder `From:'",
 530  
              "The address from whom the emailed password reminders "
 531  
                + "should originate");
 532  
 
 533  2
          confirmationEmailFrom =
 534  
            getSettingTable().ensure(
 535  
              "ConfirmationEmailFrom",
 536  
              defaultConfirmationEmailFrom,
 537  
              "Confirmation Email `From:'",
 538  
              "The address from whom the confirmation email that is sent on "
 539  
                + "registration should originate");
 540  
 
 541  2
          orderEmailFrom =
 542  
            getSettingTable().ensure(
 543  
              "OrderEmailFrom",
 544  
              defaultOrderEmailFrom,
 545  
              "Order Email `From:'",
 546  
              "The address from whom the emailed order acknowledgements "
 547  
                + "should originate");
 548  
 
 549  2
          orderEmailTo =
 550  
            getSettingTable().ensure(
 551  
              "OrderEmailTo",
 552  
              defaultOrderEmailTo,
 553  
              "Order Email `To:'",
 554  
              "The address to send email acknowledgements to (at bibliomania)");
 555  
 
 556  2
          stratusEmailTo =
 557  
            getSettingTable().ensure(
 558  
              "StratusEmailTo",
 559  
              defaultStratusEmailTo,
 560  
              "Stratus Email `To:'",
 561  
              "The address to send email orders to (at Stratus)");
 562  
 
 563  2
          contentEncoding =
 564  
            getSettingTable().ensure(
 565  
              "Content encoding",
 566  
              defaultContentEncoding,
 567  
              "Encoding (character set) to use for content",
 568  
              "The encoding, or character set, to use for the cached "
 569  
                + "content; if you don't know why you need to set this, "
 570  
                + "leave it as UTF8.");
 571  
 
 572  2
          uploadDir =
 573  
            getSettingTable().ensure(
 574  
              "UploadDir",
 575  
              defaultUploadDir,
 576  
              "Upload Directory for Product Images",
 577  
              "Upload Directory for product images.  This is prepended to the "
 578  
                + "path used for the book to which this product relates.");
 579  
 
 580  2
          uploadURL =
 581  
            getSettingTable().ensure(
 582  
              "UploadURL",
 583  
              defaultUploadURL,
 584  
              "URL used when finding uploaded images",
 585  
              "The URL used when finding uploaded images.  This is prepended to the "
 586  
                + "URL used for the book to which this product relates.");
 587  
 
 588  
          /* this is all a bit verbose, but it is nice to ensure these are present
 589  
           */
 590  
 
 591  
          // Advert table - normal admin permissions
 592  2
          setDefaultAccessPermissions(
 593  
            getAdvertTable().getTableInfo(),
 594  
            contentAdditionCapability,
 595  
            administerCapability(),
 596  
            contentModificationCapability,
 597  
            null);
 598  
 
 599  
          // Attachment table - only sys admins can add / change
 600  
          // individual users can also change things
 601  2
          setDefaultAccessPermissions(
 602  
            getAttachmentTable().getTableInfo(),
 603  
            null,
 604  
            administerCapability(),
 605  
            administerCapability(),
 606  
            null);
 607  
 
 608  
          // Attachment type table - only sys admins can add / change
 609  2
          setDefaultAccessPermissions(
 610  
            getAttachmentTypeTable().getTableInfo(),
 611  
            administerCapability(),
 612  
            administerCapability(),
 613  
            administerCapability(),
 614  
            null);
 615  
 
 616  
          // Author table - normal admin permissions
 617  2
          setDefaultAccessPermissions(
 618  
            getAuthorTable().getTableInfo(),
 619  
            contentAdditionCapability,
 620  
            administerCapability(),
 621  
            contentModificationCapability,
 622  
            null);
 623  
 
 624  
          // Author website table - normal admin permissions
 625  2
          setDefaultAccessPermissions(
 626  
            getAuthorWebSiteTable().getTableInfo(),
 627  
            contentAdditionCapability,
 628  
            administerCapability(),
 629  
            contentModificationCapability,
 630  
            null);
 631  
 
 632  
          // messageboard table - normal admin permissions
 633  2
          setDefaultAccessPermissions(
 634  
            getBoardTable().getTableInfo(),
 635  
            contentAdditionCapability,
 636  
            administerCapability(),
 637  
            contentModificationCapability,
 638  
            null);
 639  
 
 640  
          // messageboard type table - only administrators
 641  2
          setDefaultAccessPermissions(
 642  
            getBoardTypeTable().getTableInfo(),
 643  
            administerCapability(),
 644  
            administerCapability(),
 645  
            contentModificationCapability,
 646  
            null);
 647  
 
 648  
          // book table - normal admin permissions
 649  2
          setDefaultAccessPermissions(
 650  
            getBookTable().getTableInfo(),
 651  
            contentAdditionCapability,
 652  
            administerCapability(),
 653  
            contentModificationCapability,
 654  
            null);
 655  
 
 656  
          // book format table - only administrators
 657  2
          setDefaultAccessPermissions(
 658  
            getBookFormatTable().getTableInfo(),
 659  
            administerCapability(),
 660  
            administerCapability(),
 661  
            administerCapability(),
 662  
            null);
 663  
 
 664  
          // bookshop table - only administrators - but others can edit
 665  2
          setDefaultAccessPermissions(
 666  
            getBookshopTable().getTableInfo(),
 667  
            administerCapability(),
 668  
            administerCapability(),
 669  
            contentModificationCapability,
 670  
            null);
 671  
 
 672  
          // book stocking table - only administrators 
 673  2
          setDefaultAccessPermissions(
 674  
            getBookStockingTable().getTableInfo(),
 675  
            administerCapability(),
 676  
            administerCapability(),
 677  
            administerCapability(),
 678  
            null);
 679  
 
 680  
          // chapter table - normal admin permissions
 681  2
          setDefaultAccessPermissions(
 682  
            getChapterTable().getTableInfo(),
 683  
            contentAdditionCapability,
 684  
            administerCapability(),
 685  
            contentModificationCapability,
 686  
            null);
 687  
 
 688  
          // country table - normal admin permissions
 689  2
          setDefaultAccessPermissions(
 690  
            getCountryTable().getTableInfo(),
 691  
            contentAdditionCapability,
 692  
            administerCapability(),
 693  
            contentModificationCapability,
 694  
            null);
 695  
 
 696  
          // currency table - normal admin permissions
 697  2
          setDefaultAccessPermissions(
 698  
            getCurrencyTable().getTableInfo(),
 699  
            contentAdditionCapability,
 700  
            administerCapability(),
 701  
            contentModificationCapability,
 702  
            null);
 703  
 
 704  
          // delivery charge table - normal admin permissions
 705  2
          setDefaultAccessPermissions(
 706  
            getDeliveryChargeTable().getTableInfo(),
 707  
            contentAdditionCapability,
 708  
            administerCapability(),
 709  
            contentModificationCapability,
 710  
            null);
 711  
 
 712  
          // delivery charge band table - normal admin permissions
 713  2
          setDefaultAccessPermissions(
 714  
            getDeliveryChargeBandTable().getTableInfo(),
 715  
            contentAdditionCapability,
 716  
            administerCapability(),
 717  
            contentModificationCapability,
 718  
            null);
 719  
 
 720  
          // download table - normal admin permissions
 721  2
          setDefaultAccessPermissions(
 722  
            getDownloadTable().getTableInfo(),
 723  
            contentAdditionCapability,
 724  
            administerCapability(),
 725  
            contentModificationCapability,
 726  
            null);
 727  
 
 728  
          // download event table - only administrator and the relevant user
 729  2
          setDefaultAccessPermissions(
 730  
            getDownloadEventTable().getTableInfo(),
 731  
            null,
 732  
            administerCapability(),
 733  
            administerCapability(),
 734  
            administerCapability());
 735  
 
 736  
          // layout table - normal admin permissions
 737  2
          setDefaultAccessPermissions(
 738  
            getLayoutTable().getTableInfo(),
 739  
            contentAdditionCapability,
 740  
            administerCapability(),
 741  
            contentModificationCapability,
 742  
            null);
 743  
 
 744  
          // membership status table - normal admin permissions
 745  2
          setDefaultAccessPermissions(
 746  
            getMembershipStatusTable().getTableInfo(),
 747  
            contentAdditionCapability,
 748  
            administerCapability(),
 749  
            contentModificationCapability,
 750  
            null);
 751  
 
 752  
          // order table - owning user, and admins can modify
 753  2
          setDefaultAccessPermissions(
 754  
            getShopOrderTable().getTableInfo(),
 755  
            null,
 756  
            administerCapability(),
 757  
            null,
 758  
            null);
 759  
 
 760  
          // order item table - owning user, and admins can modify
 761  2
          setDefaultAccessPermissions(
 762  
            getShopOrderItemTable().getTableInfo(),
 763  
            null,
 764  
            administerCapability(),
 765  
            null,
 766  
            null);
 767  
 
 768  
          // order status table - anly admins can chnage 
 769  2
          setDefaultAccessPermissions(
 770  
            getOrderStatusTable().getTableInfo(),
 771  
            administerCapability(),
 772  
            administerCapability(),
 773  
            administerCapability(),
 774  
            null);
 775  
 
 776  
          // product table - normal permissions
 777  2
          setDefaultAccessPermissions(
 778  
            getProductTable().getTableInfo(),
 779  
            contentAdditionCapability,
 780  
            administerCapability(),
 781  
            contentModificationCapability,
 782  
            null);
 783  
 
 784  
          // product association table - normal permissions
 785  2
          setDefaultAccessPermissions(
 786  
            getProductAssociationTable().getTableInfo(),
 787  
            contentAdditionCapability,
 788  
            administerCapability(),
 789  
            contentModificationCapability,
 790  
            null);
 791  
 
 792  
          // publisher table - normal permissions
 793  2
          setDefaultAccessPermissions(
 794  
            getPublisherTable().getTableInfo(),
 795  
            contentAdditionCapability,
 796  
            administerCapability(),
 797  
            contentModificationCapability,
 798  
            null);
 799  
 
 800  
          // publisher table - normal permissions
 801  2
          setDefaultAccessPermissions(
 802  
            getPublisherTable().getTableInfo(),
 803  
            contentAdditionCapability,
 804  
            administerCapability(),
 805  
            contentModificationCapability,
 806  
            null);
 807  
 
 808  
          // section table - normal permissions
 809  2
          setDefaultAccessPermissions(
 810  
            getSectionTable().getTableInfo(),
 811  
            contentAdditionCapability,
 812  
            administerCapability(),
 813  
            contentModificationCapability,
 814  
            null);
 815  
 
 816  
          // section group table - admin only
 817  2
          setDefaultAccessPermissions(
 818  
            getSectionTable().getTableInfo(),
 819  
            administerCapability(),
 820  
            administerCapability(),
 821  
            administerCapability(),
 822  
            null);
 823  
 
 824  
          // Sex table - admin only
 825  2
          setDefaultAccessPermissions(
 826  
            getSexTable().getTableInfo(),
 827  
            administerCapability(),
 828  
            administerCapability(),
 829  
            administerCapability(),
 830  
            null);
 831  
 
 832  
          // Stockingssearch table - admin only
 833  2
          setDefaultAccessPermissions(
 834  
            getStockingsSearchTable().getTableInfo(),
 835  
            null,
 836  
            administerCapability(),
 837  
            administerCapability(),
 838  
            null);
 839  
 
 840  
          // Supplier table - normal permission
 841  2
          setDefaultAccessPermissions(
 842  
            getSupplierTable().getTableInfo(),
 843  
            contentAdditionCapability,
 844  
            administerCapability(),
 845  
            contentModificationCapability,
 846  
            null);
 847  
 
 848  
          // Supplier products table - normal permission
 849  2
          setDefaultAccessPermissions(
 850  
            getSupplierProductTable().getTableInfo(),
 851  
            contentAdditionCapability,
 852  
            administerCapability(),
 853  
            contentModificationCapability,
 854  
            null);
 855  
 
 856  
          // User table - owner and admin only
 857  2
          setDefaultAccessPermissions(
 858  
            getUserTable().getTableInfo(),
 859  
            administerCapability(),
 860  
            administerCapability(),
 861  
            administerCapability(),
 862  
            administerCapability());
 863  2
        }
 864  
      });
 865  
 
 866  2
      if (bookStockingsInBackgroundAppropriate)
 867  0
        new BackgroundStockingsChecker().start();
 868  
 
 869  
      /*
 870  
       * Here is a good place to put one off hacks.
 871  
       */
 872  
       
 873  2
    }
 874  
 
 875  
    private void setDefaultAccessPermissions(
 876  
      TableInfo info,
 877  
      Capability add,
 878  
      Capability delete,
 879  
      Capability write,
 880  
      Capability read) {
 881  68
      if (info.getCancreate() == null)
 882  10
        info.setCancreate(add);
 883  68
      if (info.getDefaultcandelete() == null)
 884  0
        info.setDefaultcandelete(delete);
 885  68
      if (info.getDefaultcanwrite() == null)
 886  4
        info.setDefaultcanwrite(write);
 887  68
      if (info.getDefaultcanread() == null)
 888  64
        info.setDefaultcanread(read);
 889  68
    }
 890  
 
 891  
    public IndexOther fti() {
 892  2
      return fti;
 893  
    }
 894  
 
 895  
    public IndexOther infoFTI() {
 896  1
      return infoFTI;
 897  
    }
 898  
 
 899  2
    Library infoLibrary = new Library() {
 900  
      public Text text(long textID) {
 901  0
        int a =
 902  
          (int) ((textID & ((1l << Chapter.ftiTextID_section_shift) - 1))
 903  
            >> Chapter.ftiTextID_author_shift);
 904  
 
 905  0
        long aMask = (1l << Chapter.ftiTextID_author_shift) - 1;
 906  
 
 907  0
        if ((textID & aMask) == aMask) {
 908  
          // it's an author
 909  
          // but be defensive about finding it
 910  
          try {
 911  0
            return getAuthorTable().getAuthorObject(new Integer(a));
 912  0
          } catch (NoSuchRowPoemException e) {
 913  
            // log it
 914  0
            e.printStackTrace(System.err);
 915  0
            return null;
 916  
          }
 917  
        } else {
 918  
          // it's a book
 919  0
          int b = (int) ((textID & aMask) >> Chapter.ftiTextID_book_shift);
 920  0
          return (Book)getBookTable().firstSelection(
 921  
            "author = " + a + " AND " + "authorsequence = " + b);
 922  
        }
 923  
      }
 924  
    };
 925  
 
 926  
    public Library infoLibrary() {
 927  0
      return infoLibrary;
 928  
    }
 929  
 
 930  
    public boolean openBerkelyDBs() { 
 931  0
      return openBerkeleyDBs;
 932  
    }
 933  
    
 934  
    public Pagination pagination() {
 935  11
      return pagination;
 936  
    }
 937  
 
 938  
    public String getWorkspaceDir() {
 939  13
      return workspaceDir.getStringCooked();
 940  
    }
 941  
 
 942  
    public String getUploadDir() {
 943  0
      return uploadDir.getStringCooked();
 944  
    }
 945  
 
 946  
    public String getUploadURL() {
 947  0
      return uploadURL.getStringCooked();
 948  
    }
 949  
 
 950  
    public String getInfoFTIDir() {
 951  1
      return getWorkspaceDir() + infoFTIDir.getStringCooked();
 952  
    }
 953  
 
 954  
    public String getContentRootDir() {
 955  15
      return contentRootDir.getStringCooked();
 956  
    }
 957  
 
 958  2
    private WebMacro _wm = null;
 959  
 
 960  
    public WebMacro getWebMacro() {
 961  14
      if (_wm == null) {
 962  2
        synchronized (this) {
 963  2
          if (_wm == null) {
 964  
            try {
 965  2
              _wm = new WM();
 966  0
            } catch (InitException e) {
 967  0
              throw new UnexpectedExceptionException(
 968  
                "Initialising WebMacro for the pagination subsystem",
 969  
                e);
 970  2
            }
 971  
          }
 972  2
        }
 973  
      }
 974  
 
 975  14
      return _wm;
 976  
    }
 977  
 
 978  
    public void 
 979  
      setupContext(Melati melati, Context context, Unit it, Hashtable<String, Object> extras) {
 980  
 
 981  6
      SectionGroup sectiongroup = it == null ? null : it.getReadArea();
 982  6
      context.put("sectiongroup", sectiongroup);
 983  6
      if (sectiongroup != null) {
 984  6
        context.put("areaColour", sectiongroup.getThemecolour());
 985  
      } else {
 986  0
        context.put("areaColour", "#FF0000");
 987  
      }
 988  
 
 989  6
      Section section = null;
 990  6
      Author author = null;
 991  6
      Book book = null;
 992  6
      Chapter chapter = null;
 993  
 
 994  6
      if (it != null) {
 995  6
        context.put("meta_description", it.getMetatag_description());
 996  6
        context.put("meta_keywords", it.getMetatag_keywords());
 997  
 
 998  6
        if (it instanceof Chapter) {
 999  3
          chapter = (Chapter)it;
 1000  3
          book = chapter.getBook();
 1001  3
          author = book.getAuthor();
 1002  3
          section = book.getSection();
 1003  3
        } else if (it instanceof Book) {
 1004  3
          book = (Book)it;
 1005  3
          author = book.getAuthor();
 1006  3
          section = book.getSection();
 1007  0
        } else if (it instanceof Author) {
 1008  0
          author = (Author)it;
 1009  0
        } else if (it instanceof Section) {
 1010  0
          section = (Section)it;
 1011  
        }
 1012  
      }
 1013  
 
 1014  6
      context.put("object", it);
 1015  6
      context.put("section", section);
 1016  6
      context.put("author", author);
 1017  6
      context.put("book", book);
 1018  6
      context.put("chapter", chapter);
 1019  6
      context.put("bib", getBib());
 1020  6
      context.put("db", this);
 1021  6
      context.put("melati", melati);
 1022  6
      if (extras != null)
 1023  2
        for (Enumeration<String> keys = extras.keys(); keys.hasMoreElements();) {
 1024  4
          String key = keys.nextElement();
 1025  4
          context.put(key, extras.get(key));
 1026  4
        }
 1027  6
    }
 1028  
 
 1029  
    public final void setupContext(Melati melati, Context context, Unit it) {
 1030  0
      setupContext(melati, context, it, null);
 1031  0
    }
 1032  
 
 1033  
    /**
 1034  
     * Hook to be called when content files are created or changed.  At the
 1035  
     * moment, this makes the file executable (<TT>chmod</TT> <TT>ugo+x</TT>),
 1036  
     * because we use mod-include (server-side includes) to serve the ad banners,
 1037  
     * and Apache will only send a <TT>Last-Modified</TT> in the header if the
 1038  
     * <TT>XBitHack</TT> option is enabled in <TT>httpd.conf</TT> and the
 1039  
     * <TT>x</TT> bit is set.  For a while we feared that if Apache doesn't send
 1040  
     * <TT>Last-Modified</TT>, Google doesn't index us; that seems not to be
 1041  
     * true, but nevertheless sending <TT>Last-Modified</TT> is a good thing.
 1042  
     */
 1043  
 
 1044  
    public static void notifyNewContentFile(File file) throws IOException {
 1045  9
      FileUtils.makeExecutable(file);
 1046  9
    }
 1047  
 
 1048  
    public String getWMTemplet(String templetName) {
 1049  0
      return "org/paneris/bibliomania/template/webmacro/templets/html/" + templetName + ".wm";
 1050  
    }
 1051  
 
 1052  
    public final void interpolateTemplateToStream(
 1053  
        org.webmacro.Template template,
 1054  
        OutputStream o,
 1055  
        Unit object) throws WebMacroException, IOException {
 1056  1
      interpolateTemplateToStream(template, o, object, null);
 1057  1
    }
 1058  
    public void interpolateTemplateToStream(org.webmacro.Template template,
 1059  
                               OutputStream o,
 1060  
                               Unit object,
 1061  
                               Hashtable extras)
 1062  
        throws WebMacroException, IOException {
 1063  
      
 1064  6
      WebMacro wm = getWebMacro();
 1065  
 
 1066  6
      MelatiFastWriter fmw =
 1067  
        new MelatiFastWriter(wm.getBroker(), o, getContentEncoding());
 1068  6
      Melati m = new Melati(new MelatiConfig(), fmw);
 1069  6
      Context context = wm.getContext();
 1070  6
      setupContext(m, context, object, extras);
 1071  6
      template.write(fmw.getFastWriter(), context);
 1072  6
      fmw.getFastWriter().flush();
 1073  
      /*
 1074  
          Melati m = new Melati(new MelatiConfig(),
 1075  
                                new SimpleMelatiWriter(new OutputStreamWriter(o)));
 1076  
          m.setBufferingOff(false);
 1077  
          Context context = wm.getContext();
 1078  
          setupContext(m, context, object, extras);
 1079  
          template.write(new FastWriter(o, getContentEncoding()), context);
 1080  
      */
 1081  6
    }
 1082  
 
 1083  
   public final void interpolateTemplateToFile(
 1084  
       String templateName, 
 1085  
       File to,
 1086  
       Unit object) throws WebMacroException, IOException {
 1087  3
     interpolateTemplateToFile(templateName, to, object, null);
 1088  3
   }
 1089  
 
 1090  
    public void interpolateTemplateToFile(
 1091  
        String templateName,
 1092  
        File to,
 1093  
        Unit object,
 1094  
        Hashtable<String, Object> extras) throws WebMacroException, IOException {
 1095  5
      org.webmacro.Template template = getWebMacro().getTemplate(templateName);
 1096  5
      OutputStream out = new BufferedOutputStream(new FileOutputStream(to));
 1097  
      try {
 1098  5
        interpolateTemplateToStream(template, out, object, extras);
 1099  
      } finally {
 1100  0
        try {
 1101  5
          out.close();
 1102  0
        } catch (Exception e) {
 1103  0
          throw new RuntimeException(e);
 1104  5
        }
 1105  
      }
 1106  
 
 1107  5
      notifyNewContentFile(to);
 1108  5
    }
 1109  
 
 1110  
 
 1111  
    public void interpolateAsTemplate(Reader in, OutputStream out, Unit object)
 1112  
        throws WebMacroException, IOException {
 1113  1
      interpolateTemplateToStream(
 1114  
          new StreamTemplate(getWebMacro().getBroker(), in), out, object);
 1115  1
    }
 1116  
 
 1117  
    public void interpolateAsTemplate(File from, OutputStream out, Unit object)
 1118  
        throws WebMacroException, IOException {
 1119  1
      Reader in = new BufferedReader(new FileReader(from));
 1120  
      try {
 1121  1
        interpolateAsTemplate(in, out, object);
 1122  
      } finally {
 1123  0
        try {
 1124  1
          in.close();
 1125  0
        } catch (Exception e) {
 1126  0
          throw new RuntimeException(e);
 1127  1
        }
 1128  
      }
 1129  1
    }
 1130  
 
 1131  
    public void interpolateAsTemplate(File from, File to, Unit object)
 1132  
        throws WebMacroException, IOException {
 1133  1
      OutputStream out = new BufferedOutputStream(new FileOutputStream(to));
 1134  
      try {
 1135  1
        interpolateAsTemplate(from, out, object);
 1136  
      } finally {
 1137  0
        try {
 1138  1
          out.close();
 1139  0
        } catch (Exception e) {
 1140  0
          throw new RuntimeException(e);
 1141  1
        }
 1142  
      }
 1143  1
    }
 1144  
 
 1145  
    public static class TemplateException extends MelatiRuntimeException {
 1146  
      private static final long serialVersionUID = 1L;
 1147  
      public File file;
 1148  
 
 1149  
      public TemplateException(File file, Exception trouble) {
 1150  
        super(trouble);
 1151  
        this.file = file;
 1152  
      }
 1153  
 
 1154  
      public String getMessage() {
 1155  
        return "Couldn't load templet from " + file + "\n" + subException;
 1156  
      }
 1157  
    }
 1158  
 
 1159  
    private org.webmacro.Template template(String source) {
 1160  1
      File file = new File(getContentRootDir(), source);
 1161  
 
 1162  1
      org.webmacro.Template it =
 1163  
        new FileTemplate(getWebMacro().getBroker(), file, getContentEncoding());
 1164  
      try {
 1165  1
        it.parse();
 1166  0
      } catch (Exception e) {
 1167  0
        throw new TemplateException(file, e);
 1168  1
      }
 1169  
 
 1170  1
      return it;
 1171  
    }
 1172  
 
 1173  
    public void writeContentHeader(OutputStream w, Unit object, String template)
 1174  
      throws WebMacroException, IOException {
 1175  0
      interpolateTemplateToStream(
 1176  
        template(template == null ? "header.wm" : template),
 1177  
        w,
 1178  
        object);
 1179  0
    }
 1180  
 
 1181  
    public void writeContentFooter(OutputStream w, Unit object, String template)
 1182  
      throws WebMacroException, IOException {
 1183  0
      interpolateTemplateToStream(
 1184  
        template(template == null ? "footer.wm" : template),
 1185  
        w,
 1186  
        object);
 1187  0
    }
 1188  
 
 1189  2
    private org.webmacro.Template footnoteTemplate = null;
 1190  
 
 1191  
    public org.webmacro.Template getFootnoteTemplate() {
 1192  1
      if (footnoteTemplate == null)
 1193  1
        footnoteTemplate = template("footnote.wm");
 1194  
 
 1195  1
      return footnoteTemplate;
 1196  
    }
 1197  
 
 1198  
    public String getPasswordReminderMessage() {
 1199  0
      return passwordReminderMessage.getStringCooked();
 1200  
    }
 1201  
 
 1202  
    public org.webmacro.Template getPasswordReminderTemplate() {
 1203  0
      return new StreamTemplate(
 1204  
        getWebMacro().getBroker(),
 1205  
        new StringReader(getPasswordReminderMessage().trim()));
 1206  
      //        new StringReader(getPasswordReminderMessage().trim()),getContentEncoding());
 1207  
    }
 1208  
 
 1209  
    public String getPasswordReminderFrom() {
 1210  0
      return passwordReminderFrom.getStringCooked();
 1211  
    }
 1212  
 
 1213  
    public String getOrderEmailFrom() {
 1214  0
      return orderEmailFrom.getStringCooked();
 1215  
    }
 1216  
 
 1217  
    public String getConfirmationEmailFrom() {
 1218  0
      return confirmationEmailFrom.getStringCooked();
 1219  
    }
 1220  
 
 1221  
    public String getOrderEmailTo() {
 1222  0
      return orderEmailTo.getStringCooked();
 1223  
    }
 1224  
 
 1225  
    public String getStratusEmailTo() {
 1226  0
      return stratusEmailTo.getStringCooked();
 1227  
    }
 1228  
 
 1229  
    public String getCachedContentRootDir() {
 1230  9
      return getWorkspaceDir() + "/cached";
 1231  
    }
 1232  
 
 1233  
    public String getStaticRootURL() {
 1234  20
      return staticRootURL.getStringCooked();
 1235  
    }
 1236  
 
 1237  
    public String getContentStaticRootURL() {
 1238  0
      return contentStaticRootURL.getStringCooked();
 1239  
    }
 1240  
 
 1241  
    public String getBannerURLPath() {
 1242  3
      return bannerURLPath.getStringCooked();
 1243  
    }
 1244  
 
 1245  
    public String getCacheRootURL() {
 1246  27
      String it = cacheRootURL.getStringCooked();
 1247  27
      return it == null ? "" : it;
 1248  
    }
 1249  
 
 1250  
    public String getHomepageURL() {
 1251  9
      return homepageURL.getStringCooked();
 1252  
    }
 1253  
 
 1254  
    public String getSmtpServer() {
 1255  0
      return smtpServer.getStringCooked();
 1256  
    }
 1257  
 
 1258  
    public int getDefaultSearchHitsPerText() {
 1259  0
      Integer it = defaultSearchHitsPerText.getIntegerCooked();
 1260  0
      return it == null ? defaultDefaultSearchHitsPerText : it.intValue();
 1261  
    }
 1262  
 
 1263  
    public int getSearchHitsPerPage() {
 1264  0
      Integer it = searchHitsPerPage.getIntegerCooked();
 1265  0
      return it == null ? defaultSearchHitsPerPage : it.intValue();
 1266  
    }
 1267  
 
 1268  
    public String getPaginationTexHeader() {
 1269  1
      return paginationTexHeader.getStringCooked();
 1270  
    }
 1271  
 
 1272  
    public int getBookStockingsCheckIntervalDays() {
 1273  0
      Integer it = bookStockingsCheckIntervalDays.getIntegerCooked();
 1274  0
      return it == null ? defaultBookStockingsCheckIntervalDays : it.intValue();
 1275  
    }
 1276  
 
 1277  
    public long getBookStockingsCheckIntervalMillis() {
 1278  0
      return (long)getBookStockingsCheckIntervalDays() * 1000L * 60L * 60L * 24L;
 1279  
    }
 1280  
 
 1281  
    public int getBibBookBookshopSearchTimeoutSeconds() {
 1282  0
      Integer it = bibBookBookshopSearchTimeoutSeconds.getIntegerCooked();
 1283  0
      return it == null
 1284  
        ? defaultBibBookBookshopSearchTimeoutSeconds
 1285  
        : it.intValue();
 1286  
    }
 1287  
 
 1288  
    public long getBibBookBookshopSearchTimeoutMillis() {
 1289  0
      return (long)getBibBookBookshopSearchTimeoutSeconds() * 1000L;
 1290  
    }
 1291  
 
 1292  
    public int getBookStockingsOutputStartOffset() {
 1293  0
      Integer it = bookStockingsOutputStartOffset.getIntegerCooked();
 1294  0
      return it == null ? defaultBookStockingsOutputStartOffset : it.intValue();
 1295  
    }
 1296  
 
 1297  
    public String getBookStockingsCacheDir() {
 1298  0
      return bookStockingsCacheDir.getStringCooked();
 1299  
    }
 1300  
 
 1301  
    public int getBookStockingsCacheSizeMax() {
 1302  0
      Integer it = bookStockingsCacheSizeMax.getIntegerCooked();
 1303  0
      return it == null ? defaultBookStockingsCacheSizeMax : it.intValue();
 1304  
    }
 1305  
 
 1306  
    public Integer pageFromAnchor(String anchor) {
 1307  0
      if (anchor.startsWith(Pagination.pageAnchorPrefix))
 1308  
        try {
 1309  0
          return new Integer(
 1310  
            Integer.parseInt(
 1311  
              anchor.substring(Pagination.pageAnchorPrefix.length()))
 1312  
              + 1);
 1313  0
        } catch (NumberFormatException e) {
 1314  0
          return null;
 1315  
        } else
 1316  0
        return null;
 1317  
    }
 1318  
 
 1319  
    public static class BookshopException extends MelatiRuntimeException {
 1320  
      /**
 1321  
       * 
 1322  
       */
 1323  
      private static final long serialVersionUID = 1L;
 1324  
      public String which;
 1325  
 
 1326  
      public BookshopException(String which, Exception e) {
 1327  
        super(e);
 1328  
        this.which = which;
 1329  
      }
 1330  
 
 1331  
      public String getMessage() {
 1332  
        return "Something went wrong starting the "
 1333  
          + which
 1334  
          + " subsystem\n"
 1335  
          + subException.getMessage();
 1336  
      }
 1337  
    }
 1338  
 
 1339  
    private BookshopBackend bookshopBackendNamed(String packageComp) {
 1340  
      try {
 1341  0
        return (
 1342  
          (BookshopBackendFactory)Class
 1343  
            .forName(
 1344  
              "org.paneris.bibliomania.metasearch." + packageComp + ".Factory")
 1345  
            .newInstance())
 1346  
            .instance(
 1347  
          new File(getWorkspaceDir()),
 1348  
          0);
 1349  0
      } catch (Exception e) {
 1350  0
        throw new BookshopException(packageComp, e);
 1351  
      }
 1352  
    }
 1353  
 
 1354  
    public Bookshop[] bookshops() {
 1355  0
      return bookshops;
 1356  
    }
 1357  
 
 1358  
    public SectionGroup getReadSectionGroup() {
 1359  3
      return readSectionGroup;
 1360  
    }
 1361  
 
 1362  
    public Currency getUKCurrency() {
 1363  0
      return UKCurrency;
 1364  
    }
 1365  
 
 1366  
    /** Not used, just for show */
 1367  
    public List<ShopOrder> getUKCurrentcyShopOrders() { 
 1368  0
      return getUKCurrency().getCurrencyShopOrderList();
 1369  
    }
 1370  
 
 1371  
    public SectionGroup getStudySectionGroup() {
 1372  5
      return studySectionGroup;
 1373  
    }
 1374  
 
 1375  
    public SectionGroup getResearchSectionGroup() {
 1376  0
      return researchSectionGroup;
 1377  
    }
 1378  
 
 1379  
    public SectionGroup getShopSectionGroup() {
 1380  0
      return shopSectionGroup;
 1381  
    }
 1382  
 
 1383  
    public SectionGroup getSearchSectionGroup() {
 1384  0
      return searchSectionGroup;
 1385  
    }
 1386  
 
 1387  
    public Group getRegisteredUserGroup() {
 1388  0
      return registeredUserGroup;
 1389  
    }
 1390  
 
 1391  
    public Capability getRegisteredUserCapability() {
 1392  0
      return registeredUserCapability;
 1393  
    }
 1394  
    public Capability getContentModificationCapability() {
 1395  0
      return contentModificationCapability;
 1396  
    }
 1397  
    public Capability getContentAdditionCapability() {
 1398  0
      return contentAdditionCapability;
 1399  
    }
 1400  
 
 1401  
    public User getTemplateRegisterUser() {
 1402  0
      return templateRegisterUser;
 1403  
    }
 1404  
 
 1405  2
    private Bib bib = null;
 1406  
 
 1407  
    public Bib getBib() {
 1408  6
      if (bib == null)
 1409  2
        bib = new Bib(this);
 1410  6
      return bib;
 1411  
    }
 1412  
 
 1413  2
    private int bookshopSearchesRunning = 0;
 1414  
 
 1415  
    public void notifyBookshopSearchStart() {
 1416  0
      ++bookshopSearchesRunning;
 1417  0
    }
 1418  
 
 1419  
    public void notifyBookshopSearchStop() {
 1420  0
      --bookshopSearchesRunning;
 1421  0
    }
 1422  
 
 1423  
    public boolean okToRunABookshopSearch() {
 1424  0
      Integer maxO = bookStockingsCheckConcurrentMax.getIntegerCooked();
 1425  0
      int max =
 1426  
        maxO == null ? defaultBookStockingsCheckConcurrentMax : maxO.intValue();
 1427  
 
 1428  0
      return bookshopSearchesRunning < max;
 1429  
    }
 1430  
 
 1431  
    public boolean getBookStockingsInBackground() {
 1432  0
      return bookStockingsInBackgroundAppropriate
 1433  
        && Boolean.TRUE.equals(bookStockingsInBackground.getBooleanCooked());
 1434  
    }
 1435  
 
 1436  
    public String getContentEncoding() {
 1437  8
      return contentEncoding.getStringCooked();
 1438  
    }
 1439  
 
 1440  0
    private class BackgroundStockingsChecker extends Thread {
 1441  
 
 1442  
      private PreparedStatementFactory booksPS, booksPSNull;
 1443  
 
 1444  0
      BackgroundStockingsChecker() {
 1445  0
        booksPSNull =
 1446  
          new PreparedStatementFactory(
 1447  
            BibliomaniaDatabase.this,
 1448  
            "SELECT book.id FROM book WHERE lastbookshopsearch IS NULL AND "
 1449  
              + "(hasnofrontpage IS NULL OR NOT hasnofrontpage) AND "
 1450  
              + "(author.id = book.author AND "
 1451  
              + "(author.nonstandard IS NULL OR NOT author.nonstandard)) "
 1452  
              + "LIMIT 1");
 1453  
 
 1454  0
        booksPS =
 1455  
          new PreparedStatementFactory(
 1456  
            BibliomaniaDatabase.this,
 1457  
            "SELECT id FROM book WHERE lastbookshopsearch < ? AND "
 1458  
              + "(hasnofrontpage IS NULL OR NOT hasnofrontpage) AND "
 1459  
              + "(author.id = book.author AND "
 1460  
              + "(author.nonstandard IS NULL OR NOT author.nonstandard)) "
 1461  
              + "ORDER BY lastbookshopsearch "
 1462  
              + "LIMIT 1");
 1463  0
      }
 1464  
 
 1465  
      private void doNext() throws Exception {
 1466  0
        inSession(AccessToken.root, new PoemTask() {
 1467  
          public void run() {
 1468  
            Book nextToDo;
 1469  0
            PreparedStatement ps = null;
 1470  
 
 1471  
            try {
 1472  0
              if (!getBookStockingsInBackground())
 1473  0
                nextToDo = null;
 1474  
              else {
 1475  0
                Integer bookTroid = null;
 1476  
 
 1477  0
                ps = booksPSNull.preparedStatement(PoemThread.transaction());
 1478  0
                ResultSet rs = ps.executeQuery();
 1479  
                try {
 1480  0
                  if (rs.next())
 1481  0
                    bookTroid = new Integer(rs.getInt(1));
 1482  
                } finally {
 1483  0
                  rs.close();
 1484  0
                }
 1485  
 
 1486  0
                if (bookTroid == null) {
 1487  0
                  ps = booksPS.preparedStatement(PoemThread.transaction());
 1488  0
                  ps.setTimestamp(
 1489  
                    1,
 1490  
                    new Timestamp(
 1491  
                      System.currentTimeMillis()
 1492  
                        - getBookStockingsCheckIntervalMillis()));
 1493  
 
 1494  0
                  rs = ps.executeQuery();
 1495  
                  try {
 1496  0
                    if (rs.next())
 1497  0
                      bookTroid = new Integer(rs.getInt(1));
 1498  
                  } finally {
 1499  0
                    rs.close();
 1500  0
                  }
 1501  
                }
 1502  
 
 1503  0
                nextToDo =
 1504  
                  bookTroid == null
 1505  
                    ? null
 1506  
                    : (Book)getBookTable().getObject(bookTroid);
 1507  
              }
 1508  0
            } catch (Exception e) {
 1509  0
              System.err.println("BackgroundStockingsChecker: " + e);
 1510  0
              nextToDo = null;
 1511  0
            }
 1512  
 
 1513  0
            if (nextToDo != null)
 1514  0
              getStockingsSearchTable().searchFor(nextToDo).runNewSearch();
 1515  0
          }
 1516  
        });
 1517  0
      }
 1518  
 
 1519  
      public void run() {
 1520  
        for (;;) {
 1521  
          try {
 1522  0
            Thread.sleep(120000);
 1523  0
            doNext();
 1524  0
          } catch (Exception e) {
 1525  0
            System.err.println("Background stockings checker: " + e);
 1526  0
          }
 1527  
        }
 1528  
      }
 1529  
    }
 1530  
 
 1531  
    public Author getShakespeare() {
 1532  3
      return shakespeare;
 1533  
    }
 1534  
 
 1535  
    public Section getDrama() {
 1536  2
      return drama;
 1537  
    }
 1538  
 
 1539  
    public Book getMacbeth() {
 1540  0
      return macbeth;
 1541  
    }
 1542  
 
 1543  
  public org.paneris.melati.boards.model.UserTable<org.paneris.melati.boards.model.User> getBoardsUserTable() {  
 1544  0
   return (org.paneris.melati.boards.model.UserTable<org.paneris.melati.boards.model.User>)getBoardsUserTable();
 1545  
  }
 1546  
  
 1547  
  /** 
 1548  
   * Convert 'Head in the Sky' to 'headInTheSky'.
 1549  
   * Also 'NHS management' to 'nhsManagement'.
 1550  
   */
 1551  
  public static String toCamelCase(String value) {
 1552  2
    return toCamelCase(value, true);   
 1553  
  }
 1554  
  public static String toCamelCase(String value, boolean lowercaseFirstLetter) {
 1555  4
    StringBuilder sb = new StringBuilder();
 1556  
 
 1557  4
    final char delimiter = ' ';
 1558  4
    boolean lower = lowercaseFirstLetter;
 1559  62
    for (int i = 0; i < value.length(); ++i) {
 1560  58
      final char valueChar = value.charAt(i);
 1561  58
      if (valueChar == delimiter) {
 1562  8
        lower = false;
 1563  50
      } else if (lower) {
 1564  40
        sb.append(Character.toLowerCase(valueChar));
 1565  
      } else {
 1566  10
        sb.append(Character.toUpperCase(valueChar));
 1567  10
        lower = true;
 1568  
      }
 1569  
    }
 1570  
 
 1571  4
    return sb.toString();
 1572  
  }
 1573  
 }
 1574  
 
 1575