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
59
60 public class BibliomaniaDatabase extends BibliomaniaDatabaseBase
61 implements BibliomaniaDatabaseTables {
62
63 private IndexOther fti = null, infoFTI = null;
64 private Properties ftiConfig;
65 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
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
119
120 private Group registeredUserGroup;
121
122 private Capability registeredUserCapability,
123 contentModificationCapability,
124 contentAdditionCapability;
125
126 private User templateRegisterUser;
127
128 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 this(false);
144 }
145
146 public BibliomaniaDatabase(boolean bookStockingsInBackgroundAppropriate) {
147 this(bookStockingsInBackgroundAppropriate, true);
148 }
149
150 public BibliomaniaDatabase(
151 boolean bookStockingsInBackgroundAppropriate,
152 boolean openAuxDBs) {
153 this(bookStockingsInBackgroundAppropriate, openAuxDBs, null);
154 }
155
156 public BibliomaniaDatabase(
157 boolean bookStockingsInBackgroundAppropriate,
158 boolean openAuxDBs,
159 Properties ftiConfig) {
160 this.bookStockingsInBackgroundAppropriate =
161 bookStockingsInBackgroundAppropriate;
162 this.openBerkeleyDBs = openAuxDBs;
163 this.ftiConfig = ftiConfig;
164 }
165
166 public boolean debug() {
167 return false;
168 }
169
170 public Capability getCanAdminister() {
171 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 super.connect(name, dbmsclass, url, username, password, maxConnections);
182
183 inSession(AccessToken.root, new PoemTask() {
184 public void run() {
185 String root = "/usr/local/bibliomania";
186 ((UserTable)getUserTable()).setBoardManager(
187 ((UserTable)getUserTable()).ensure(
188 "_manager_","FIXME",
189 "board_manager@paneris.co.uk",
190 "Bibliomania Board Manager"));
191
192
193 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 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 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
230
231
232
233
234
235
236
237
238
239
240
241 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 drama = getSectionTable().ensure("Drama", readSectionGroup);
255 shakespeare = getAuthorTable().ensure("William Shakespeare", drama);
256 macbeth = getBookTable().ensure("Macbeth", shakespeare, drama);
257
258 registeredUserGroup = getGroupTable().ensure("Registered users");
259 registeredUserCapability =
260 getCapabilityTable().ensure("Access study material");
261 contentModificationCapability =
262 getCapabilityTable().ensure("Edit content database");
263 contentAdditionCapability =
264 getCapabilityTable().ensure("Add to content database");
265
266 getGroupCapabilityTable().ensure(
267 getGroupTable().administratorsGroup(),
268 contentModificationCapability);
269
270 getGroupCapabilityTable().ensure(
271 getGroupTable().administratorsGroup(),
272 contentAdditionCapability);
273
274
275 templateRegisterUser =
276 (User)getUserTable().getLoginColumn().firstWhereEq(
277 "_registerTemplate_");
278
279 if (templateRegisterUser == null) {
280 templateRegisterUser = (User)getUserTable().newPersistent();
281 templateRegisterUser.setLogin("_registerTemplate_");
282 templateRegisterUser.setPassword("0.804461358580738");
283 templateRegisterUser.setEmail("none@bogus");
284 templateRegisterUser.setFulltimeeducation(false);
285 templateRegisterUser.setWantspam(false);
286 templateRegisterUser.setWantemailalerts(false);
287 templateRegisterUser.setDodgeyemail(false);
288 templateRegisterUser.setName(
289 "<Template for newly registering users>");
290 getUserTable().create(templateRegisterUser);
291 }
292
293 workspaceDir =
294 getSettingTable().ensure(
295 "WorkspaceDir",
296 root + "/workspace",
297 "Workspace directory",
298 "Where the system should store its working files");
299
300 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 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 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 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 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 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 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 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 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 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 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 bookStockingsInBackground =
387 getSettingTable().ensure(
388 "StockingsCheckInBackground",
389 false,
390 "Background bookshop search",
391 "Whether to run continual bookshop searches in the background");
392
393 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 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 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 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 UKCurrency =
424 getCurrencyTable().ensure("UK Pound Sterling", 1d, Locale.UK);
425
426
427 if (openBerkeleyDBs) {
428 try {
429 fti = new IndexOther(new File(getWorkspaceDir()), ftiConfig);
430 infoFTI = new IndexOther(new File(getInfoFTIDir()));
431 } catch (Exception e) {
432 throw new FTIException(e);
433 }
434 }
435 try{
436 pagination = new Pagination(new File(getWorkspaceDir()));
437 } catch (Exception e) {
438 throw new RuntimeException(e);
439 }
440
441 paginationTexHeader =
442 (Setting)getSettingTable().getNameColumn().firstWhereEq(
443 "PaginationTexHeader");
444 if (paginationTexHeader == null) {
445 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 paginationTexHeader.setWidth(60);
453 paginationTexHeader.setHeight(5);
454 }
455
456 Vector<Bookshop> bookshopsList = new Vector<Bookshop>();
457
458 Bookshop bol = getBookshopTable().ensure("BOLUK", "BOL UK", "uk.gif");
459 if (!Boolean.TRUE.equals(bol.getDisabled())) {
460 bol.backend = bookshopBackendNamed("bol");
461 bookshopsList.addElement(bol);
462 }
463
464 Bookshop bob =
465 getBookshopTable().ensure(
466 "BOB",
467 "Blackwells Online Bookshop",
468 "uk.gif");
469 if (!Boolean.TRUE.equals(bob.getDisabled())) {
470 bob.backend = bookshopBackendNamed("bob");
471 bookshopsList.addElement(bob);
472 }
473
474 Bookshop amazon =
475 getBookshopTable().ensure("AMAZON", "amazon.com", "us.gif");
476 if (!Boolean.TRUE.equals(amazon.getDisabled())) {
477 amazon.backend = bookshopBackendNamed("amazon");
478 bookshopsList.addElement(amazon);
479 }
480
481 bookshops = new Bookshop[bookshopsList.size()];
482 bookshopsList.copyInto(bookshops);
483
484 String defaultSmtpServer;
485 try {
486 defaultSmtpServer = InetAddress.getLocalHost().toString();
487 } catch (Exception e) {
488 defaultSmtpServer = "www.bibliomania.com";
489 }
490
491 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 passwordReminderMessage =
498 (Setting)getSettingTable().getNameColumn().firstWhereEq(
499 "PasswordReminderMessage");
500 if (passwordReminderMessage == null) {
501 String it;
502 try {
503 it =
504 new String(
505 IoUtils.slurp(
506 this.getClass().getResource(defaultPasswordReminderMessage),
507 4096));
508 } catch (Exception e) {
509 throw new UnexpectedExceptionException(
510 "Didn't find resource " + defaultPasswordReminderMessage,
511 e);
512 }
513
514 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 passwordReminderMessage.setWidth(80);
522 passwordReminderMessage.setHeight(30);
523 }
524
525 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 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 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 orderEmailTo =
550 getSettingTable().ensure(
551 "OrderEmailTo",
552 defaultOrderEmailTo,
553 "Order Email `To:'",
554 "The address to send email acknowledgements to (at bibliomania)");
555
556 stratusEmailTo =
557 getSettingTable().ensure(
558 "StratusEmailTo",
559 defaultStratusEmailTo,
560 "Stratus Email `To:'",
561 "The address to send email orders to (at Stratus)");
562
563 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 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 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
589
590
591
592 setDefaultAccessPermissions(
593 getAdvertTable().getTableInfo(),
594 contentAdditionCapability,
595 administerCapability(),
596 contentModificationCapability,
597 null);
598
599
600
601 setDefaultAccessPermissions(
602 getAttachmentTable().getTableInfo(),
603 null,
604 administerCapability(),
605 administerCapability(),
606 null);
607
608
609 setDefaultAccessPermissions(
610 getAttachmentTypeTable().getTableInfo(),
611 administerCapability(),
612 administerCapability(),
613 administerCapability(),
614 null);
615
616
617 setDefaultAccessPermissions(
618 getAuthorTable().getTableInfo(),
619 contentAdditionCapability,
620 administerCapability(),
621 contentModificationCapability,
622 null);
623
624
625 setDefaultAccessPermissions(
626 getAuthorWebSiteTable().getTableInfo(),
627 contentAdditionCapability,
628 administerCapability(),
629 contentModificationCapability,
630 null);
631
632
633 setDefaultAccessPermissions(
634 getBoardTable().getTableInfo(),
635 contentAdditionCapability,
636 administerCapability(),
637 contentModificationCapability,
638 null);
639
640
641 setDefaultAccessPermissions(
642 getBoardTypeTable().getTableInfo(),
643 administerCapability(),
644 administerCapability(),
645 contentModificationCapability,
646 null);
647
648
649 setDefaultAccessPermissions(
650 getBookTable().getTableInfo(),
651 contentAdditionCapability,
652 administerCapability(),
653 contentModificationCapability,
654 null);
655
656
657 setDefaultAccessPermissions(
658 getBookFormatTable().getTableInfo(),
659 administerCapability(),
660 administerCapability(),
661 administerCapability(),
662 null);
663
664
665 setDefaultAccessPermissions(
666 getBookshopTable().getTableInfo(),
667 administerCapability(),
668 administerCapability(),
669 contentModificationCapability,
670 null);
671
672
673 setDefaultAccessPermissions(
674 getBookStockingTable().getTableInfo(),
675 administerCapability(),
676 administerCapability(),
677 administerCapability(),
678 null);
679
680
681 setDefaultAccessPermissions(
682 getChapterTable().getTableInfo(),
683 contentAdditionCapability,
684 administerCapability(),
685 contentModificationCapability,
686 null);
687
688
689 setDefaultAccessPermissions(
690 getCountryTable().getTableInfo(),
691 contentAdditionCapability,
692 administerCapability(),
693 contentModificationCapability,
694 null);
695
696
697 setDefaultAccessPermissions(
698 getCurrencyTable().getTableInfo(),
699 contentAdditionCapability,
700 administerCapability(),
701 contentModificationCapability,
702 null);
703
704
705 setDefaultAccessPermissions(
706 getDeliveryChargeTable().getTableInfo(),
707 contentAdditionCapability,
708 administerCapability(),
709 contentModificationCapability,
710 null);
711
712
713 setDefaultAccessPermissions(
714 getDeliveryChargeBandTable().getTableInfo(),
715 contentAdditionCapability,
716 administerCapability(),
717 contentModificationCapability,
718 null);
719
720
721 setDefaultAccessPermissions(
722 getDownloadTable().getTableInfo(),
723 contentAdditionCapability,
724 administerCapability(),
725 contentModificationCapability,
726 null);
727
728
729 setDefaultAccessPermissions(
730 getDownloadEventTable().getTableInfo(),
731 null,
732 administerCapability(),
733 administerCapability(),
734 administerCapability());
735
736
737 setDefaultAccessPermissions(
738 getLayoutTable().getTableInfo(),
739 contentAdditionCapability,
740 administerCapability(),
741 contentModificationCapability,
742 null);
743
744
745 setDefaultAccessPermissions(
746 getMembershipStatusTable().getTableInfo(),
747 contentAdditionCapability,
748 administerCapability(),
749 contentModificationCapability,
750 null);
751
752
753 setDefaultAccessPermissions(
754 getShopOrderTable().getTableInfo(),
755 null,
756 administerCapability(),
757 null,
758 null);
759
760
761 setDefaultAccessPermissions(
762 getShopOrderItemTable().getTableInfo(),
763 null,
764 administerCapability(),
765 null,
766 null);
767
768
769 setDefaultAccessPermissions(
770 getOrderStatusTable().getTableInfo(),
771 administerCapability(),
772 administerCapability(),
773 administerCapability(),
774 null);
775
776
777 setDefaultAccessPermissions(
778 getProductTable().getTableInfo(),
779 contentAdditionCapability,
780 administerCapability(),
781 contentModificationCapability,
782 null);
783
784
785 setDefaultAccessPermissions(
786 getProductAssociationTable().getTableInfo(),
787 contentAdditionCapability,
788 administerCapability(),
789 contentModificationCapability,
790 null);
791
792
793 setDefaultAccessPermissions(
794 getPublisherTable().getTableInfo(),
795 contentAdditionCapability,
796 administerCapability(),
797 contentModificationCapability,
798 null);
799
800
801 setDefaultAccessPermissions(
802 getPublisherTable().getTableInfo(),
803 contentAdditionCapability,
804 administerCapability(),
805 contentModificationCapability,
806 null);
807
808
809 setDefaultAccessPermissions(
810 getSectionTable().getTableInfo(),
811 contentAdditionCapability,
812 administerCapability(),
813 contentModificationCapability,
814 null);
815
816
817 setDefaultAccessPermissions(
818 getSectionTable().getTableInfo(),
819 administerCapability(),
820 administerCapability(),
821 administerCapability(),
822 null);
823
824
825 setDefaultAccessPermissions(
826 getSexTable().getTableInfo(),
827 administerCapability(),
828 administerCapability(),
829 administerCapability(),
830 null);
831
832
833 setDefaultAccessPermissions(
834 getStockingsSearchTable().getTableInfo(),
835 null,
836 administerCapability(),
837 administerCapability(),
838 null);
839
840
841 setDefaultAccessPermissions(
842 getSupplierTable().getTableInfo(),
843 contentAdditionCapability,
844 administerCapability(),
845 contentModificationCapability,
846 null);
847
848
849 setDefaultAccessPermissions(
850 getSupplierProductTable().getTableInfo(),
851 contentAdditionCapability,
852 administerCapability(),
853 contentModificationCapability,
854 null);
855
856
857 setDefaultAccessPermissions(
858 getUserTable().getTableInfo(),
859 administerCapability(),
860 administerCapability(),
861 administerCapability(),
862 administerCapability());
863 }
864 });
865
866 if (bookStockingsInBackgroundAppropriate)
867 new BackgroundStockingsChecker().start();
868
869
870
871
872
873 }
874
875 private void setDefaultAccessPermissions(
876 TableInfo info,
877 Capability add,
878 Capability delete,
879 Capability write,
880 Capability read) {
881 if (info.getCancreate() == null)
882 info.setCancreate(add);
883 if (info.getDefaultcandelete() == null)
884 info.setDefaultcandelete(delete);
885 if (info.getDefaultcanwrite() == null)
886 info.setDefaultcanwrite(write);
887 if (info.getDefaultcanread() == null)
888 info.setDefaultcanread(read);
889 }
890
891 public IndexOther fti() {
892 return fti;
893 }
894
895 public IndexOther infoFTI() {
896 return infoFTI;
897 }
898
899 Library infoLibrary = new Library() {
900 public Text text(long textID) {
901 int a =
902 (int) ((textID & ((1l << Chapter.ftiTextID_section_shift) - 1))
903 >> Chapter.ftiTextID_author_shift);
904
905 long aMask = (1l << Chapter.ftiTextID_author_shift) - 1;
906
907 if ((textID & aMask) == aMask) {
908
909
910 try {
911 return getAuthorTable().getAuthorObject(new Integer(a));
912 } catch (NoSuchRowPoemException e) {
913
914 e.printStackTrace(System.err);
915 return null;
916 }
917 } else {
918
919 int b = (int) ((textID & aMask) >> Chapter.ftiTextID_book_shift);
920 return (Book)getBookTable().firstSelection(
921 "author = " + a + " AND " + "authorsequence = " + b);
922 }
923 }
924 };
925
926 public Library infoLibrary() {
927 return infoLibrary;
928 }
929
930 public boolean openBerkelyDBs() {
931 return openBerkeleyDBs;
932 }
933
934 public Pagination pagination() {
935 return pagination;
936 }
937
938 public String getWorkspaceDir() {
939 return workspaceDir.getStringCooked();
940 }
941
942 public String getUploadDir() {
943 return uploadDir.getStringCooked();
944 }
945
946 public String getUploadURL() {
947 return uploadURL.getStringCooked();
948 }
949
950 public String getInfoFTIDir() {
951 return getWorkspaceDir() + infoFTIDir.getStringCooked();
952 }
953
954 public String getContentRootDir() {
955 return contentRootDir.getStringCooked();
956 }
957
958 private WebMacro _wm = null;
959
960 public WebMacro getWebMacro() {
961 if (_wm == null) {
962 synchronized (this) {
963 if (_wm == null) {
964 try {
965 _wm = new WM();
966 } catch (InitException e) {
967 throw new UnexpectedExceptionException(
968 "Initialising WebMacro for the pagination subsystem",
969 e);
970 }
971 }
972 }
973 }
974
975 return _wm;
976 }
977
978 public void
979 setupContext(Melati melati, Context context, Unit it, Hashtable<String, Object> extras) {
980
981 SectionGroup sectiongroup = it == null ? null : it.getReadArea();
982 context.put("sectiongroup", sectiongroup);
983 if (sectiongroup != null) {
984 context.put("areaColour", sectiongroup.getThemecolour());
985 } else {
986 context.put("areaColour", "#FF0000");
987 }
988
989 Section section = null;
990 Author author = null;
991 Book book = null;
992 Chapter chapter = null;
993
994 if (it != null) {
995 context.put("meta_description", it.getMetatag_description());
996 context.put("meta_keywords", it.getMetatag_keywords());
997
998 if (it instanceof Chapter) {
999 chapter = (Chapter)it;
1000 book = chapter.getBook();
1001 author = book.getAuthor();
1002 section = book.getSection();
1003 } else if (it instanceof Book) {
1004 book = (Book)it;
1005 author = book.getAuthor();
1006 section = book.getSection();
1007 } else if (it instanceof Author) {
1008 author = (Author)it;
1009 } else if (it instanceof Section) {
1010 section = (Section)it;
1011 }
1012 }
1013
1014 context.put("object", it);
1015 context.put("section", section);
1016 context.put("author", author);
1017 context.put("book", book);
1018 context.put("chapter", chapter);
1019 context.put("bib", getBib());
1020 context.put("db", this);
1021 context.put("melati", melati);
1022 if (extras != null)
1023 for (Enumeration<String> keys = extras.keys(); keys.hasMoreElements();) {
1024 String key = keys.nextElement();
1025 context.put(key, extras.get(key));
1026 }
1027 }
1028
1029 public final void setupContext(Melati melati, Context context, Unit it) {
1030 setupContext(melati, context, it, null);
1031 }
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044 public static void notifyNewContentFile(File file) throws IOException {
1045 FileUtils.makeExecutable(file);
1046 }
1047
1048 public String getWMTemplet(String templetName) {
1049 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 interpolateTemplateToStream(template, o, object, null);
1057 }
1058 public void interpolateTemplateToStream(org.webmacro.Template template,
1059 OutputStream o,
1060 Unit object,
1061 Hashtable extras)
1062 throws WebMacroException, IOException {
1063
1064 WebMacro wm = getWebMacro();
1065
1066 MelatiFastWriter fmw =
1067 new MelatiFastWriter(wm.getBroker(), o, getContentEncoding());
1068 Melati m = new Melati(new MelatiConfig(), fmw);
1069 Context context = wm.getContext();
1070 setupContext(m, context, object, extras);
1071 template.write(fmw.getFastWriter(), context);
1072 fmw.getFastWriter().flush();
1073
1074
1075
1076
1077
1078
1079
1080
1081 }
1082
1083 public final void interpolateTemplateToFile(
1084 String templateName,
1085 File to,
1086 Unit object) throws WebMacroException, IOException {
1087 interpolateTemplateToFile(templateName, to, object, null);
1088 }
1089
1090 public void interpolateTemplateToFile(
1091 String templateName,
1092 File to,
1093 Unit object,
1094 Hashtable<String, Object> extras) throws WebMacroException, IOException {
1095 org.webmacro.Template template = getWebMacro().getTemplate(templateName);
1096 OutputStream out = new BufferedOutputStream(new FileOutputStream(to));
1097 try {
1098 interpolateTemplateToStream(template, out, object, extras);
1099 } finally {
1100 try {
1101 out.close();
1102 } catch (Exception e) {
1103 throw new RuntimeException(e);
1104 }
1105 }
1106
1107 notifyNewContentFile(to);
1108 }
1109
1110
1111 public void interpolateAsTemplate(Reader in, OutputStream out, Unit object)
1112 throws WebMacroException, IOException {
1113 interpolateTemplateToStream(
1114 new StreamTemplate(getWebMacro().getBroker(), in), out, object);
1115 }
1116
1117 public void interpolateAsTemplate(File from, OutputStream out, Unit object)
1118 throws WebMacroException, IOException {
1119 Reader in = new BufferedReader(new FileReader(from));
1120 try {
1121 interpolateAsTemplate(in, out, object);
1122 } finally {
1123 try {
1124 in.close();
1125 } catch (Exception e) {
1126 throw new RuntimeException(e);
1127 }
1128 }
1129 }
1130
1131 public void interpolateAsTemplate(File from, File to, Unit object)
1132 throws WebMacroException, IOException {
1133 OutputStream out = new BufferedOutputStream(new FileOutputStream(to));
1134 try {
1135 interpolateAsTemplate(from, out, object);
1136 } finally {
1137 try {
1138 out.close();
1139 } catch (Exception e) {
1140 throw new RuntimeException(e);
1141 }
1142 }
1143 }
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 File file = new File(getContentRootDir(), source);
1161
1162 org.webmacro.Template it =
1163 new FileTemplate(getWebMacro().getBroker(), file, getContentEncoding());
1164 try {
1165 it.parse();
1166 } catch (Exception e) {
1167 throw new TemplateException(file, e);
1168 }
1169
1170 return it;
1171 }
1172
1173 public void writeContentHeader(OutputStream w, Unit object, String template)
1174 throws WebMacroException, IOException {
1175 interpolateTemplateToStream(
1176 template(template == null ? "header.wm" : template),
1177 w,
1178 object);
1179 }
1180
1181 public void writeContentFooter(OutputStream w, Unit object, String template)
1182 throws WebMacroException, IOException {
1183 interpolateTemplateToStream(
1184 template(template == null ? "footer.wm" : template),
1185 w,
1186 object);
1187 }
1188
1189 private org.webmacro.Template footnoteTemplate = null;
1190
1191 public org.webmacro.Template getFootnoteTemplate() {
1192 if (footnoteTemplate == null)
1193 footnoteTemplate = template("footnote.wm");
1194
1195 return footnoteTemplate;
1196 }
1197
1198 public String getPasswordReminderMessage() {
1199 return passwordReminderMessage.getStringCooked();
1200 }
1201
1202 public org.webmacro.Template getPasswordReminderTemplate() {
1203 return new StreamTemplate(
1204 getWebMacro().getBroker(),
1205 new StringReader(getPasswordReminderMessage().trim()));
1206
1207 }
1208
1209 public String getPasswordReminderFrom() {
1210 return passwordReminderFrom.getStringCooked();
1211 }
1212
1213 public String getOrderEmailFrom() {
1214 return orderEmailFrom.getStringCooked();
1215 }
1216
1217 public String getConfirmationEmailFrom() {
1218 return confirmationEmailFrom.getStringCooked();
1219 }
1220
1221 public String getOrderEmailTo() {
1222 return orderEmailTo.getStringCooked();
1223 }
1224
1225 public String getStratusEmailTo() {
1226 return stratusEmailTo.getStringCooked();
1227 }
1228
1229 public String getCachedContentRootDir() {
1230 return getWorkspaceDir() + "/cached";
1231 }
1232
1233 public String getStaticRootURL() {
1234 return staticRootURL.getStringCooked();
1235 }
1236
1237 public String getContentStaticRootURL() {
1238 return contentStaticRootURL.getStringCooked();
1239 }
1240
1241 public String getBannerURLPath() {
1242 return bannerURLPath.getStringCooked();
1243 }
1244
1245 public String getCacheRootURL() {
1246 String it = cacheRootURL.getStringCooked();
1247 return it == null ? "" : it;
1248 }
1249
1250 public String getHomepageURL() {
1251 return homepageURL.getStringCooked();
1252 }
1253
1254 public String getSmtpServer() {
1255 return smtpServer.getStringCooked();
1256 }
1257
1258 public int getDefaultSearchHitsPerText() {
1259 Integer it = defaultSearchHitsPerText.getIntegerCooked();
1260 return it == null ? defaultDefaultSearchHitsPerText : it.intValue();
1261 }
1262
1263 public int getSearchHitsPerPage() {
1264 Integer it = searchHitsPerPage.getIntegerCooked();
1265 return it == null ? defaultSearchHitsPerPage : it.intValue();
1266 }
1267
1268 public String getPaginationTexHeader() {
1269 return paginationTexHeader.getStringCooked();
1270 }
1271
1272 public int getBookStockingsCheckIntervalDays() {
1273 Integer it = bookStockingsCheckIntervalDays.getIntegerCooked();
1274 return it == null ? defaultBookStockingsCheckIntervalDays : it.intValue();
1275 }
1276
1277 public long getBookStockingsCheckIntervalMillis() {
1278 return (long)getBookStockingsCheckIntervalDays() * 1000L * 60L * 60L * 24L;
1279 }
1280
1281 public int getBibBookBookshopSearchTimeoutSeconds() {
1282 Integer it = bibBookBookshopSearchTimeoutSeconds.getIntegerCooked();
1283 return it == null
1284 ? defaultBibBookBookshopSearchTimeoutSeconds
1285 : it.intValue();
1286 }
1287
1288 public long getBibBookBookshopSearchTimeoutMillis() {
1289 return (long)getBibBookBookshopSearchTimeoutSeconds() * 1000L;
1290 }
1291
1292 public int getBookStockingsOutputStartOffset() {
1293 Integer it = bookStockingsOutputStartOffset.getIntegerCooked();
1294 return it == null ? defaultBookStockingsOutputStartOffset : it.intValue();
1295 }
1296
1297 public String getBookStockingsCacheDir() {
1298 return bookStockingsCacheDir.getStringCooked();
1299 }
1300
1301 public int getBookStockingsCacheSizeMax() {
1302 Integer it = bookStockingsCacheSizeMax.getIntegerCooked();
1303 return it == null ? defaultBookStockingsCacheSizeMax : it.intValue();
1304 }
1305
1306 public Integer pageFromAnchor(String anchor) {
1307 if (anchor.startsWith(Pagination.pageAnchorPrefix))
1308 try {
1309 return new Integer(
1310 Integer.parseInt(
1311 anchor.substring(Pagination.pageAnchorPrefix.length()))
1312 + 1);
1313 } catch (NumberFormatException e) {
1314 return null;
1315 } else
1316 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 return (
1342 (BookshopBackendFactory)Class
1343 .forName(
1344 "org.paneris.bibliomania.metasearch." + packageComp + ".Factory")
1345 .newInstance())
1346 .instance(
1347 new File(getWorkspaceDir()),
1348 0);
1349 } catch (Exception e) {
1350 throw new BookshopException(packageComp, e);
1351 }
1352 }
1353
1354 public Bookshop[] bookshops() {
1355 return bookshops;
1356 }
1357
1358 public SectionGroup getReadSectionGroup() {
1359 return readSectionGroup;
1360 }
1361
1362 public Currency getUKCurrency() {
1363 return UKCurrency;
1364 }
1365
1366
1367 public List<ShopOrder> getUKCurrentcyShopOrders() {
1368 return getUKCurrency().getCurrencyShopOrderList();
1369 }
1370
1371 public SectionGroup getStudySectionGroup() {
1372 return studySectionGroup;
1373 }
1374
1375 public SectionGroup getResearchSectionGroup() {
1376 return researchSectionGroup;
1377 }
1378
1379 public SectionGroup getShopSectionGroup() {
1380 return shopSectionGroup;
1381 }
1382
1383 public SectionGroup getSearchSectionGroup() {
1384 return searchSectionGroup;
1385 }
1386
1387 public Group getRegisteredUserGroup() {
1388 return registeredUserGroup;
1389 }
1390
1391 public Capability getRegisteredUserCapability() {
1392 return registeredUserCapability;
1393 }
1394 public Capability getContentModificationCapability() {
1395 return contentModificationCapability;
1396 }
1397 public Capability getContentAdditionCapability() {
1398 return contentAdditionCapability;
1399 }
1400
1401 public User getTemplateRegisterUser() {
1402 return templateRegisterUser;
1403 }
1404
1405 private Bib bib = null;
1406
1407 public Bib getBib() {
1408 if (bib == null)
1409 bib = new Bib(this);
1410 return bib;
1411 }
1412
1413 private int bookshopSearchesRunning = 0;
1414
1415 public void notifyBookshopSearchStart() {
1416 ++bookshopSearchesRunning;
1417 }
1418
1419 public void notifyBookshopSearchStop() {
1420 --bookshopSearchesRunning;
1421 }
1422
1423 public boolean okToRunABookshopSearch() {
1424 Integer maxO = bookStockingsCheckConcurrentMax.getIntegerCooked();
1425 int max =
1426 maxO == null ? defaultBookStockingsCheckConcurrentMax : maxO.intValue();
1427
1428 return bookshopSearchesRunning < max;
1429 }
1430
1431 public boolean getBookStockingsInBackground() {
1432 return bookStockingsInBackgroundAppropriate
1433 && Boolean.TRUE.equals(bookStockingsInBackground.getBooleanCooked());
1434 }
1435
1436 public String getContentEncoding() {
1437 return contentEncoding.getStringCooked();
1438 }
1439
1440 private class BackgroundStockingsChecker extends Thread {
1441
1442 private PreparedStatementFactory booksPS, booksPSNull;
1443
1444 BackgroundStockingsChecker() {
1445 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 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 }
1464
1465 private void doNext() throws Exception {
1466 inSession(AccessToken.root, new PoemTask() {
1467 public void run() {
1468 Book nextToDo;
1469 PreparedStatement ps = null;
1470
1471 try {
1472 if (!getBookStockingsInBackground())
1473 nextToDo = null;
1474 else {
1475 Integer bookTroid = null;
1476
1477 ps = booksPSNull.preparedStatement(PoemThread.transaction());
1478 ResultSet rs = ps.executeQuery();
1479 try {
1480 if (rs.next())
1481 bookTroid = new Integer(rs.getInt(1));
1482 } finally {
1483 rs.close();
1484 }
1485
1486 if (bookTroid == null) {
1487 ps = booksPS.preparedStatement(PoemThread.transaction());
1488 ps.setTimestamp(
1489 1,
1490 new Timestamp(
1491 System.currentTimeMillis()
1492 - getBookStockingsCheckIntervalMillis()));
1493
1494 rs = ps.executeQuery();
1495 try {
1496 if (rs.next())
1497 bookTroid = new Integer(rs.getInt(1));
1498 } finally {
1499 rs.close();
1500 }
1501 }
1502
1503 nextToDo =
1504 bookTroid == null
1505 ? null
1506 : (Book)getBookTable().getObject(bookTroid);
1507 }
1508 } catch (Exception e) {
1509 System.err.println("BackgroundStockingsChecker: " + e);
1510 nextToDo = null;
1511 }
1512
1513 if (nextToDo != null)
1514 getStockingsSearchTable().searchFor(nextToDo).runNewSearch();
1515 }
1516 });
1517 }
1518
1519 public void run() {
1520 for (;;) {
1521 try {
1522 Thread.sleep(120000);
1523 doNext();
1524 } catch (Exception e) {
1525 System.err.println("Background stockings checker: " + e);
1526 }
1527 }
1528 }
1529 }
1530
1531 public Author getShakespeare() {
1532 return shakespeare;
1533 }
1534
1535 public Section getDrama() {
1536 return drama;
1537 }
1538
1539 public Book getMacbeth() {
1540 return macbeth;
1541 }
1542
1543 public org.paneris.melati.boards.model.UserTable<org.paneris.melati.boards.model.User> getBoardsUserTable() {
1544 return (org.paneris.melati.boards.model.UserTable<org.paneris.melati.boards.model.User>)getBoardsUserTable();
1545 }
1546
1547
1548
1549
1550
1551 public static String toCamelCase(String value) {
1552 return toCamelCase(value, true);
1553 }
1554 public static String toCamelCase(String value, boolean lowercaseFirstLetter) {
1555 StringBuilder sb = new StringBuilder();
1556
1557 final char delimiter = ' ';
1558 boolean lower = lowercaseFirstLetter;
1559 for (int i = 0; i < value.length(); ++i) {
1560 final char valueChar = value.charAt(i);
1561 if (valueChar == delimiter) {
1562 lower = false;
1563 } else if (lower) {
1564 sb.append(Character.toLowerCase(valueChar));
1565 } else {
1566 sb.append(Character.toUpperCase(valueChar));
1567 lower = true;
1568 }
1569 }
1570
1571 return sb.toString();
1572 }
1573 }
1574
1575