0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/announcement/tags/sakai_2-4-1/announcement-impl/impl/src/java/org/sakaiproject/announcement/impl/BaseAnnouncementService.java $
0003: * $Id: BaseAnnouncementService.java 22564 2007-03-13 19:52:27Z josrodri@iupui.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.announcement.impl;
0021:
0022: import java.io.PrintWriter;
0023: import java.util.Collection;
0024: import java.util.Iterator;
0025: import java.util.List;
0026: import java.util.Stack;
0027: import java.util.Map;
0028: import java.util.HashMap;
0029:
0030: import javax.servlet.http.HttpServletRequest;
0031: import javax.servlet.http.HttpServletResponse;
0032:
0033: import org.apache.commons.logging.Log;
0034: import org.apache.commons.logging.LogFactory;
0035: import org.sakaiproject.announcement.api.AnnouncementChannel;
0036: import org.sakaiproject.announcement.api.AnnouncementChannelEdit;
0037: import org.sakaiproject.announcement.api.AnnouncementMessage;
0038: import org.sakaiproject.announcement.api.AnnouncementMessageEdit;
0039: import org.sakaiproject.announcement.api.AnnouncementMessageHeader;
0040: import org.sakaiproject.announcement.api.AnnouncementMessageHeaderEdit;
0041: import org.sakaiproject.announcement.api.AnnouncementService;
0042: import org.sakaiproject.authz.cover.FunctionManager;
0043: import org.sakaiproject.authz.cover.SecurityService;
0044: import org.sakaiproject.content.api.ContentResource;
0045: import org.sakaiproject.content.cover.ContentHostingService;
0046: import org.sakaiproject.entity.api.ContextObserver;
0047: import org.sakaiproject.entity.api.Edit;
0048: import org.sakaiproject.entity.api.Entity;
0049: import org.sakaiproject.entity.api.Summary;
0050: import org.sakaiproject.entity.api.EntityAccessOverloadException;
0051: import org.sakaiproject.entity.api.EntityCopyrightException;
0052: import org.sakaiproject.entity.api.EntityNotDefinedException;
0053: import org.sakaiproject.entity.api.EntityPermissionException;
0054: import org.sakaiproject.entity.api.EntityTransferrer;
0055: import org.sakaiproject.entity.api.HttpAccess;
0056: import org.sakaiproject.entity.api.Reference;
0057: import org.sakaiproject.entity.api.ResourceProperties;
0058: import org.sakaiproject.entity.api.ResourcePropertiesEdit;
0059: import org.sakaiproject.event.api.NotificationEdit;
0060: import org.sakaiproject.event.api.NotificationService;
0061: import org.sakaiproject.exception.IdInvalidException;
0062: import org.sakaiproject.exception.IdUnusedException;
0063: import org.sakaiproject.exception.IdUsedException;
0064: import org.sakaiproject.exception.InUseException;
0065: import org.sakaiproject.exception.PermissionException;
0066: import org.sakaiproject.javax.Filter;
0067: import org.sakaiproject.message.api.Message;
0068: import org.sakaiproject.message.api.MessageChannel;
0069: import org.sakaiproject.message.api.MessageHeader;
0070: import org.sakaiproject.message.api.MessageHeaderEdit;
0071: import org.sakaiproject.message.impl.BaseMessageService;
0072: import org.sakaiproject.site.api.SiteService;
0073: import org.sakaiproject.time.api.Time;
0074: import org.sakaiproject.time.cover.TimeService;
0075: import org.sakaiproject.tool.cover.SessionManager;
0076: import org.sakaiproject.tool.cover.ToolManager;
0077: import org.sakaiproject.util.ResourceLoader;
0078: import org.sakaiproject.util.StringUtil;
0079: import org.sakaiproject.util.Validator;
0080: import org.w3c.dom.Document;
0081: import org.w3c.dom.Element;
0082:
0083: /**
0084: * <p>
0085: * BaseAnnouncementService extends the BaseMessageService for the specifics of Announcement.
0086: * </p>
0087: */
0088: public abstract class BaseAnnouncementService extends
0089: BaseMessageService implements AnnouncementService,
0090: ContextObserver, EntityTransferrer {
0091: /** Our logger. */
0092: private static Log M_log = LogFactory
0093: .getLog(BaseAnnouncementService.class);
0094:
0095: /** Messages, for the http access. */
0096: protected static ResourceLoader rb = new ResourceLoader(
0097: "annc-access");
0098:
0099: /**********************************************************************************************************************************************************************************************************************************************************
0100: * Constructors, Dependencies and their setter methods
0101: *********************************************************************************************************************************************************************************************************************************************************/
0102:
0103: /** Dependency: NotificationService. */
0104: protected NotificationService m_notificationService = null;
0105:
0106: /**
0107: * Dependency: NotificationService.
0108: *
0109: * @param service
0110: * The NotificationService.
0111: */
0112: public void setNotificationService(NotificationService service) {
0113: m_notificationService = service;
0114: }
0115:
0116: /**********************************************************************************************************************************************************************************************************************************************************
0117: * Init and Destroy
0118: *********************************************************************************************************************************************************************************************************************************************************/
0119:
0120: /**
0121: * Final initialization, once all dependencies are set.
0122: */
0123: public void init() {
0124: try {
0125: super .init();
0126:
0127: // register a transient notification for announcements
0128: NotificationEdit edit = m_notificationService
0129: .addTransientNotification();
0130:
0131: // set functions
0132: edit.setFunction(eventId(SECURE_ADD));
0133: edit.addFunction(eventId(SECURE_UPDATE_OWN));
0134: edit.addFunction(eventId(SECURE_UPDATE_ANY));
0135:
0136: // set the filter to any announcement resource (see messageReference())
0137: edit.setResourceFilter(getAccessPoint(true)
0138: + Entity.SEPARATOR + REF_TYPE_MESSAGE);
0139:
0140: // set the action
0141: edit.setAction(new SiteEmailNotificationAnnc());
0142:
0143: // register functions
0144: FunctionManager.registerFunction(eventId(SECURE_READ));
0145: FunctionManager.registerFunction(eventId(SECURE_ADD));
0146: FunctionManager
0147: .registerFunction(eventId(SECURE_REMOVE_ANY));
0148: FunctionManager
0149: .registerFunction(eventId(SECURE_REMOVE_OWN));
0150: FunctionManager
0151: .registerFunction(eventId(SECURE_UPDATE_ANY));
0152: FunctionManager
0153: .registerFunction(eventId(SECURE_UPDATE_OWN));
0154: FunctionManager
0155: .registerFunction(eventId(SECURE_ALL_GROUPS));
0156:
0157: // Sakai v2.4: UI end says hidden, 'under the covers' says draft
0158: // Done so import from old sites causes drafts to 'become' hidden in new sites
0159: FunctionManager
0160: .registerFunction(eventId(SECURE_READ_DRAFT));
0161:
0162: // entity producer registration
0163: m_entityManager
0164: .registerEntityProducer(this , REFERENCE_ROOT);
0165:
0166: M_log.info("init()");
0167: } catch (Throwable t) {
0168: M_log.warn("init(): ", t);
0169: }
0170:
0171: } // init
0172:
0173: /**********************************************************************************************************************************************************************************************************************************************************
0174: * StorageUser implementation
0175: *********************************************************************************************************************************************************************************************************************************************************/
0176:
0177: /**
0178: * Construct a new continer given just ids.
0179: *
0180: * @param ref
0181: * The container reference.
0182: * @return The new containe Resource.
0183: */
0184: public Entity newContainer(String ref) {
0185: return new BaseAnnouncementChannelEdit(ref);
0186: }
0187:
0188: /**
0189: * Construct a new container resource, from an XML element.
0190: *
0191: * @param element
0192: * The XML.
0193: * @return The new container resource.
0194: */
0195: public Entity newContainer(Element element) {
0196: return new BaseAnnouncementChannelEdit(element);
0197: }
0198:
0199: /**
0200: * Construct a new container resource, as a copy of another
0201: *
0202: * @param other
0203: * The other contianer to copy.
0204: * @return The new container resource.
0205: */
0206: public Entity newContainer(Entity other) {
0207: return new BaseAnnouncementChannelEdit((MessageChannel) other);
0208: }
0209:
0210: /**
0211: * Construct a new rsource given just an id.
0212: *
0213: * @param container
0214: * The Resource that is the container for the new resource (may be null).
0215: * @param id
0216: * The id for the new object.
0217: * @param others
0218: * (options) array of objects to load into the Resource's fields.
0219: * @return The new resource.
0220: */
0221: public Entity newResource(Entity container, String id,
0222: Object[] others) {
0223: return new BaseAnnouncementMessageEdit(
0224: (MessageChannel) container, id);
0225: }
0226:
0227: /**
0228: * Construct a new resource, from an XML element.
0229: *
0230: * @param container
0231: * The Resource that is the container for the new resource (may be null).
0232: * @param element
0233: * The XML.
0234: * @return The new resource from the XML.
0235: */
0236: public Entity newResource(Entity container, Element element) {
0237: return new BaseAnnouncementMessageEdit(
0238: (MessageChannel) container, element);
0239: }
0240:
0241: /**
0242: * Construct a new resource from another resource of the same type.
0243: *
0244: * @param container
0245: * The Resource that is the container for the new resource (may be null).
0246: * @param other
0247: * The other resource.
0248: * @return The new resource as a copy of the other.
0249: */
0250: public Entity newResource(Entity container, Entity other) {
0251: return new BaseAnnouncementMessageEdit(
0252: (MessageChannel) container, (Message) other);
0253: }
0254:
0255: /**
0256: * Construct a new continer given just ids.
0257: *
0258: * @param ref
0259: * The container reference.
0260: * @return The new containe Resource.
0261: */
0262: public Edit newContainerEdit(String ref) {
0263: BaseAnnouncementChannelEdit rv = new BaseAnnouncementChannelEdit(
0264: ref);
0265: rv.activate();
0266: return rv;
0267: }
0268:
0269: /**
0270: * Construct a new container resource, from an XML element.
0271: *
0272: * @param element
0273: * The XML.
0274: * @return The new container resource.
0275: */
0276: public Edit newContainerEdit(Element element) {
0277: BaseAnnouncementChannelEdit rv = new BaseAnnouncementChannelEdit(
0278: element);
0279: rv.activate();
0280: return rv;
0281: }
0282:
0283: /**
0284: * Construct a new container resource, as a copy of another
0285: *
0286: * @param other
0287: * The other contianer to copy.
0288: * @return The new container resource.
0289: */
0290: public Edit newContainerEdit(Entity other) {
0291: BaseAnnouncementChannelEdit rv = new BaseAnnouncementChannelEdit(
0292: (MessageChannel) other);
0293: rv.activate();
0294: return rv;
0295: }
0296:
0297: /**
0298: * Construct a new rsource given just an id.
0299: *
0300: * @param container
0301: * The Resource that is the container for the new resource (may be null).
0302: * @param id
0303: * The id for the new object.
0304: * @param others
0305: * (options) array of objects to load into the Resource's fields.
0306: * @return The new resource.
0307: */
0308: public Edit newResourceEdit(Entity container, String id,
0309: Object[] others) {
0310: BaseAnnouncementMessageEdit rv = new BaseAnnouncementMessageEdit(
0311: (MessageChannel) container, id);
0312: rv.activate();
0313: return rv;
0314: }
0315:
0316: /**
0317: * Construct a new resource, from an XML element.
0318: *
0319: * @param container
0320: * The Resource that is the container for the new resource (may be null).
0321: * @param element
0322: * The XML.
0323: * @return The new resource from the XML.
0324: */
0325: public Edit newResourceEdit(Entity container, Element element) {
0326: BaseAnnouncementMessageEdit rv = new BaseAnnouncementMessageEdit(
0327: (MessageChannel) container, element);
0328: rv.activate();
0329: return rv;
0330: }
0331:
0332: /**
0333: * Construct a new resource from another resource of the same type.
0334: *
0335: * @param container
0336: * The Resource that is the container for the new resource (may be null).
0337: * @param other
0338: * The other resource.
0339: * @return The new resource as a copy of the other.
0340: */
0341: public Edit newResourceEdit(Entity container, Entity other) {
0342: BaseAnnouncementMessageEdit rv = new BaseAnnouncementMessageEdit(
0343: (MessageChannel) container, (Message) other);
0344: rv.activate();
0345: return rv;
0346: }
0347:
0348: /**
0349: * Collect the fields that need to be stored outside the XML (for the resource).
0350: *
0351: * @return An array of field values to store in the record outside the XML (for the resource).
0352: */
0353: public Object[] storageFields(Entity r) {
0354: Object[] rv = new Object[4];
0355: rv[0] = ((Message) r).getHeader().getDate();
0356: rv[1] = ((Message) r).getHeader().getFrom().getId();
0357: rv[2] = ((AnnouncementMessage) r).getAnnouncementHeader()
0358: .getDraft() ? "1" : "0";
0359: rv[3] = r.getProperties().getProperty(
0360: ResourceProperties.PROP_PUBVIEW) == null ? "0" : "1";
0361: // rv[3] = ((AnnouncementMessage) r).getAnnouncementHeader().getAccess() == MessageHeader.MessageAccess.PUBLIC ? "1" : "0";
0362:
0363: return rv;
0364: }
0365:
0366: /**
0367: * Check if this resource is in draft mode.
0368: *
0369: * @param r
0370: * The resource.
0371: * @return true if the resource is in draft mode, false if not.
0372: */
0373: public boolean isDraft(Entity r) {
0374: return ((AnnouncementMessage) r).getAnnouncementHeader()
0375: .getDraft();
0376: }
0377:
0378: /**
0379: * Access the resource owner user id.
0380: *
0381: * @param r
0382: * The resource.
0383: * @return The resource owner user id.
0384: */
0385: public String getOwnerId(Entity r) {
0386: return ((Message) r).getHeader().getFrom().getId();
0387: }
0388:
0389: /**
0390: * Access the resource date.
0391: *
0392: * @param r
0393: * The resource.
0394: * @return The resource date.
0395: */
0396: public Time getDate(Entity r) {
0397: return ((Message) r).getHeader().getDate();
0398: }
0399:
0400: /**********************************************************************************************************************************************************************************************************************************************************
0401: * Abstractions, etc. satisfied
0402: *********************************************************************************************************************************************************************************************************************************************************/
0403:
0404: /**
0405: * Report the Service API name being implemented.
0406: */
0407: protected String serviceName() {
0408: return AnnouncementService.class.getName();
0409: }
0410:
0411: /**
0412: * Construct a new message header from XML in a DOM element.
0413: *
0414: * @param id
0415: * The message Id.
0416: * @return The new message header.
0417: */
0418: protected MessageHeaderEdit newMessageHeader(Message msg, String id) {
0419: return new BaseAnnouncementMessageHeaderEdit(msg, id);
0420:
0421: } // newMessageHeader
0422:
0423: /**
0424: * Construct a new message header from XML in a DOM element.
0425: *
0426: * @param el
0427: * The XML DOM element that has the header information.
0428: * @return The new message header.
0429: */
0430: protected MessageHeaderEdit newMessageHeader(Message msg, Element el) {
0431: return new BaseAnnouncementMessageHeaderEdit(msg, el);
0432:
0433: } // newMessageHeader
0434:
0435: /**
0436: * Construct a new message header as a copy of another.
0437: *
0438: * @param other
0439: * The other header to copy.
0440: * @return The new message header.
0441: */
0442: protected MessageHeaderEdit newMessageHeader(Message msg,
0443: MessageHeader other) {
0444: return new BaseAnnouncementMessageHeaderEdit(msg, other);
0445:
0446: } // newMessageHeader
0447:
0448: /**
0449: * Form a tracking event string based on a security function string.
0450: *
0451: * @param secure
0452: * The security function string.
0453: * @return The event tracking string.
0454: */
0455: protected String eventId(String secure) {
0456: return SECURE_ANNC_ROOT + secure;
0457:
0458: } // eventId
0459:
0460: /**
0461: * Return the reference rooot for use in resource references and urls.
0462: *
0463: * @return The reference rooot for use in resource references and urls.
0464: */
0465: protected String getReferenceRoot() {
0466: return REFERENCE_ROOT;
0467:
0468: } // getReferenceRoot
0469:
0470: /**
0471: * {@inheritDoc}
0472: */
0473: public boolean parseEntityReference(String reference, Reference ref) {
0474: if (reference.startsWith(REFERENCE_ROOT)) {
0475: String[] parts = StringUtil.split(reference,
0476: Entity.SEPARATOR);
0477:
0478: String id = null;
0479: String subType = null;
0480: String context = null;
0481: String container = null;
0482:
0483: // the first part will be null, then next the service, the third will be "msg" or "channel"
0484: if (parts.length > 2) {
0485: subType = parts[2];
0486: if (REF_TYPE_CHANNEL.equals(subType)) {
0487: // next is the context id
0488: if (parts.length > 3) {
0489: context = parts[3];
0490:
0491: // next is the channel id
0492: if (parts.length > 4) {
0493: id = parts[4];
0494: }
0495: }
0496: } else if (REF_TYPE_MESSAGE.equals(subType)) {
0497: // next three parts are context, channel (container) and mesage id
0498: if (parts.length > 5) {
0499: context = parts[3];
0500: container = parts[4];
0501: id = parts[5];
0502: }
0503: } else
0504: M_log.warn("parse(): unknown message subtype: "
0505: + subType + " in ref: " + reference);
0506: }
0507:
0508: ref.set(APPLICATION_ID, subType, id, container, context);
0509:
0510: return true;
0511: }
0512:
0513: return false;
0514: }
0515:
0516: /**
0517: * {@inheritDoc}
0518: */
0519: public void contextCreated(String context, boolean toolPlacement) {
0520: if (toolPlacement)
0521: enableMessageChannel(context);
0522: }
0523:
0524: /**
0525: * {@inheritDoc}
0526: */
0527: public void contextUpdated(String context, boolean toolPlacement) {
0528: if (toolPlacement)
0529: enableMessageChannel(context);
0530: }
0531:
0532: /**
0533: * {@inheritDoc}
0534: */
0535: public void contextDeleted(String context, boolean toolPlacement) {
0536: disableMessageChannel(context);
0537: }
0538:
0539: /**
0540: * {@inheritDoc}
0541: */
0542: public String[] myToolIds() {
0543: String[] toolIds = { "sakai.announcements" };
0544: return toolIds;
0545: }
0546:
0547: /**
0548: * {@inheritDoc}
0549: */
0550: public HttpAccess getHttpAccess() {
0551: return new HttpAccess() {
0552: public void handleAccess(HttpServletRequest req,
0553: HttpServletResponse res, Reference ref,
0554: Collection copyrightAcceptedRefs)
0555: throws EntityPermissionException,
0556: EntityNotDefinedException,
0557: EntityAccessOverloadException,
0558: EntityCopyrightException {
0559: /** Resource bundle using current language locale */
0560: // final ResourceBundle rb = ResourceBundle.getBundle("access");
0561: // check security on the message (throws if not permitted)
0562: try {
0563: unlock(SECURE_READ, ref.getReference());
0564: } catch (PermissionException e) {
0565: throw new EntityPermissionException(e.getUser(), e
0566: .getLock(), e.getResource());
0567: }
0568:
0569: try {
0570: AnnouncementMessage msg = (AnnouncementMessage) ref
0571: .getEntity();
0572: AnnouncementMessageHeader hdr = (AnnouncementMessageHeader) msg
0573: .getAnnouncementHeader();
0574:
0575: res.setContentType("text/html; charset=UTF-8");
0576: PrintWriter out = res.getWriter();
0577: out
0578: .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
0579: + "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n"
0580: + "<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
0581: + "<style type=\"text/css\">body{margin:0px;padding:1em;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:80%;}</style>\n"
0582: + "<title>"
0583: + rb.getString("announcement")
0584: + ": "
0585: + Validator.escapeHtml(hdr
0586: .getSubject())
0587: + "</title>"
0588: + "</head>\n<body>");
0589:
0590: out.println("<h1>" + rb.getString("announcement")
0591: + "</h1>");
0592:
0593: // header
0594: out.println("<table><tr><td><b>"
0595: + rb.getString("from")
0596: + ":</b></td><td>"
0597: + Validator.escapeHtml(hdr.getFrom()
0598: .getDisplayName()) + "</td></tr>");
0599: out.println("<tr><td><b>"
0600: + rb.getString("date")
0601: + ":</b></td><td>"
0602: + Validator.escapeHtml(hdr.getDate()
0603: .toStringLocalFull())
0604: + "</td></tr>");
0605: out.println("<tr><td><b>" + rb.getString("subject")
0606: + ":</b></td><td>"
0607: + Validator.escapeHtml(hdr.getSubject())
0608: + "</td></tr></table>");
0609:
0610: // body
0611: out.println("<p>"
0612: + Validator.escapeHtmlFormattedText(msg
0613: .getBody()) + "</p>");
0614:
0615: // attachments
0616: List attachments = hdr.getAttachments();
0617: if (attachments.size() > 0) {
0618: out.println("<p><b>"
0619: + rb.getString("attachments")
0620: + ":</b></p><p>");
0621: for (Iterator iAttachments = attachments
0622: .iterator(); iAttachments.hasNext();) {
0623: Reference attachment = (Reference) iAttachments
0624: .next();
0625: out.println("<a href=\""
0626: + Validator.escapeHtml(attachment
0627: .getUrl())
0628: + "\">"
0629: + Validator.escapeHtml(attachment
0630: .getUrl()) + "</a><br />");
0631: }
0632: out.println("</p>");
0633: }
0634:
0635: out.println("</body></html>");
0636: } catch (Throwable t) {
0637: throw new EntityNotDefinedException(ref
0638: .getReference());
0639: }
0640: }
0641: };
0642: }
0643:
0644: /**********************************************************************************************************************************************************************************************************************************************************
0645: * AnnouncementService implementation
0646: *********************************************************************************************************************************************************************************************************************************************************/
0647:
0648: /**
0649: * Return a specific announcement channel.
0650: *
0651: * @param ref
0652: * The channel reference.
0653: * @return the AnnouncementChannel that has the specified name.
0654: * @exception IdUnusedException
0655: * If this name is not defined for a announcement channel.
0656: * @exception PermissionException
0657: * If the user does not have any permissions to the channel.
0658: */
0659: public AnnouncementChannel getAnnouncementChannel(String ref)
0660: throws IdUnusedException, PermissionException {
0661: return (AnnouncementChannel) getChannel(ref);
0662:
0663: } // getAnnouncementChannel
0664:
0665: /**
0666: * Add a new announcement channel.
0667: *
0668: * @param ref
0669: * The channel reference.
0670: * @return The newly created channel.
0671: * @exception IdUsedException
0672: * if the id is not unique.
0673: * @exception IdInvalidException
0674: * if the id is not made up of valid characters.
0675: * @exception PermissionException
0676: * if the user does not have permission to add a channel.
0677: */
0678: public AnnouncementChannelEdit addAnnouncementChannel(String ref)
0679: throws IdUsedException, IdInvalidException,
0680: PermissionException {
0681: return (AnnouncementChannelEdit) addChannel(ref);
0682:
0683: } // addAnnouncementChannel
0684:
0685: /**********************************************************************************************************************************************************************************************************************************************************
0686: * ResourceService implementation
0687: *********************************************************************************************************************************************************************************************************************************************************/
0688:
0689: /**
0690: * {@inheritDoc}
0691: */
0692: public String getLabel() {
0693: return "announcement";
0694: }
0695:
0696: /**********************************************************************************************************************************************************************************************************************************************************
0697: * getSummaryFromHeader implementation
0698: *********************************************************************************************************************************************************************************************************************************************************/
0699: protected String getSummaryFromHeader(Message item,
0700: MessageHeader header) {
0701: String newText;
0702: if (header instanceof AnnouncementMessageHeader) {
0703: AnnouncementMessageHeader hdr = (AnnouncementMessageHeader) header;
0704: newText = hdr.getSubject();
0705: } else {
0706: newText = item.getBody();
0707: if (newText.length() > 50)
0708: newText = newText.substring(1, 49);
0709: }
0710: newText = newText + ", " + header.getFrom().getDisplayName()
0711: + ", " + header.getDate().toStringLocalFull();
0712: return newText;
0713: }
0714:
0715: /**
0716: * {@inheritDoc}
0717: */
0718: public void transferCopyEntities(String fromContext,
0719: String toContext, List resourceIds) {
0720: // get the channel associated with this site
0721: String oChannelRef = channelReference(fromContext,
0722: SiteService.MAIN_CONTAINER);
0723: AnnouncementChannel oChannel = null;
0724: try {
0725: oChannel = (AnnouncementChannel) getChannel(oChannelRef);
0726: // the "to" message channel
0727: String nChannelRef = channelReference(toContext,
0728: SiteService.MAIN_CONTAINER);
0729: AnnouncementChannel nChannel = null;
0730: try {
0731: nChannel = (AnnouncementChannel) getChannel(nChannelRef);
0732: } catch (IdUnusedException e) {
0733: try {
0734: commitChannel(addChannel(nChannelRef));
0735:
0736: try {
0737: nChannel = (AnnouncementChannel) getChannel(nChannelRef);
0738: } catch (Exception eee) {
0739: // ignore
0740: }
0741: } catch (Exception ee) {
0742: // ignore
0743: }
0744: }
0745:
0746: if (nChannel != null) {
0747: // pass the DOM to get new message ids, record the mapping from old to new, and adjust attachments
0748: List oMessageList = oChannel.getMessages(null, true);
0749: AnnouncementMessage oMessage = null;
0750: AnnouncementMessageHeader oMessageHeader = null;
0751: AnnouncementMessageEdit nMessage = null;
0752: for (int i = 0; i < oMessageList.size(); i++) {
0753: // the "from" message
0754: oMessage = (AnnouncementMessage) oMessageList
0755: .get(i);
0756: String oMessageId = oMessage.getId();
0757:
0758: boolean toBeImported = true;
0759: if (resourceIds != null && resourceIds.size() > 0) {
0760: // if there is a list for import assignments, only import those assignments and relative submissions
0761: toBeImported = false;
0762: for (int m = 0; m < resourceIds.size()
0763: && !toBeImported; m++) {
0764: if (((String) resourceIds.get(m))
0765: .equals(oMessageId)) {
0766: toBeImported = true;
0767: }
0768: }
0769: }
0770:
0771: if (toBeImported) {
0772: oMessageHeader = (AnnouncementMessageHeaderEdit) oMessage
0773: .getHeader();
0774: ResourceProperties oProperties = oMessage
0775: .getProperties();
0776:
0777: // the "to" message
0778: nMessage = (AnnouncementMessageEdit) nChannel
0779: .addMessage();
0780: nMessage.setBody(oMessage.getBody());
0781: // message header
0782: AnnouncementMessageHeaderEdit nMessageHeader = (AnnouncementMessageHeaderEdit) nMessage
0783: .getHeaderEdit();
0784: nMessageHeader
0785: .setDate(oMessageHeader.getDate());
0786: // when importing, refer to property to determine draft status
0787: if ("false"
0788: .equalsIgnoreCase(m_serverConfigurationService
0789: .getString("import.importAsDraft"))) {
0790: nMessageHeader.setDraft(oMessageHeader
0791: .getDraft());
0792: } else {
0793: nMessageHeader.setDraft(true);
0794: }
0795:
0796: nMessageHeader
0797: .setFrom(oMessageHeader.getFrom());
0798: nMessageHeader.setSubject(oMessageHeader
0799: .getSubject());
0800: // attachment
0801: List oAttachments = oMessageHeader
0802: .getAttachments();
0803: List nAttachments = m_entityManager
0804: .newReferenceList();
0805: for (int n = 0; n < oAttachments.size(); n++) {
0806: Reference oAttachmentRef = (Reference) oAttachments
0807: .get(n);
0808: String oAttachmentId = ((Reference) oAttachments
0809: .get(n)).getId();
0810: if (oAttachmentId.indexOf(fromContext) != -1) {
0811: // replace old site id with new site id in attachments
0812: String nAttachmentId = oAttachmentId
0813: .replaceAll(fromContext,
0814: toContext);
0815: try {
0816: ContentResource attachment = ContentHostingService
0817: .getResource(nAttachmentId);
0818: nAttachments.add(m_entityManager
0819: .newReference(attachment
0820: .getReference()));
0821: } catch (IdUnusedException e) {
0822: try {
0823: ContentResource oAttachment = ContentHostingService
0824: .getResource(oAttachmentId);
0825: try {
0826: if (ContentHostingService
0827: .isAttachmentResource(nAttachmentId)) {
0828: // add the new resource into attachment collection area
0829: ContentResource attachment = ContentHostingService
0830: .addAttachmentResource(
0831: Validator
0832: .escapeResourceName(oAttachment
0833: .getProperties()
0834: .getProperty(
0835: ResourceProperties.PROP_DISPLAY_NAME)),
0836: ToolManager
0837: .getCurrentPlacement()
0838: .getContext(),
0839: ToolManager
0840: .getTool(
0841: "sakai.announcements")
0842: .getTitle(),
0843: oAttachment
0844: .getContentType(),
0845: oAttachment
0846: .getContent(),
0847: oAttachment
0848: .getProperties());
0849: // add to attachment list
0850: nAttachments
0851: .add(m_entityManager
0852: .newReference(attachment
0853: .getReference()));
0854: } else {
0855: // add the new resource into resource area
0856: ContentResource attachment = ContentHostingService
0857: .addResource(
0858: Validator
0859: .escapeResourceName(oAttachment
0860: .getProperties()
0861: .getProperty(
0862: ResourceProperties.PROP_DISPLAY_NAME)),
0863: ToolManager
0864: .getCurrentPlacement()
0865: .getContext(),
0866: 1,
0867: oAttachment
0868: .getContentType(),
0869: oAttachment
0870: .getContent(),
0871: oAttachment
0872: .getProperties(),
0873: NotificationService.NOTI_NONE);
0874: // add to attachment list
0875: nAttachments
0876: .add(m_entityManager
0877: .newReference(attachment
0878: .getReference()));
0879: }
0880: } catch (Exception eeAny) {
0881: // if the new resource cannot be added
0882: M_log
0883: .warn(" cannot add new attachment with id="
0884: + nAttachmentId);
0885: }
0886: } catch (Exception eAny) {
0887: // if cannot find the original attachment, do nothing.
0888: M_log
0889: .warn(" cannot find the original attachment with id="
0890: + oAttachmentId);
0891: }
0892: } catch (Exception any) {
0893: M_log.info(any.getMessage());
0894: }
0895: } else {
0896: nAttachments.add(oAttachmentRef);
0897: }
0898: }
0899: nMessageHeader.replaceAttachments(nAttachments);
0900: // properties
0901: ResourcePropertiesEdit p = nMessage
0902: .getPropertiesEdit();
0903: p.clear();
0904: p.addAll(oProperties);
0905:
0906: // complete the edit
0907: nChannel.commitMessage(nMessage,
0908: NotificationService.NOTI_NONE);
0909: }
0910: }
0911:
0912: } // if
0913:
0914: transferSynopticOptions(fromContext, toContext);
0915: } catch (IdUnusedException e) {
0916: M_log.warn(" MessageChannel " + fromContext
0917: + " cannot be found. ");
0918: } catch (Exception any) {
0919: M_log.warn(".importResources(): exception in handling "
0920: + serviceName() + " : ", any);
0921: }
0922: }
0923:
0924: /**********************************************************************************************************************************************************************************************************************************************************
0925: * AnnouncementChannel implementation
0926: *********************************************************************************************************************************************************************************************************************************************************/
0927:
0928: public class BaseAnnouncementChannelEdit extends
0929: BaseMessageChannelEdit implements AnnouncementChannelEdit {
0930: /**
0931: * Construct with a reference.
0932: *
0933: * @param ref
0934: * The channel reference.
0935: */
0936: public BaseAnnouncementChannelEdit(String ref) {
0937: super (ref);
0938:
0939: } // BaseAnnouncementChannelEdit
0940:
0941: /**
0942: * Construct as a copy of another message.
0943: *
0944: * @param other
0945: * The other message to copy.
0946: */
0947: public BaseAnnouncementChannelEdit(MessageChannel other) {
0948: super (other);
0949:
0950: } // BaseAnnouncementChannelEdit
0951:
0952: /**
0953: * Construct from a channel (and possibly messages) already defined in XML in a DOM tree. The Channel is added to storage.
0954: *
0955: * @param el
0956: * The XML DOM element defining the channel.
0957: */
0958: public BaseAnnouncementChannelEdit(Element el) {
0959: super (el);
0960:
0961: } // BaseAnnouncementChannelEdit
0962:
0963: /**
0964: * Return a specific announcement channel message, as specified by message name.
0965: *
0966: * @param messageId
0967: * The id of the message to get.
0968: * @return the AnnouncementMessage that has the specified id.
0969: * @exception IdUnusedException
0970: * If this name is not a defined message in this announcement channel.
0971: * @exception PermissionException
0972: * If the user does not have any permissions to read the message.
0973: */
0974: public AnnouncementMessage getAnnouncementMessage(
0975: String messageId) throws IdUnusedException,
0976: PermissionException {
0977: AnnouncementMessage msg = (AnnouncementMessage) getMessage(messageId);
0978:
0979: // filter out drafts not by this user (unless this user is a super user or has access_draft ability)
0980: if ((msg.getAnnouncementHeader()).getDraft()
0981: && (!SecurityService.isSuperUser())
0982: && (!msg.getHeader().getFrom().getId().equals(
0983: SessionManager.getCurrentSessionUserId()))
0984: && (!unlockCheck(SECURE_READ_DRAFT, msg
0985: .getReference()))) {
0986: throw new PermissionException(SessionManager
0987: .getCurrentSessionUserId(), SECURE_READ, msg
0988: .getReference());
0989: }
0990:
0991: return msg;
0992:
0993: } // getAnnouncementMessage
0994:
0995: /**
0996: * Return a list of all or filtered messages in the channel. The order in which the messages will be found in the iteration is by date, oldest first if ascending is true, newest first if ascending is false.
0997: *
0998: * @param filter
0999: * A filtering object to accept messages, or null if no filtering is desired.
1000: * @param ascending
1001: * Order of messages, ascending if true, descending if false
1002: * @return a list on channel Message objects or specializations of Message objects (may be empty).
1003: * @exception PermissionException
1004: * if the user does not have read permission to the channel.
1005: */
1006: public List getMessages(Filter filter, boolean ascending)
1007: throws PermissionException {
1008: // filter out drafts this user cannot see
1009: filter = new PrivacyFilter(filter);
1010:
1011: return super .getMessages(filter, ascending);
1012:
1013: } // getMessages
1014:
1015: /**
1016: * A (AnnouncementMessageEdit) cover for editMessage. Return a specific channel message, as specified by message name, locked for update. Must commitEdit() to make official, or cancelEdit() when done!
1017: *
1018: * @param messageId
1019: * The id of the message to get.
1020: * @return the Message that has the specified id.
1021: * @exception IdUnusedException
1022: * If this name is not a defined message in this channel.
1023: * @exception PermissionException
1024: * If the user does not have any permissions to read the message.
1025: * @exception InUseException
1026: * if the current user does not have permission to mess with this user.
1027: */
1028: public AnnouncementMessageEdit editAnnouncementMessage(
1029: String messageId) throws IdUnusedException,
1030: PermissionException, InUseException {
1031: return (AnnouncementMessageEdit) editMessage(messageId);
1032:
1033: } // editAnnouncementMessage
1034:
1035: /**
1036: * A (AnnouncementMessageEdit) cover for addMessage. Add a new message to this channel. Must commitEdit() to make official, or cancelEdit() when done!
1037: *
1038: * @return The newly added message, locked for update.
1039: * @exception PermissionException
1040: * If the user does not have write permission to the channel.
1041: */
1042: public AnnouncementMessageEdit addAnnouncementMessage()
1043: throws PermissionException {
1044: return (AnnouncementMessageEdit) addMessage();
1045:
1046: } // addAnnouncementMessage
1047:
1048: /**
1049: * a (AnnouncementMessage) cover for addMessage to add a new message to this channel.
1050: *
1051: * @param subject
1052: * The message header subject.
1053: * @param draft
1054: * The message header draft indication.
1055: * @param attachments
1056: * The message header attachments, a vector of Reference objects.
1057: * @param body
1058: * The message body.
1059: * @return The newly added message.
1060: * @exception PermissionException
1061: * If the user does not have write permission to the channel.
1062: */
1063: public AnnouncementMessage addAnnouncementMessage(
1064: String subject, boolean draft, List attachments,
1065: String body) throws PermissionException {
1066: AnnouncementMessageEdit edit = (AnnouncementMessageEdit) addMessage();
1067: AnnouncementMessageHeaderEdit header = edit
1068: .getAnnouncementHeaderEdit();
1069: edit.setBody(body);
1070: header.replaceAttachments(attachments);
1071: header.setSubject(subject);
1072: header.setDraft(draft);
1073:
1074: commitMessage(edit);
1075:
1076: return edit;
1077:
1078: } // addAnnouncementMessage
1079:
1080: } // class BaseAnnouncementChannelEdit
1081:
1082: /**********************************************************************************************************************************************************************************************************************************************************
1083: * AnnouncementMessage implementation
1084: *********************************************************************************************************************************************************************************************************************************************************/
1085:
1086: public class BaseAnnouncementMessageEdit extends BaseMessageEdit
1087: implements AnnouncementMessageEdit {
1088: /**
1089: * Construct.
1090: *
1091: * @param channel
1092: * The channel in which this message lives.
1093: * @param id
1094: * The message id.
1095: */
1096: public BaseAnnouncementMessageEdit(MessageChannel channel,
1097: String id) {
1098: super (channel, id);
1099:
1100: } // BaseAnnouncementMessageEdit
1101:
1102: /**
1103: * Construct as a copy of another message.
1104: *
1105: * @param other
1106: * The other message to copy.
1107: */
1108: public BaseAnnouncementMessageEdit(MessageChannel channel,
1109: Message other) {
1110: super (channel, other);
1111:
1112: } // BaseAnnouncementMessageEdit
1113:
1114: /**
1115: * Construct from an existing definition, in xml.
1116: *
1117: * @param channel
1118: * The channel in which this message lives.
1119: * @param el
1120: * The message in XML in a DOM element.
1121: */
1122: public BaseAnnouncementMessageEdit(MessageChannel channel,
1123: Element el) {
1124: super (channel, el);
1125:
1126: } // BaseAnnouncementMessageEdit
1127:
1128: /**
1129: * Access the announcement message header.
1130: *
1131: * @return The announcement message header.
1132: */
1133: public AnnouncementMessageHeader getAnnouncementHeader() {
1134: return (AnnouncementMessageHeader) getHeader();
1135:
1136: } // getAnnouncementHeader
1137:
1138: /**
1139: * Access the announcement message header.
1140: *
1141: * @return The announcement message header.
1142: */
1143: public AnnouncementMessageHeaderEdit getAnnouncementHeaderEdit() {
1144: return (AnnouncementMessageHeaderEdit) getHeader();
1145:
1146: } // getAnnouncementHeaderEdit
1147:
1148: } // class BasicAnnouncementMessageEdit
1149:
1150: /**********************************************************************************************************************************************************************************************************************************************************
1151: * AnnouncementMessageHeaderEdit implementation
1152: *********************************************************************************************************************************************************************************************************************************************************/
1153:
1154: public class BaseAnnouncementMessageHeaderEdit extends
1155: BaseMessageHeaderEdit implements
1156: AnnouncementMessageHeaderEdit {
1157: /** The subject for the announcement. */
1158: protected String m_subject = null;
1159:
1160: /**
1161: * Construct.
1162: *
1163: * @param id
1164: * The unique (within the channel) message id.
1165: * @param from
1166: * The User who sent the message to the channel.
1167: * @param attachments
1168: * The message header attachments, a vector of Reference objects.
1169: */
1170: public BaseAnnouncementMessageHeaderEdit(Message msg, String id) {
1171: super (msg, id);
1172:
1173: } // BaseAnnouncementMessageHeaderEdit
1174:
1175: /**
1176: * Construct, from an already existing XML DOM element.
1177: *
1178: * @param el
1179: * The header in XML in a DOM element.
1180: */
1181: public BaseAnnouncementMessageHeaderEdit(Message msg, Element el) {
1182: super (msg, el);
1183:
1184: // extract the subject
1185: m_subject = el.getAttribute("subject");
1186:
1187: } // BaseAnnouncementMessageHeaderEdit
1188:
1189: /**
1190: * Construct as a copy of another header.
1191: *
1192: * @param other
1193: * The other message header to copy.
1194: */
1195: public BaseAnnouncementMessageHeaderEdit(Message msg,
1196: MessageHeader other) {
1197: super (msg, other);
1198:
1199: m_subject = ((AnnouncementMessageHeader) other)
1200: .getSubject();
1201:
1202: } // BaseAnnouncementMessageHeaderEdit
1203:
1204: /**
1205: * Access the subject of the announcement.
1206: *
1207: * @return The subject of the announcement.
1208: */
1209: public String getSubject() {
1210: return ((m_subject == null) ? "" : m_subject);
1211:
1212: } // getSubject
1213:
1214: /**
1215: * Set the subject of the announcement.
1216: *
1217: * @param subject
1218: * The subject of the announcement.
1219: */
1220: public void setSubject(String subject) {
1221: if (StringUtil.different(subject, m_subject)) {
1222: m_subject = subject;
1223: }
1224:
1225: } // setSubject
1226:
1227: /**
1228: * Serialize the resource into XML, adding an element to the doc under the top of the stack element.
1229: *
1230: * @param doc
1231: * The DOM doc to contain the XML (or null for a string return).
1232: * @param stack
1233: * The DOM elements, the top of which is the containing element of the new "resource" element.
1234: * @return The newly added element.
1235: */
1236: public Element toXml(Document doc, Stack stack) {
1237: // get the basic work done
1238: Element header = super .toXml(doc, stack);
1239:
1240: // add draft, subject
1241: header.setAttribute("subject", getSubject());
1242: header.setAttribute("draft", new Boolean(getDraft())
1243: .toString());
1244:
1245: return header;
1246:
1247: } // toXml
1248:
1249: } // BaseAnnouncementMessageHeader
1250:
1251: /**
1252: * A filter that will reject announcement message drafts not from the current user, and otherwise use another filter, if defined, for acceptance.
1253: */
1254: protected class PrivacyFilter implements Filter {
1255: /** The other filter to check with. May be null. */
1256: protected Filter m_filter = null;
1257:
1258: /**
1259: * Construct
1260: *
1261: * @param filter
1262: * The other filter we check with.
1263: */
1264: public PrivacyFilter(Filter filter) {
1265: m_filter = filter;
1266:
1267: } // PrivacyFilter
1268:
1269: /**
1270: * Does this object satisfy the criteria of the filter?
1271: *
1272: * @return true if the object is accepted by the filter, false if not.
1273: */
1274: public boolean accept(Object o) {
1275: // first if o is a announcement message that's a draft from another user, reject it
1276: if (o instanceof AnnouncementMessage) {
1277: AnnouncementMessage msg = (AnnouncementMessage) o;
1278:
1279: if ((msg.getAnnouncementHeader()).getDraft()
1280: && (!SecurityService.isSuperUser())
1281: && (!msg.getHeader().getFrom().getId().equals(
1282: SessionManager
1283: .getCurrentSessionUserId()))
1284: && (!unlockCheck(SECURE_READ_DRAFT, msg
1285: .getReference()))) {
1286: return false;
1287: }
1288: }
1289:
1290: // now, use the real filter, if present
1291: if (m_filter != null)
1292: return m_filter.accept(o);
1293:
1294: return true;
1295:
1296: } // accept
1297:
1298: } // PrivacyFilter
1299:
1300: }
|