Source Code Cross Referenced for BaseDigestService.java in  » ERP-CRM-Financial » sakai » org » sakaiproject » email » impl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » sakai » org.sakaiproject.email.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**********************************************************************************
0002:         * $URL: https://source.sakaiproject.org/svn/email/tags/sakai_2-4-1/email-impl/impl/src/java/org/sakaiproject/email/impl/BaseDigestService.java $
0003:         * $Id: BaseDigestService.java 7516 2006-04-09 13:01:18Z ggolden@umich.edu $
0004:         ***********************************************************************************
0005:         *
0006:         * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007:         * 
0008:         * Licensed under the Educational Community License, Version 1.0 (the "License"); 
0009:         * you may not use this file except in compliance with the License. 
0010:         * You may obtain a copy of the License at
0011:         * 
0012:         *      http://www.opensource.org/licenses/ecl1.php
0013:         * 
0014:         * Unless required by applicable law or agreed to in writing, software 
0015:         * distributed under the License is distributed on an "AS IS" BASIS, 
0016:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
0017:         * See the License for the specific language governing permissions and 
0018:         * limitations under the License.
0019:         *
0020:         **********************************************************************************/package org.sakaiproject.email.impl;
0021:
0022:        import java.util.Hashtable;
0023:        import java.util.Iterator;
0024:        import java.util.List;
0025:        import java.util.Map;
0026:        import java.util.Stack;
0027:        import java.util.Vector;
0028:
0029:        import org.apache.commons.logging.Log;
0030:        import org.apache.commons.logging.LogFactory;
0031:        import org.sakaiproject.authz.api.SecurityService;
0032:        import org.sakaiproject.component.api.ServerConfigurationService;
0033:        import org.sakaiproject.component.cover.ComponentManager;
0034:        import org.sakaiproject.email.api.Digest;
0035:        import org.sakaiproject.email.api.DigestEdit;
0036:        import org.sakaiproject.email.api.DigestMessage;
0037:        import org.sakaiproject.email.api.DigestService;
0038:        import org.sakaiproject.email.api.EmailService;
0039:        import org.sakaiproject.entity.api.Edit;
0040:        import org.sakaiproject.entity.api.Entity;
0041:        import org.sakaiproject.entity.api.ResourceProperties;
0042:        import org.sakaiproject.entity.api.ResourcePropertiesEdit;
0043:        import org.sakaiproject.event.api.EventTrackingService;
0044:        import org.sakaiproject.exception.IdUnusedException;
0045:        import org.sakaiproject.exception.IdUsedException;
0046:        import org.sakaiproject.exception.InUseException;
0047:        import org.sakaiproject.exception.PermissionException;
0048:        import org.sakaiproject.time.api.Time;
0049:        import org.sakaiproject.time.api.TimeBreakdown;
0050:        import org.sakaiproject.time.api.TimeRange;
0051:        import org.sakaiproject.time.api.TimeService;
0052:        import org.sakaiproject.user.api.UserDirectoryService;
0053:        import org.sakaiproject.util.BaseResourcePropertiesEdit;
0054:        import org.sakaiproject.util.ResourceLoader;
0055:        import org.sakaiproject.util.StorageUser;
0056:        import org.sakaiproject.util.Xml;
0057:        import org.sakaiproject.tool.api.SessionBindingEvent;
0058:        import org.sakaiproject.tool.api.SessionBindingListener;
0059:        import org.sakaiproject.tool.api.SessionManager;
0060:        import org.w3c.dom.Document;
0061:        import org.w3c.dom.Element;
0062:        import org.w3c.dom.Node;
0063:        import org.w3c.dom.NodeList;
0064:
0065:        /**
0066:         * <p>
0067:         * BaseDigestService is the base service for DigestService.
0068:         * </p>
0069:         */
0070:        public abstract class BaseDigestService implements  DigestService,
0071:                StorageUser, Runnable {
0072:            /** Our logger. */
0073:            private static Log M_log = LogFactory
0074:                    .getLog(BasicEmailService.class);
0075:
0076:            private ResourceLoader rb = new ResourceLoader("email-impl");
0077:
0078:            /** Storage manager for this service. */
0079:            protected Storage m_storage = null;
0080:
0081:            /** The initial portion of a relative access point URL. */
0082:            protected String m_relativeAccessPoint = null;
0083:
0084:            /** The queue of digests waiting to be added (DigestMessage). */
0085:            protected List m_digestQueue = new Vector();
0086:
0087:            /** The thread I run my periodic clean and report on. */
0088:            protected Thread m_thread = null;
0089:
0090:            /** My thread's quit flag. */
0091:            protected boolean m_threadStop = false;
0092:
0093:            /** How long to wait between runnable runs (ms). */
0094:            protected static final long PERIOD = 1000;
0095:
0096:            /** True if we are in the mode of sending out digests, false if we are waiting. */
0097:            protected boolean m_sendDigests = true;
0098:
0099:            /** The time period last time the sendDigests() was called. */
0100:            protected String m_lastSendPeriod = null;
0101:
0102:            /**********************************************************************************************************************************************************************************************************************************************************
0103:             * Runnable
0104:             *********************************************************************************************************************************************************************************************************************************************************/
0105:
0106:            /**
0107:             * Start the clean and report thread.
0108:             */
0109:            protected void start() {
0110:                m_threadStop = false;
0111:
0112:                m_thread = new Thread(this , getClass().getName());
0113:                m_thread.start();
0114:            }
0115:
0116:            /**
0117:             * Stop the clean and report thread.
0118:             */
0119:            protected void stop() {
0120:                if (m_thread == null)
0121:                    return;
0122:
0123:                // signal the thread to stop
0124:                m_threadStop = true;
0125:
0126:                // wake up the thread
0127:                m_thread.interrupt();
0128:
0129:                m_thread = null;
0130:            }
0131:
0132:            /**
0133:             * Run the clean and report thread.
0134:             */
0135:            public void run() {
0136:                // since we might be running while the component manager is still being created and populated, such as at server
0137:                // startup, wait here for a complete component manager
0138:                ComponentManager.waitTillConfigured();
0139:
0140:                // loop till told to stop
0141:                while ((!m_threadStop)
0142:                        && (!Thread.currentThread().isInterrupted())) {
0143:                    try {
0144:                        // process the queue of digest requests
0145:                        processQueue();
0146:
0147:                        // check for a digest mailing time
0148:                        sendDigests();
0149:                    } catch (Throwable e) {
0150:                        M_log.warn(": exception: ", e);
0151:                    }
0152:
0153:                    // take a small nap
0154:                    try {
0155:                        Thread.sleep(PERIOD);
0156:                    } catch (Throwable ignore) {
0157:                    }
0158:                }
0159:            }
0160:
0161:            /**
0162:             * Attempt to process all the queued digest requests. Ones that cannot be processed now will be returned to the queue.
0163:             */
0164:            protected void processQueue() {
0165:                // setup a re-try queue
0166:                List retry = new Vector();
0167:
0168:                // grab the queue - any new stuff will be processed next time
0169:                List queue = new Vector();
0170:                synchronized (m_digestQueue) {
0171:                    queue.addAll(m_digestQueue);
0172:                    m_digestQueue.clear();
0173:                }
0174:
0175:                for (Iterator iQueue = queue.iterator(); iQueue.hasNext();) {
0176:                    DigestMessage message = (DigestMessage) iQueue.next();
0177:                    try {
0178:                        DigestEdit edit = edit(message.getTo());
0179:                        edit.add(message);
0180:                        commit(edit);
0181:                        // %%% could do this by pulling all for id from the queue in one commit -ggolden
0182:                    } catch (InUseException e) {
0183:                        // retry next time
0184:                        retry.add(message);
0185:                    }
0186:                }
0187:
0188:                // requeue the retrys
0189:                if (retry.size() > 0) {
0190:                    synchronized (m_digestQueue) {
0191:                        m_digestQueue.addAll(retry);
0192:                    }
0193:                }
0194:            }
0195:
0196:            /**
0197:             * If it's time, send out any digested messages. Send once daily, after a certiain time of day (local time).
0198:             */
0199:            protected void sendDigests() {
0200:                // compute the current period
0201:                String curPeriod = computeRange(timeService().newTime())
0202:                        .toString();
0203:
0204:                // if we are in a new period, start sending again
0205:                if (!curPeriod.equals(m_lastSendPeriod)) {
0206:                    m_sendDigests = true;
0207:
0208:                    // remember this period for next check
0209:                    m_lastSendPeriod = curPeriod;
0210:                }
0211:
0212:                // if we are not sending, early out
0213:                if (!m_sendDigests)
0214:                    return;
0215:
0216:                if (M_log.isDebugEnabled())
0217:                    M_log.debug("checking for sending digests");
0218:
0219:                // count send candidate digests
0220:                int count = 0;
0221:
0222:                // process each digest
0223:                List digests = getDigests();
0224:                for (Iterator iDigests = digests.iterator(); iDigests.hasNext();) {
0225:                    Digest digest = (Digest) iDigests.next();
0226:
0227:                    // see if this one has any prior periods
0228:                    List periods = digest.getPeriods();
0229:                    if (periods.size() == 0)
0230:                        continue;
0231:
0232:                    boolean found = false;
0233:                    for (Iterator iPeriods = periods.iterator(); iPeriods
0234:                            .hasNext();) {
0235:                        String period = (String) iPeriods.next();
0236:                        if (!curPeriod.equals(period)) {
0237:                            found = true;
0238:                            break;
0239:                        }
0240:                    }
0241:                    if (!found)
0242:                        continue;
0243:
0244:                    // this digest is a send candidate
0245:                    count++;
0246:
0247:                    // get a lock
0248:                    DigestEdit edit = null;
0249:                    try {
0250:                        boolean changed = false;
0251:                        edit = edit(digest.getId());
0252:
0253:                        // process each non-current period
0254:                        for (Iterator iPeriods = edit.getPeriods().iterator(); iPeriods
0255:                                .hasNext();) {
0256:                            String period = (String) iPeriods.next();
0257:
0258:                            // process if it's not the current period
0259:                            if (!curPeriod.equals(period)) {
0260:                                TimeRange periodRange = timeService()
0261:                                        .newTimeRange(period);
0262:                                Time timeInPeriod = periodRange.firstTime();
0263:
0264:                                // any messages?
0265:                                List msgs = edit.getMessages(timeInPeriod);
0266:                                if (msgs.size() > 0) {
0267:                                    // send this one
0268:                                    send(edit.getId(), msgs, periodRange);
0269:                                }
0270:
0271:                                // clear this period
0272:                                edit.clear(timeInPeriod);
0273:
0274:                                changed = true;
0275:                            }
0276:                        }
0277:
0278:                        // commit, release the lock
0279:                        if (changed) {
0280:                            // delete it if empty
0281:                            if (edit.getPeriods().size() == 0) {
0282:                                remove(edit);
0283:                            } else {
0284:                                commit(edit);
0285:                            }
0286:                            edit = null;
0287:                        } else {
0288:                            cancel(edit);
0289:                            edit = null;
0290:                        }
0291:                    }
0292:                    // if in use, missing, whatever, skip on
0293:                    catch (Throwable any) {
0294:                    } finally {
0295:                        if (edit != null) {
0296:                            cancel(edit);
0297:                            edit = null;
0298:                        }
0299:                    }
0300:
0301:                } // for (Iterator iDigests = digests.iterator(); iDigests.hasNext();)
0302:
0303:                // if we didn't see any send candidates, we will stop sending till next period
0304:                if (count == 0) {
0305:                    m_sendDigests = false;
0306:                }
0307:            }
0308:
0309:            /**
0310:             * Send a single digest message
0311:             * 
0312:             * @param id
0313:             *        The use id to send the message to.
0314:             * @param msgs
0315:             *        The List (DigestMessage) of message to digest.
0316:             * @param period
0317:             *        The time period of the digested messages.
0318:             */
0319:            protected void send(String id, List msgs, TimeRange period) {
0320:                // sanity check
0321:                if (msgs.size() == 0)
0322:                    return;
0323:
0324:                try {
0325:                    String to = userDirectoryService().getUser(id).getEmail();
0326:
0327:                    // if use has no email address we can't send it
0328:                    if ((to == null) || (to.length() == 0))
0329:                        return;
0330:
0331:                    String from = "postmaster@"
0332:                            + serverConfigurationService().getServerName();
0333:                    String subject = serverConfigurationService().getString(
0334:                            "ui.service", "Sakai")
0335:                            + " "
0336:                            + rb.getString("notif")
0337:                            + " "
0338:                            + period.firstTime().toStringLocalDate();
0339:
0340:                    StringBuffer body = new StringBuffer();
0341:                    body.append(subject);
0342:                    body.append("\n\n");
0343:
0344:                    // toc
0345:                    int count = 1;
0346:                    for (Iterator iMsgs = msgs.iterator(); iMsgs.hasNext();) {
0347:                        DigestMessage msg = (DigestMessage) iMsgs.next();
0348:
0349:                        body.append(Integer.toString(count));
0350:                        body.append(".  ");
0351:                        body.append(msg.getSubject());
0352:                        body.append("\n");
0353:                        count++;
0354:                    }
0355:                    body.append("\n----------------------\n\n");
0356:
0357:                    // for each msg
0358:                    count = 1;
0359:                    for (Iterator iMsgs = msgs.iterator(); iMsgs.hasNext();) {
0360:                        DigestMessage msg = (DigestMessage) iMsgs.next();
0361:
0362:                        // repeate toc entry
0363:                        body.append(Integer.toString(count));
0364:                        body.append(".  ");
0365:                        body.append(msg.getSubject());
0366:                        body.append("\n\n");
0367:
0368:                        // message body
0369:                        body.append(msg.getBody());
0370:
0371:                        body.append("\n----------------------\n\n");
0372:                        count++;
0373:                    }
0374:
0375:                    // tag
0376:                    body.append(rb.getString("thiaut")
0377:                            + " "
0378:                            + serverConfigurationService().getString(
0379:                                    "ui.service", "Sakai") + " " + "("
0380:                            + serverConfigurationService().getServerUrl() + ")"
0381:                            + "\n" + rb.getString("youcan") + "\n");
0382:
0383:                    if (M_log.isDebugEnabled())
0384:                        M_log.debug(this  + " sending digest email to: " + to);
0385:
0386:                    emailService().send(from, to, subject, body.toString(), to,
0387:                            null, null);
0388:                } catch (Throwable any) {
0389:                    M_log.warn(".send: digest to: " + id + " not sent: "
0390:                            + any.toString());
0391:                }
0392:            }
0393:
0394:            /**********************************************************************************************************************************************************************************************************************************************************
0395:             * Abstractions, etc.
0396:             *********************************************************************************************************************************************************************************************************************************************************/
0397:
0398:            /**
0399:             * Construct storage for this service.
0400:             */
0401:            protected abstract Storage newStorage();
0402:
0403:            /**
0404:             * Access the partial URL that forms the root of resource URLs.
0405:             * 
0406:             * @param relative
0407:             *        if true, form within the access path only (i.e. starting with /content)
0408:             * @return the partial URL that forms the root of resource URLs.
0409:             */
0410:            protected String getAccessPoint(boolean relative) {
0411:                return (relative ? "" : serverConfigurationService()
0412:                        .getAccessUrl())
0413:                        + m_relativeAccessPoint;
0414:            }
0415:
0416:            /**
0417:             * Access the internal reference which can be used to access the resource from within the system.
0418:             * 
0419:             * @param id
0420:             *        The digest id string.
0421:             * @return The the internal reference which can be used to access the resource from within the system.
0422:             */
0423:            public String digestReference(String id) {
0424:                return getAccessPoint(true) + Entity.SEPARATOR + id;
0425:            }
0426:
0427:            /**
0428:             * Access the digest id extracted from a digest reference.
0429:             * 
0430:             * @param ref
0431:             *        The digest reference string.
0432:             * @return The the digest id extracted from a digest reference.
0433:             */
0434:            protected String digestId(String ref) {
0435:                String start = getAccessPoint(true) + Entity.SEPARATOR;
0436:                int i = ref.indexOf(start);
0437:                if (i == -1)
0438:                    return ref;
0439:                String id = ref.substring(i + start.length());
0440:                return id;
0441:            }
0442:
0443:            /**
0444:             * Check security permission.
0445:             * 
0446:             * @param lock
0447:             *        The lock id string.
0448:             * @param resource
0449:             *        The resource reference string, or null if no resource is involved.
0450:             * @return true if allowd, false if not
0451:             */
0452:            protected boolean unlockCheck(String lock, String resource) {
0453:                if (!securityService().unlock(lock, resource)) {
0454:                    return false;
0455:                }
0456:
0457:                return true;
0458:            }
0459:
0460:            /**
0461:             * Check security permission.
0462:             * 
0463:             * @param lock
0464:             *        The lock id string.
0465:             * @param resource
0466:             *        The resource reference string, or null if no resource is involved.
0467:             * @exception PermissionException
0468:             *            Thrown if the user does not have access
0469:             */
0470:            protected void unlock(String lock, String resource)
0471:                    throws PermissionException {
0472:                if (!unlockCheck(lock, resource)) {
0473:                    throw new PermissionException(sessionManager()
0474:                            .getCurrentSessionUserId(), lock, resource);
0475:                }
0476:            }
0477:
0478:            /**********************************************************************************************************************************************************************************************************************************************************
0479:             * Dependencies
0480:             *********************************************************************************************************************************************************************************************************************************************************/
0481:
0482:            /**
0483:             * @return the TimeService collaborator.
0484:             */
0485:            protected abstract TimeService timeService();
0486:
0487:            /**
0488:             * @return the ServerConfigurationService collaborator.
0489:             */
0490:            protected abstract ServerConfigurationService serverConfigurationService();
0491:
0492:            /**
0493:             * @return the EmailService collaborator.
0494:             */
0495:            protected abstract EmailService emailService();
0496:
0497:            /**
0498:             * @return the EventTrackingService collaborator.
0499:             */
0500:            protected abstract EventTrackingService eventTrackingService();
0501:
0502:            /**
0503:             * @return the MemoryServiSecurityServicece collaborator.
0504:             */
0505:            protected abstract SecurityService securityService();
0506:
0507:            /**
0508:             * @return the UserDirectoryService collaborator.
0509:             */
0510:            protected abstract UserDirectoryService userDirectoryService();
0511:
0512:            /**
0513:             * @return the SessionManager collaborator.
0514:             */
0515:            protected abstract SessionManager sessionManager();
0516:
0517:            /**********************************************************************************************************************************************************************************************************************************************************
0518:             * Init and Destroy
0519:             *********************************************************************************************************************************************************************************************************************************************************/
0520:
0521:            /**
0522:             * Final initialization, once all dependencies are set.
0523:             */
0524:            public void init() {
0525:                m_relativeAccessPoint = REFERENCE_ROOT;
0526:
0527:                // construct storage and read
0528:                m_storage = newStorage();
0529:                m_storage.open();
0530:
0531:                // setup the queue
0532:                m_digestQueue.clear();
0533:
0534:                start();
0535:
0536:                M_log.info("init()");
0537:            }
0538:
0539:            /**
0540:             * Returns to uninitialized state.
0541:             */
0542:            public void destroy() {
0543:                stop();
0544:
0545:                m_storage.close();
0546:                m_storage = null;
0547:
0548:                if (m_digestQueue.size() > 0) {
0549:                    M_log.warn(".shutdown: with items in digest queue"); // %%%
0550:                }
0551:                m_digestQueue.clear();
0552:
0553:                M_log.info("destroy()");
0554:            }
0555:
0556:            /**********************************************************************************************************************************************************************************************************************************************************
0557:             * DigestService implementation
0558:             *********************************************************************************************************************************************************************************************************************************************************/
0559:
0560:            /**
0561:             * @inheritDoc
0562:             */
0563:            public Digest getDigest(String id) throws IdUnusedException {
0564:                Digest digest = findDigest(id);
0565:                if (digest == null)
0566:                    throw new IdUnusedException(id);
0567:
0568:                return digest;
0569:            }
0570:
0571:            /**
0572:             * @inheritDoc
0573:             */
0574:            public List getDigests() {
0575:                List digests = m_storage.getAll();
0576:
0577:                return digests;
0578:            }
0579:
0580:            /**
0581:             * @inheritDoc
0582:             */
0583:            public void digest(String to, String subject, String body) {
0584:                DigestMessage message = new org.sakaiproject.email.impl.DigestMessage(
0585:                        to, subject, body);
0586:
0587:                // queue this for digesting
0588:                synchronized (m_digestQueue) {
0589:                    m_digestQueue.add(message);
0590:                }
0591:            }
0592:
0593:            /**
0594:             * @inheritDoc
0595:             */
0596:            public DigestEdit edit(String id) throws InUseException {
0597:                // security
0598:                // unlock(SECURE_EDIT_DIGEST, digestReference(id));
0599:
0600:                // one add/edit at a time, please, to make sync. only one digest per user
0601:                // TODO: I don't link sync... could just do the add and let it fail if it already exists -ggolden
0602:                synchronized (m_storage) {
0603:                    // check for existance
0604:                    if (!m_storage.check(id)) {
0605:                        try {
0606:                            return add(id);
0607:                        } catch (IdUsedException e) {
0608:                            M_log.warn(".edit: from the add: " + e);
0609:                        }
0610:                    }
0611:
0612:                    // ignore the cache - get the user with a lock from the info store
0613:                    DigestEdit edit = m_storage.edit(id);
0614:                    if (edit == null)
0615:                        throw new InUseException(id);
0616:
0617:                    ((BaseDigest) edit).setEvent(SECURE_EDIT_DIGEST);
0618:
0619:                    return edit;
0620:                }
0621:            }
0622:
0623:            /**
0624:             * @inheritDoc
0625:             */
0626:            public void commit(DigestEdit edit) {
0627:                // check for closed edit
0628:                if (!edit.isActiveEdit()) {
0629:                    try {
0630:                        throw new Exception();
0631:                    } catch (Exception e) {
0632:                        M_log.warn(".commit(): closed DigestEdit", e);
0633:                    }
0634:                    return;
0635:                }
0636:
0637:                // update the properties
0638:                // addLiveUpdateProperties(user.getPropertiesEdit());
0639:
0640:                // complete the edit
0641:                m_storage.commit(edit);
0642:
0643:                // track it
0644:                eventTrackingService().post(
0645:                        eventTrackingService().newEvent(
0646:                                ((BaseDigest) edit).getEvent(),
0647:                                edit.getReference(), true));
0648:
0649:                // close the edit object
0650:                ((BaseDigest) edit).closeEdit();
0651:            }
0652:
0653:            /**
0654:             * @inheritDoc
0655:             */
0656:            public void cancel(DigestEdit edit) {
0657:                // check for closed edit
0658:                if (!edit.isActiveEdit()) {
0659:                    try {
0660:                        throw new Exception();
0661:                    } catch (Exception e) {
0662:                        M_log.warn(".cancel(): closed DigestEdit", e);
0663:                    }
0664:                    return;
0665:                }
0666:
0667:                // release the edit lock
0668:                m_storage.cancel(edit);
0669:
0670:                // close the edit object
0671:                ((BaseDigest) edit).closeEdit();
0672:            }
0673:
0674:            /**
0675:             * @inheritDoc
0676:             */
0677:            public void remove(DigestEdit edit) {
0678:                // check for closed edit
0679:                if (!edit.isActiveEdit()) {
0680:                    try {
0681:                        throw new Exception();
0682:                    } catch (Exception e) {
0683:                        M_log.warn(".remove(): closed DigestEdit", e);
0684:                    }
0685:                    return;
0686:                }
0687:
0688:                // complete the edit
0689:                m_storage.remove(edit);
0690:
0691:                // track it
0692:                eventTrackingService().post(
0693:                        eventTrackingService().newEvent(SECURE_REMOVE_DIGEST,
0694:                                edit.getReference(), true));
0695:
0696:                // close the edit object
0697:                ((BaseDigest) edit).closeEdit();
0698:            }
0699:
0700:            /**
0701:             * @inheritDoc
0702:             */
0703:            protected BaseDigest findDigest(String id) {
0704:                BaseDigest digest = (BaseDigest) m_storage.get(id);
0705:
0706:                return digest;
0707:            }
0708:
0709:            /**
0710:             * @inheritDoc
0711:             */
0712:            public DigestEdit add(String id) throws IdUsedException {
0713:                // check security (throws if not permitted)
0714:                // unlock(SECURE_ADD_DIGEST, digestReference(id));
0715:
0716:                // one add/edit at a time, please, to make sync. only one digest per user
0717:                synchronized (m_storage) {
0718:                    // reserve a user with this id from the info store - if it's in use, this will return null
0719:                    DigestEdit edit = m_storage.put(id);
0720:                    if (edit == null) {
0721:                        throw new IdUsedException(id);
0722:                    }
0723:
0724:                    return edit;
0725:                }
0726:            }
0727:
0728:            /**********************************************************************************************************************************************************************************************************************************************************
0729:             * Digest implementation
0730:             *********************************************************************************************************************************************************************************************************************************************************/
0731:
0732:            public class BaseDigest implements  DigestEdit,
0733:                    SessionBindingListener {
0734:                /** The user id. */
0735:                protected String m_id = null;
0736:
0737:                /** The properties. */
0738:                protected ResourcePropertiesEdit m_properties = null;
0739:
0740:                /** The digest time ranges (Map TimeRange string to List of DigestMessage). */
0741:                protected Map m_ranges = null;
0742:
0743:                /**
0744:                 * Construct.
0745:                 * 
0746:                 * @param id
0747:                 *        The user id.
0748:                 */
0749:                public BaseDigest(String id) {
0750:                    m_id = id;
0751:
0752:                    // setup for properties
0753:                    ResourcePropertiesEdit props = new BaseResourcePropertiesEdit();
0754:                    m_properties = props;
0755:
0756:                    // setup for ranges
0757:                    m_ranges = new Hashtable();
0758:
0759:                    // if the id is not null (a new user, rather than a reconstruction)
0760:                    // and not the anon (id == "") user,
0761:                    // add the automatic (live) properties
0762:                    // %%% if ((m_id != null) && (m_id.length() > 0)) addLiveProperties(props);
0763:                }
0764:
0765:                /**
0766:                 * Construct from another Digest object.
0767:                 * 
0768:                 * @param user
0769:                 *        The user object to use for values.
0770:                 */
0771:                public BaseDigest(Digest digest) {
0772:                    setAll(digest);
0773:                }
0774:
0775:                /**
0776:                 * Construct from information in XML.
0777:                 * 
0778:                 * @param el
0779:                 *        The XML DOM Element definining the user.
0780:                 */
0781:                public BaseDigest(Element el) {
0782:                    // setup for properties
0783:                    m_properties = new BaseResourcePropertiesEdit();
0784:
0785:                    // setup for ranges
0786:                    m_ranges = new Hashtable();
0787:
0788:                    m_id = el.getAttribute("id");
0789:
0790:                    // the children (properties, messages)
0791:                    NodeList children = el.getChildNodes();
0792:                    final int length = children.getLength();
0793:                    for (int i = 0; i < length; i++) {
0794:                        Node child = children.item(i);
0795:                        if (child.getNodeType() != Node.ELEMENT_NODE)
0796:                            continue;
0797:                        Element element = (Element) child;
0798:
0799:                        // look for properties
0800:                        if (element.getTagName().equals("properties")) {
0801:                            // re-create properties
0802:                            m_properties = new BaseResourcePropertiesEdit(
0803:                                    element);
0804:                        }
0805:
0806:                        // look for a messages
0807:                        else if (element.getTagName().equals("messages")) {
0808:                            String period = element.getAttribute("period");
0809:
0810:                            // find the range
0811:                            List msgs = (List) m_ranges.get(period);
0812:                            if (msgs == null) {
0813:                                msgs = new Vector();
0814:                                m_ranges.put(period, msgs);
0815:                            }
0816:
0817:                            // do these children for messages
0818:                            NodeList msgChildren = element.getChildNodes();
0819:                            final int msgChildrenLen = msgChildren.getLength();
0820:                            for (int m = 0; m < msgChildrenLen; m++) {
0821:                                Node msgChild = msgChildren.item(m);
0822:                                if (msgChild.getNodeType() != Node.ELEMENT_NODE)
0823:                                    continue;
0824:                                Element msgChildEl = (Element) msgChild;
0825:
0826:                                if (msgChildEl.getTagName().equals("message")) {
0827:                                    String subject = Xml.decodeAttribute(
0828:                                            msgChildEl, "subject");
0829:                                    String body = Xml.decodeAttribute(
0830:                                            msgChildEl, "body");
0831:                                    msgs
0832:                                            .add(new org.sakaiproject.email.impl.DigestMessage(
0833:                                                    m_id, subject, body));
0834:                                }
0835:                            }
0836:                        }
0837:                    }
0838:                }
0839:
0840:                /**
0841:                 * Take all values from this object.
0842:                 * 
0843:                 * @param user
0844:                 *        The user object to take values from.
0845:                 */
0846:                protected void setAll(Digest digest) {
0847:                    m_id = digest.getId();
0848:
0849:                    m_properties = new BaseResourcePropertiesEdit();
0850:                    m_properties.addAll(digest.getProperties());
0851:
0852:                    m_ranges = new Hashtable();
0853:                    // %%% deep enough? -ggolden
0854:                    m_ranges.putAll(((BaseDigest) digest).m_ranges);
0855:                }
0856:
0857:                /**
0858:                 * @inheritDoc
0859:                 */
0860:                public Element toXml(Document doc, Stack stack) {
0861:                    Element digest = doc.createElement("digest");
0862:
0863:                    if (stack.isEmpty()) {
0864:                        doc.appendChild(digest);
0865:                    } else {
0866:                        ((Element) stack.peek()).appendChild(digest);
0867:                    }
0868:
0869:                    stack.push(digest);
0870:
0871:                    digest.setAttribute("id", getId());
0872:
0873:                    // properties
0874:                    m_properties.toXml(doc, stack);
0875:
0876:                    // for each message range
0877:                    for (Iterator it = m_ranges.entrySet().iterator(); it
0878:                            .hasNext();) {
0879:                        Map.Entry entry = (Map.Entry) it.next();
0880:
0881:                        Element messages = doc.createElement("messages");
0882:                        digest.appendChild(messages);
0883:                        messages
0884:                                .setAttribute("period", (String) entry.getKey());
0885:
0886:                        // for each message
0887:                        for (Iterator iMsgs = ((List) entry.getValue())
0888:                                .iterator(); iMsgs.hasNext();) {
0889:                            DigestMessage msg = (DigestMessage) iMsgs.next();
0890:
0891:                            Element message = doc.createElement("message");
0892:                            messages.appendChild(message);
0893:                            Xml.encodeAttribute(message, "subject", msg
0894:                                    .getSubject());
0895:                            Xml.encodeAttribute(message, "body", msg.getBody());
0896:                        }
0897:                    }
0898:
0899:                    stack.pop();
0900:
0901:                    return digest;
0902:                }
0903:
0904:                /**
0905:                 * @inheritDoc
0906:                 */
0907:                public String getId() {
0908:                    if (m_id == null)
0909:                        return "";
0910:                    return m_id;
0911:                }
0912:
0913:                /**
0914:                 * @inheritDoc
0915:                 */
0916:                public String getUrl() {
0917:                    return getAccessPoint(false) + m_id;
0918:                }
0919:
0920:                /**
0921:                 * @inheritDoc
0922:                 */
0923:                public String getReference() {
0924:                    return digestReference(m_id);
0925:                }
0926:
0927:                /**
0928:                 * @inheritDoc
0929:                 */
0930:                public String getReference(String rootProperty) {
0931:                    return getReference();
0932:                }
0933:
0934:                /**
0935:                 * @inheritDoc
0936:                 */
0937:                public String getUrl(String rootProperty) {
0938:                    return getUrl();
0939:                }
0940:
0941:                /**
0942:                 * @inheritDoc
0943:                 */
0944:                public ResourceProperties getProperties() {
0945:                    return m_properties;
0946:                }
0947:
0948:                /**
0949:                 * @inheritDoc
0950:                 */
0951:                public List getMessages(Time period) {
0952:                    synchronized (m_ranges) {
0953:                        // find the range
0954:                        String range = computeRange(period).toString();
0955:                        List msgs = (List) m_ranges.get(range);
0956:
0957:                        List rv = new Vector();
0958:                        if (msgs != null) {
0959:                            rv.addAll(msgs);
0960:                        }
0961:
0962:                        return rv;
0963:                    }
0964:                }
0965:
0966:                /**
0967:                 * @inheritDoc
0968:                 */
0969:                public List getPeriods() {
0970:                    synchronized (m_ranges) {
0971:                        List rv = new Vector();
0972:                        rv.addAll(m_ranges.keySet());
0973:
0974:                        return rv;
0975:                    }
0976:                }
0977:
0978:                /**
0979:                 * @inheritDoc
0980:                 */
0981:                public boolean equals(Object obj) {
0982:                    if (!(obj instanceof  Digest))
0983:                        return false;
0984:                    return ((Digest) obj).getId().equals(getId());
0985:                }
0986:
0987:                /**
0988:                 * @inheritDoc
0989:                 */
0990:                public int hashCode() {
0991:                    return getId().hashCode();
0992:                }
0993:
0994:                /**
0995:                 * @inheritDoc
0996:                 */
0997:                public int compareTo(Object obj) {
0998:                    if (!(obj instanceof  Digest))
0999:                        throw new ClassCastException();
1000:
1001:                    // if the object are the same, say so
1002:                    if (obj == this )
1003:                        return 0;
1004:
1005:                    // sort based on (unique) id
1006:                    int compare = getId().compareTo(((Digest) obj).getId());
1007:
1008:                    return compare;
1009:                }
1010:
1011:                /******************************************************************************************************************************************************************************************************************************************************
1012:                 * Edit implementation
1013:                 *****************************************************************************************************************************************************************************************************************************************************/
1014:
1015:                /** The event code for this edit. */
1016:                protected String m_event = null;
1017:
1018:                /** Active flag. */
1019:                protected boolean m_active = false;
1020:
1021:                /**
1022:                 * @inheritDoc
1023:                 */
1024:                public void add(DigestMessage msg) {
1025:                    synchronized (m_ranges) {
1026:                        // find the current range
1027:                        String range = computeRange(timeService().newTime())
1028:                                .toString();
1029:                        List msgs = (List) m_ranges.get(range);
1030:                        if (msgs == null) {
1031:                            msgs = new Vector();
1032:                            m_ranges.put(range, msgs);
1033:                        }
1034:                        msgs.add(msg);
1035:                    }
1036:                }
1037:
1038:                /**
1039:                 * @inheritDoc
1040:                 */
1041:                public void add(String to, String subject, String body) {
1042:                    DigestMessage msg = new org.sakaiproject.email.impl.DigestMessage(
1043:                            to, subject, body);
1044:
1045:                    synchronized (m_ranges) {
1046:                        // find the current range
1047:                        String range = computeRange(timeService().newTime())
1048:                                .toString();
1049:                        List msgs = (List) m_ranges.get(range);
1050:                        if (msgs == null) {
1051:                            msgs = new Vector();
1052:                            m_ranges.put(range, msgs);
1053:                        }
1054:                        msgs.add(msg);
1055:                    }
1056:                }
1057:
1058:                /**
1059:                 * @inheritDoc
1060:                 */
1061:                public void clear(Time period) {
1062:                    synchronized (m_ranges) {
1063:                        // find the range
1064:                        String range = computeRange(period).toString();
1065:                        List msgs = (List) m_ranges.get(range);
1066:                        if (msgs != null) {
1067:                            m_ranges.remove(range);
1068:                        }
1069:                    }
1070:                }
1071:
1072:                /**
1073:                 * Clean up.
1074:                 */
1075:                protected void finalize() {
1076:                    // catch the case where an edit was made but never resolved
1077:                    if (m_active) {
1078:                        cancel(this );
1079:                    }
1080:                }
1081:
1082:                /**
1083:                 * Take all values from this object.
1084:                 * 
1085:                 * @param user
1086:                 *        The user object to take values from.
1087:                 */
1088:                protected void set(Digest digest) {
1089:                    setAll(digest);
1090:                }
1091:
1092:                /**
1093:                 * Access the event code for this edit.
1094:                 * 
1095:                 * @return The event code for this edit.
1096:                 */
1097:                protected String getEvent() {
1098:                    return m_event;
1099:                }
1100:
1101:                /**
1102:                 * Set the event code for this edit.
1103:                 * 
1104:                 * @param event
1105:                 *        The event code for this edit.
1106:                 */
1107:                protected void setEvent(String event) {
1108:                    m_event = event;
1109:                }
1110:
1111:                /**
1112:                 * @inheritDoc
1113:                 */
1114:                public ResourcePropertiesEdit getPropertiesEdit() {
1115:                    return m_properties;
1116:                }
1117:
1118:                /**
1119:                 * Enable editing.
1120:                 */
1121:                protected void activate() {
1122:                    m_active = true;
1123:                }
1124:
1125:                /**
1126:                 * @inheritDoc
1127:                 */
1128:                public boolean isActiveEdit() {
1129:                    return m_active;
1130:                }
1131:
1132:                /**
1133:                 * Close the edit object - it cannot be used after this.
1134:                 */
1135:                protected void closeEdit() {
1136:                    m_active = false;
1137:                }
1138:
1139:                /******************************************************************************************************************************************************************************************************************************************************
1140:                 * SessionBindingListener implementation
1141:                 *****************************************************************************************************************************************************************************************************************************************************/
1142:
1143:                /**
1144:                 * @inheritDoc
1145:                 */
1146:                public void valueBound(SessionBindingEvent event) {
1147:                }
1148:
1149:                /**
1150:                 * @inheritDoc
1151:                 */
1152:                public void valueUnbound(SessionBindingEvent event) {
1153:                    if (M_log.isDebugEnabled())
1154:                        M_log.debug(this  + ".valueUnbound()");
1155:
1156:                    // catch the case where an edit was made but never resolved
1157:                    if (m_active) {
1158:                        cancel(this );
1159:                    }
1160:                }
1161:            }
1162:
1163:            /**********************************************************************************************************************************************************************************************************************************************************
1164:             * Storage
1165:             *********************************************************************************************************************************************************************************************************************************************************/
1166:
1167:            protected interface Storage {
1168:                /**
1169:                 * Open.
1170:                 */
1171:                public void open();
1172:
1173:                /**
1174:                 * Close.
1175:                 */
1176:                public void close();
1177:
1178:                /**
1179:                 * Check if a digest by this id exists.
1180:                 * 
1181:                 * @param id
1182:                 *        The user id.
1183:                 * @return true if a digest for this id exists, false if not.
1184:                 */
1185:                public boolean check(String id);
1186:
1187:                /**
1188:                 * Get the digest with this id, or null if not found.
1189:                 * 
1190:                 * @param id
1191:                 *        The digest id.
1192:                 * @return The digest with this id, or null if not found.
1193:                 */
1194:                public Digest get(String id);
1195:
1196:                /**
1197:                 * Get all digests.
1198:                 * 
1199:                 * @return The list of all digests.
1200:                 */
1201:                public List getAll();
1202:
1203:                /**
1204:                 * Add a new digest with this id.
1205:                 * 
1206:                 * @param id
1207:                 *        The digest id.
1208:                 * @return The locked Digest object with this id, or null if the id is in use.
1209:                 */
1210:                public DigestEdit put(String id);
1211:
1212:                /**
1213:                 * Get a lock on the digest with this id, or null if a lock cannot be gotten.
1214:                 * 
1215:                 * @param id
1216:                 *        The digest id.
1217:                 * @return The locked Digest with this id, or null if this records cannot be locked.
1218:                 */
1219:                public DigestEdit edit(String id);
1220:
1221:                /**
1222:                 * Commit the changes and release the lock.
1223:                 * 
1224:                 * @param user
1225:                 *        The edit to commit.
1226:                 */
1227:                public void commit(DigestEdit edit);
1228:
1229:                /**
1230:                 * Cancel the changes and release the lock.
1231:                 * 
1232:                 * @param user
1233:                 *        The edit to commit.
1234:                 */
1235:                public void cancel(DigestEdit edit);
1236:
1237:                /**
1238:                 * Remove this edit and release the lock.
1239:                 * 
1240:                 * @param user
1241:                 *        The edit to remove.
1242:                 */
1243:                public void remove(DigestEdit edit);
1244:            }
1245:
1246:            /**********************************************************************************************************************************************************************************************************************************************************
1247:             * StorageUser implementation (no container)
1248:             *********************************************************************************************************************************************************************************************************************************************************/
1249:
1250:            /**
1251:             * @inheritDoc
1252:             */
1253:            public Entity newContainer(String ref) {
1254:                return null;
1255:            }
1256:
1257:            /**
1258:             * @inheritDoc
1259:             */
1260:            public Entity newContainer(Element element) {
1261:                return null;
1262:            }
1263:
1264:            /**
1265:             * @inheritDoc
1266:             */
1267:            public Entity newContainer(Entity other) {
1268:                return null;
1269:            }
1270:
1271:            /**
1272:             * @inheritDoc
1273:             */
1274:            public Entity newResource(Entity container, String id,
1275:                    Object[] others) {
1276:                return new BaseDigest(id);
1277:            }
1278:
1279:            /**
1280:             * @inheritDoc
1281:             */
1282:            public Entity newResource(Entity container, Element element) {
1283:                return new BaseDigest(element);
1284:            }
1285:
1286:            /**
1287:             * @inheritDoc
1288:             */
1289:            public Entity newResource(Entity container, Entity other) {
1290:                return new BaseDigest((Digest) other);
1291:            }
1292:
1293:            /**
1294:             * @inheritDoc
1295:             */
1296:            public Edit newContainerEdit(String ref) {
1297:                return null;
1298:            }
1299:
1300:            /**
1301:             * @inheritDoc
1302:             */
1303:            public Edit newContainerEdit(Element element) {
1304:                return null;
1305:            }
1306:
1307:            /**
1308:             * @inheritDoc
1309:             */
1310:            public Edit newContainerEdit(Entity other) {
1311:                return null;
1312:            }
1313:
1314:            /**
1315:             * @inheritDoc
1316:             */
1317:            public Edit newResourceEdit(Entity container, String id,
1318:                    Object[] others) {
1319:                BaseDigest e = new BaseDigest(id);
1320:                e.activate();
1321:                return e;
1322:            }
1323:
1324:            /**
1325:             * @inheritDoc
1326:             */
1327:            public Edit newResourceEdit(Entity container, Element element) {
1328:                BaseDigest e = new BaseDigest(element);
1329:                e.activate();
1330:                return e;
1331:            }
1332:
1333:            /**
1334:             * @inheritDoc
1335:             */
1336:            public Edit newResourceEdit(Entity container, Entity other) {
1337:                BaseDigest e = new BaseDigest((Digest) other);
1338:                e.activate();
1339:                return e;
1340:            }
1341:
1342:            /**
1343:             * @inheritDoc
1344:             */
1345:            public Object[] storageFields(Entity r) {
1346:                return null;
1347:            }
1348:
1349:            /**
1350:             * @inheritDoc
1351:             */
1352:            public boolean isDraft(Entity r) {
1353:                return false;
1354:            }
1355:
1356:            /**
1357:             * @inheritDoc
1358:             */
1359:            public String getOwnerId(Entity r) {
1360:                return null;
1361:            }
1362:
1363:            /**
1364:             * @inheritDoc
1365:             */
1366:            public Time getDate(Entity r) {
1367:                return null;
1368:            }
1369:
1370:            /**
1371:             * Compute a time range based on a specific time.
1372:             * 
1373:             * @return The time range that encloses the specific time.
1374:             */
1375:            protected TimeRange computeRange(Time time) {
1376:                // set the period to "today" (local!) from day start to next day start, not end inclusive
1377:                TimeBreakdown brk = time.breakdownLocal();
1378:                brk.setMs(0);
1379:                brk.setSec(0);
1380:                brk.setMin(0);
1381:                brk.setHour(0);
1382:                Time start = timeService().newTimeLocal(brk);
1383:                Time end = timeService().newTime(
1384:                        start.getTime() + 24 * 60 * 60 * 1000);
1385:                return timeService().newTimeRange(start, end, true, false);
1386:            }
1387:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.