0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/chat/tags/sakai_2-4-1/chat-impl/impl/src/java/org/sakaiproject/chat/impl/BaseChatService.java $
0003: * $Id: BaseChatService.java 22868 2007-03-19 01:49:36Z chmaurer@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.chat.impl;
0021:
0022: import java.util.Iterator;
0023: import java.util.List;
0024: import java.util.Map;
0025: import java.util.HashMap;
0026: import java.util.Set;
0027: import java.util.Stack;
0028: import java.util.Properties;
0029:
0030: import org.apache.commons.logging.Log;
0031: import org.apache.commons.logging.LogFactory;
0032: import org.sakaiproject.authz.cover.FunctionManager;
0033: import org.sakaiproject.chat.api.ChatChannel;
0034: import org.sakaiproject.chat.api.ChatChannelEdit;
0035: import org.sakaiproject.chat.api.ChatMessage;
0036: import org.sakaiproject.chat.api.ChatMessageEdit;
0037: import org.sakaiproject.chat.api.ChatMessageHeader;
0038: import org.sakaiproject.chat.api.ChatMessageHeaderEdit;
0039: import org.sakaiproject.chat.api.ChatService;
0040: import org.sakaiproject.entity.api.ContextObserver;
0041: import org.sakaiproject.entity.api.Edit;
0042: import org.sakaiproject.entity.api.Entity;
0043: import org.sakaiproject.entity.api.Summary;
0044: import org.sakaiproject.entity.api.Reference;
0045: import org.sakaiproject.entity.api.ResourceProperties;
0046: import org.sakaiproject.entity.api.EntityTransferrer;
0047: import org.sakaiproject.exception.IdInvalidException;
0048: import org.sakaiproject.exception.IdUnusedException;
0049: import org.sakaiproject.exception.IdUsedException;
0050: import org.sakaiproject.exception.InUseException;
0051: import org.sakaiproject.exception.PermissionException;
0052: import org.sakaiproject.message.api.Message;
0053: import org.sakaiproject.message.api.MessageChannel;
0054: import org.sakaiproject.message.api.MessageHeader;
0055: import org.sakaiproject.message.api.MessageHeaderEdit;
0056: import org.sakaiproject.message.impl.BaseMessageService;
0057: import org.sakaiproject.site.cover.SiteService;
0058: import org.sakaiproject.time.api.Time;
0059: import org.sakaiproject.time.cover.TimeService;
0060:
0061: import org.sakaiproject.tool.api.Session;
0062: import org.sakaiproject.tool.api.ToolSession;
0063: import org.sakaiproject.tool.cover.SessionManager;
0064: import org.sakaiproject.util.StringUtil;
0065: import org.sakaiproject.site.api.Site;
0066: import org.sakaiproject.site.api.ToolConfiguration;
0067: import org.w3c.dom.DOMException;
0068: import org.w3c.dom.Document;
0069: import org.w3c.dom.Element;
0070: import org.w3c.dom.Node;
0071: import org.w3c.dom.NodeList;
0072:
0073: /**
0074: * <p>
0075: * BaseChatService extends the BaseMessageService for the specifics of Chat.
0076: * </p>
0077: */
0078: public abstract class BaseChatService extends BaseMessageService
0079: implements ChatService, ContextObserver, EntityTransferrer {
0080: /** Our logger. */
0081: private static Log M_log = LogFactory.getLog(BaseChatService.class);
0082:
0083: private static final String CHAT = "chat";
0084: private static final String CHANNEL = "channel";
0085: private static final String CHANNEL_ID = "id";
0086: private static final String PREF_CHAT_ROOM = "selectedChatRoom";
0087: private static final String FILTER_TYPE = "filterType";
0088: private static final String FILTER_PARAM = "filterParam";
0089: private static final String ARCHIVE_VERSION = "2.4"; // in case new features are added in future exports
0090: private static final String VERSION_ATTR = "version";
0091: private static final String SYNOPTIC_TOOL = "synoptic_tool";
0092: private static final String NAME = "name";
0093: private static final String VALUE = "value";
0094:
0095: // properties
0096: private static final String CHANNEL_PROP = "channel";
0097: private static final String FILTER_TYPE_PROP = "filter-type";
0098: private static final String FILTER_PARAM_PROP = "filter-param";
0099: private static final String PROPERTIES = "properties";
0100: private static final String PROPERTY = "property";
0101:
0102: /** Tool session attribute name used to schedule a whole page refresh. */
0103: public static final String ATTR_TOP_REFRESH = "sakai.vppa.top.refresh";
0104: private static final String STATE_UPDATE = "update";
0105:
0106: /**********************************************************************************************************************************************************************************************************************************************************
0107: * Init and Destroy
0108: *********************************************************************************************************************************************************************************************************************************************************/
0109:
0110: /**
0111: * Final initialization, once all dependencies are set.
0112: */
0113: public void init() {
0114: super .init();
0115: /*
0116: // register functions
0117: FunctionManager.registerFunction(eventId(SECURE_READ));
0118: FunctionManager.registerFunction(eventId(SECURE_ADD));
0119: FunctionManager.registerFunction(eventId(SECURE_REMOVE_ANY));
0120: FunctionManager.registerFunction(eventId(SECURE_REMOVE_OWN));
0121:
0122: // entity producer registration
0123: m_entityManager.registerEntityProducer(this, REFERENCE_ROOT);
0124: */
0125: }
0126:
0127: /**********************************************************************************************************************************************************************************************************************************************************
0128: * StorageUser implementation
0129: *********************************************************************************************************************************************************************************************************************************************************/
0130:
0131: /**
0132: * Construct a new continer given just ids.
0133: *
0134: * @param ref
0135: * The channel reference.
0136: * @return The new containe Resource.
0137: */
0138: public Entity newContainer(String ref) {
0139: return new BaseChatChannelEdit(ref);
0140: }
0141:
0142: /**
0143: * Construct a new container resource, from an XML element.
0144: *
0145: * @param element
0146: * The XML.
0147: * @return The new container resource.
0148: */
0149: public Entity newContainer(Element element) {
0150: return new BaseChatChannelEdit(element);
0151: }
0152:
0153: /**
0154: * Construct a new container resource, as a copy of another
0155: *
0156: * @param other
0157: * The other contianer to copy.
0158: * @return The new container resource.
0159: */
0160: public Entity newContainer(Entity other) {
0161: return new BaseChatChannelEdit((MessageChannel) other);
0162: }
0163:
0164: /**
0165: * Construct a new rsource given just an id.
0166: *
0167: * @param container
0168: * The Resource that is the container for the new resource (may be null).
0169: * @param id
0170: * The id for the new object.
0171: * @param others
0172: * (options) array of objects to load into the Resource's fields.
0173: * @return The new resource.
0174: */
0175: public Entity newResource(Entity container, String id,
0176: Object[] others) {
0177: return new BaseChatMessageEdit((MessageChannel) container, id);
0178: }
0179:
0180: /**
0181: * Construct a new resource, from an XML element.
0182: *
0183: * @param container
0184: * The Resource that is the container for the new resource (may be null).
0185: * @param element
0186: * The XML.
0187: * @return The new resource from the XML.
0188: */
0189: public Entity newResource(Entity container, Element element) {
0190: return new BaseChatMessageEdit((MessageChannel) container,
0191: element);
0192: }
0193:
0194: /**
0195: * Construct a new resource from another resource of the same type.
0196: *
0197: * @param container
0198: * The Resource that is the container for the new resource (may be null).
0199: * @param other
0200: * The other resource.
0201: * @return The new resource as a copy of the other.
0202: */
0203: public Entity newResource(Entity container, Entity other) {
0204: return new BaseChatMessageEdit((MessageChannel) container,
0205: (Message) other);
0206: }
0207:
0208: /**
0209: * Construct a new continer given just ids.
0210: *
0211: * @param ref
0212: * The channel reference.
0213: * @return The new containe Resource.
0214: */
0215: public Edit newContainerEdit(String ref) {
0216: BaseChatChannelEdit rv = new BaseChatChannelEdit(ref);
0217: rv.activate();
0218: return rv;
0219: }
0220:
0221: /**
0222: * Construct a new container resource, from an XML element.
0223: *
0224: * @param element
0225: * The XML.
0226: * @return The new container resource.
0227: */
0228: public Edit newContainerEdit(Element element) {
0229: BaseChatChannelEdit rv = new BaseChatChannelEdit(element);
0230: rv.activate();
0231: return rv;
0232: }
0233:
0234: /**
0235: * Construct a new container resource, as a copy of another
0236: *
0237: * @param other
0238: * The other contianer to copy.
0239: * @return The new container resource.
0240: */
0241: public Edit newContainerEdit(Entity other) {
0242: BaseChatChannelEdit rv = new BaseChatChannelEdit(
0243: (MessageChannel) other);
0244: rv.activate();
0245: return rv;
0246: }
0247:
0248: /**
0249: * Construct a new rsource given just an id.
0250: *
0251: * @param container
0252: * The Resource that is the container for the new resource (may be null).
0253: * @param id
0254: * The id for the new object.
0255: * @param others
0256: * (options) array of objects to load into the Resource's fields.
0257: * @return The new resource.
0258: */
0259: public Edit newResourceEdit(Entity container, String id,
0260: Object[] others) {
0261: BaseChatMessageEdit rv = new BaseChatMessageEdit(
0262: (MessageChannel) container, id);
0263: rv.activate();
0264: return rv;
0265: }
0266:
0267: /**
0268: * Construct a new resource, from an XML element.
0269: *
0270: * @param container
0271: * The Resource that is the container for the new resource (may be null).
0272: * @param element
0273: * The XML.
0274: * @return The new resource from the XML.
0275: */
0276: public Edit newResourceEdit(Entity container, Element element) {
0277: BaseChatMessageEdit rv = new BaseChatMessageEdit(
0278: (MessageChannel) container, element);
0279: rv.activate();
0280: return rv;
0281: }
0282:
0283: /**
0284: * Construct a new resource from another resource of the same type.
0285: *
0286: * @param container
0287: * The Resource that is the container for the new resource (may be null).
0288: * @param other
0289: * The other resource.
0290: * @return The new resource as a copy of the other.
0291: */
0292: public Edit newResourceEdit(Entity container, Entity other) {
0293: BaseChatMessageEdit rv = new BaseChatMessageEdit(
0294: (MessageChannel) container, (Message) other);
0295: rv.activate();
0296: return rv;
0297: }
0298:
0299: /**
0300: * Collect the fields that need to be stored outside the XML (for the resource).
0301: *
0302: * @return An array of field values to store in the record outside the XML (for the resource).
0303: */
0304: public Object[] storageFields(Entity r) {
0305: Object[] rv = new Object[4];
0306: rv[0] = ((Message) r).getHeader().getDate();
0307: rv[1] = ((Message) r).getHeader().getFrom().getId();
0308: rv[2] = "0";
0309: rv[3] = r.getProperties().getProperty(
0310: ResourceProperties.PROP_PUBVIEW) == null ? "0" : "1";
0311:
0312: return rv;
0313: }
0314:
0315: /**
0316: * Check if this resource is in draft mode.
0317: *
0318: * @param r
0319: * The resource.
0320: * @return true if the resource is in draft mode, false if not.
0321: */
0322: public boolean isDraft(Entity r) {
0323: return false;
0324: }
0325:
0326: /**
0327: * Access the resource owner user id.
0328: *
0329: * @param r
0330: * The resource.
0331: * @return The resource owner user id.
0332: */
0333: public String getOwnerId(Entity r) {
0334: return ((Message) r).getHeader().getFrom().getId();
0335: }
0336:
0337: /**
0338: * Access the resource date.
0339: *
0340: * @param r
0341: * The resource.
0342: * @return The resource date.
0343: */
0344: public Time getDate(Entity r) {
0345: return ((Message) r).getHeader().getDate();
0346: }
0347:
0348: /**********************************************************************************************************************************************************************************************************************************************************
0349: * Abstractions, etc. satisfied
0350: *********************************************************************************************************************************************************************************************************************************************************/
0351:
0352: /**
0353: * Report the Service API name being implemented.
0354: */
0355: protected String serviceName() {
0356: return ChatService.class.getName();
0357: }
0358:
0359: /**
0360: * Construct a new message header from XML in a DOM element.
0361: *
0362: * @param id
0363: * The message Id.
0364: * @return The new message header.
0365: */
0366: protected MessageHeaderEdit newMessageHeader(Message msg, String id) {
0367: return new BaseChatMessageHeaderEdit(msg, id);
0368:
0369: } // newMessageHeader
0370:
0371: /**
0372: * Construct a new message header from XML in a DOM element.
0373: *
0374: * @param el
0375: * The XML DOM element that has the header information.
0376: * @return The new message header.
0377: */
0378: protected MessageHeaderEdit newMessageHeader(Message msg, Element el) {
0379: return new BaseChatMessageHeaderEdit(msg, el);
0380:
0381: } // newMessageHeader
0382:
0383: /**
0384: * Construct a new message header as a copy of another.
0385: *
0386: * @param other
0387: * The other header to copy.
0388: * @return The new message header.
0389: */
0390: protected MessageHeaderEdit newMessageHeader(Message msg,
0391: MessageHeader other) {
0392: return new BaseChatMessageHeaderEdit(msg, other);
0393:
0394: } // newMessageHeader
0395:
0396: /**
0397: * Form a tracking event string based on a security function string.
0398: *
0399: * @param secure
0400: * The security function string.
0401: * @return The event tracking string.
0402: */
0403: protected String eventId(String secure) {
0404: return "chat." + secure;
0405:
0406: } // eventId
0407:
0408: /**
0409: * Return the reference rooot for use in resource references and urls.
0410: *
0411: * @return The reference rooot for use in resource references and urls.
0412: */
0413: protected String getReferenceRoot() {
0414: return REFERENCE_ROOT;
0415:
0416: } // getReferenceRoot
0417:
0418: /**
0419: * {@inheritDoc}
0420: */
0421: public boolean parseEntityReference(String reference, Reference ref) {
0422: if (reference.startsWith(REFERENCE_ROOT)) {
0423: String[] parts = StringUtil.split(reference,
0424: Entity.SEPARATOR);
0425:
0426: String id = null;
0427: String subType = null;
0428: String context = null;
0429: String container = null;
0430:
0431: // the first part will be null, then next the service, the third will be "msg" or "channel"
0432: if (parts.length > 2) {
0433: subType = parts[2];
0434: if (REF_TYPE_CHANNEL.equals(subType)) {
0435: // next is the context id
0436: if (parts.length > 3) {
0437: context = parts[3];
0438:
0439: // next is the channel id
0440: if (parts.length > 4) {
0441: id = parts[4];
0442: }
0443: }
0444: } else if (REF_TYPE_MESSAGE.equals(subType)) {
0445: // next three parts are context, channel (container) and mesage id
0446: if (parts.length > 5) {
0447: context = parts[3];
0448: container = parts[4];
0449: id = parts[5];
0450: }
0451: } else
0452: M_log.warn("parse(): unknown message subtype: "
0453: + subType + " in ref: " + reference);
0454: }
0455:
0456: ref.set(APPLICATION_ID, subType, id, container, context);
0457:
0458: return true;
0459: }
0460:
0461: return false;
0462: }
0463:
0464: /**
0465: * {@inheritDoc}
0466: */
0467: public void contextCreated(String context, boolean toolPlacement) {
0468: if (toolPlacement)
0469: enableMessageChannel(context);
0470: }
0471:
0472: /**
0473: * {@inheritDoc}
0474: */
0475: public void contextUpdated(String context, boolean toolPlacement) {
0476: if (toolPlacement)
0477: enableMessageChannel(context);
0478: }
0479:
0480: /**
0481: * {@inheritDoc}
0482: */
0483: public void contextDeleted(String context, boolean toolPlacement) {
0484: disableMessageChannel(context);
0485: }
0486:
0487: /**
0488: * {@inheritDoc}
0489: */
0490: public String[] myToolIds() {
0491: String[] toolIds = { "sakai.chat" };
0492: return toolIds;
0493: }
0494:
0495: /**********************************************************************************************************************************************************************************************************************************************************
0496: * ChatService implementation
0497: *********************************************************************************************************************************************************************************************************************************************************/
0498:
0499: /**
0500: * Return a specific chat channel.
0501: *
0502: * @param ref
0503: * The channel reference.
0504: * @return the ChatChannel that has the specified name.
0505: * @exception IdUnusedException
0506: * If this name is not defined for a chat channel.
0507: * @exception PermissionException
0508: * If the user does not have any permissions to the channel.
0509: */
0510: public ChatChannel getChatChannel(String ref)
0511: throws IdUnusedException, PermissionException {
0512: return (ChatChannel) getChannel(ref);
0513:
0514: } // getChatChannel
0515:
0516: /**
0517: * Add a new chat channel.
0518: *
0519: * @param ref
0520: * The channel reference.
0521: * @return The newly created channel.
0522: * @exception IdUsedException
0523: * if the id is not unique.
0524: * @exception IdInvalidException
0525: * if the id is not made up of valid characters.
0526: * @exception PermissionException
0527: * if the user does not have permission to add a channel.
0528: */
0529: public ChatChannelEdit addChatChannel(String ref)
0530: throws IdUsedException, IdInvalidException,
0531: PermissionException {
0532: return (ChatChannelEdit) addChannel(ref);
0533:
0534: } // addChatChannel
0535:
0536: /**********************************************************************************************************************************************************************************************************************************************************
0537: * ResourceService implementation
0538: *********************************************************************************************************************************************************************************************************************************************************/
0539:
0540: /**
0541: * {@inheritDoc}
0542: */
0543: public String getLabel() {
0544: return "chat";
0545: }
0546:
0547: /**********************************************************************************************************************************************************************************************************************************************************
0548: * ChatChannel implementation
0549: *********************************************************************************************************************************************************************************************************************************************************/
0550:
0551: public class BaseChatChannelEdit extends BaseMessageChannelEdit
0552: implements ChatChannelEdit {
0553: /**
0554: * Construct with a reference.
0555: *
0556: * @param ref
0557: * The channel reference.
0558: */
0559: public BaseChatChannelEdit(String ref) {
0560: super (ref);
0561:
0562: } // BaseChatChannelEdit
0563:
0564: /**
0565: * Construct as a copy of another message.
0566: *
0567: * @param other
0568: * The other message to copy.
0569: */
0570: public BaseChatChannelEdit(MessageChannel other) {
0571: super (other);
0572:
0573: } // BaseChatChannelEdit
0574:
0575: /**
0576: * Construct from a channel (and possibly messages) already defined in XML in a DOM tree. The Channel is added to storage.
0577: *
0578: * @param el
0579: * The XML DOM element defining the channel.
0580: */
0581: public BaseChatChannelEdit(Element el) {
0582: super (el);
0583:
0584: } // BaseChatChannelEdit
0585:
0586: /**
0587: * Return a specific chat channel message, as specified by message name.
0588: *
0589: * @param messageId
0590: * The id of the message to get.
0591: * @return the ChatMessage that has the specified id.
0592: * @exception IdUnusedException
0593: * If this name is not a defined message in this chat channel.
0594: * @exception PermissionException
0595: * If the user does not have any permissions to read the message.
0596: */
0597: public ChatMessage getChatMessage(String messageId)
0598: throws IdUnusedException, PermissionException {
0599: return (ChatMessage) getMessage(messageId);
0600:
0601: } // getChatMessage
0602:
0603: /**
0604: * A (ChatMessageEdit) 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!
0605: *
0606: * @param messageId
0607: * The id of the message to get.
0608: * @return the Message that has the specified id.
0609: * @exception IdUnusedException
0610: * If this name is not a defined message in this channel.
0611: * @exception PermissionException
0612: * If the user does not have any permissions to read the message.
0613: * @exception InUseException
0614: * if the current user does not have permission to mess with this user.
0615: */
0616: public ChatMessageEdit editChatMessage(String messageId)
0617: throws IdUnusedException, PermissionException,
0618: InUseException {
0619: return (ChatMessageEdit) editMessage(messageId);
0620:
0621: } // editChatMessage
0622:
0623: /**
0624: * A (ChatMessageEdit) cover for addMessage. Add a new message to this channel. Must commitEdit() to make official, or cancelEdit() when done!
0625: *
0626: * @return The newly added message, locked for update.
0627: * @exception PermissionException
0628: * If the user does not have write permission to the channel.
0629: */
0630: public ChatMessageEdit addChatMessage()
0631: throws PermissionException {
0632: return (ChatMessageEdit) addMessage();
0633:
0634: } // addChatMessage
0635:
0636: /**
0637: * a (ChatMessage) cover for addMessage to add a new message to this channel.
0638: *
0639: * @param attachments
0640: * The message header attachments, a vector of Reference objects.
0641: * @param body
0642: * The body text.
0643: * @return The newly added message.
0644: * @exception PermissionException
0645: * If the user does not have write permission to the channel.
0646: */
0647: public ChatMessage addChatMessage(List attachments, String body)
0648: throws PermissionException {
0649: ChatMessageEdit edit = (ChatMessageEdit) addMessage();
0650: ChatMessageHeaderEdit header = edit.getChatHeaderEdit();
0651: edit.setBody(body);
0652: header.replaceAttachments(attachments);
0653:
0654: commitMessage(edit);
0655:
0656: return edit;
0657:
0658: } // addChatMessage
0659:
0660: } // class BaseChatChannelEdit
0661:
0662: /**********************************************************************************************************************************************************************************************************************************************************
0663: * ChatMessage implementation
0664: *********************************************************************************************************************************************************************************************************************************************************/
0665:
0666: public class BaseChatMessageEdit extends BaseMessageEdit implements
0667: ChatMessageEdit {
0668: /**
0669: * Construct.
0670: *
0671: * @param channel
0672: * The channel in which this message lives.
0673: * @param id
0674: * The message id.
0675: */
0676: public BaseChatMessageEdit(MessageChannel channel, String id) {
0677: super (channel, id);
0678:
0679: } // BaseChatMessageEdit
0680:
0681: /**
0682: * Construct as a copy of another message.
0683: *
0684: * @param other
0685: * The other message to copy.
0686: */
0687: public BaseChatMessageEdit(MessageChannel channel, Message other) {
0688: super (channel, other);
0689:
0690: } // BaseChatMessageEdit
0691:
0692: /**
0693: * Construct from an existing definition, in xml.
0694: *
0695: * @param channel
0696: * The channel in which this message lives.
0697: * @param el
0698: * The message in XML in a DOM element.
0699: */
0700: public BaseChatMessageEdit(MessageChannel channel, Element el) {
0701: super (channel, el);
0702:
0703: } // BaseChatMessageEdit
0704:
0705: /**
0706: * Access the chat message header.
0707: *
0708: * @return The chat message header.
0709: */
0710: public ChatMessageHeader getChatHeader() {
0711: return (ChatMessageHeader) getHeader();
0712:
0713: } // getChatHeader
0714:
0715: /**
0716: * Access the chat message header.
0717: *
0718: * @return The chat message header.
0719: */
0720: public ChatMessageHeaderEdit getChatHeaderEdit() {
0721: return (ChatMessageHeaderEdit) getHeader();
0722:
0723: } // getChatHeaderEdit
0724:
0725: } // class BasicChatMessageEdit
0726:
0727: /**********************************************************************************************************************************************************************************************************************************************************
0728: * ChatMessageHeaderEdit implementation
0729: *********************************************************************************************************************************************************************************************************************************************************/
0730:
0731: public class BaseChatMessageHeaderEdit extends
0732: BaseMessageHeaderEdit implements ChatMessageHeaderEdit {
0733: /**
0734: * Construct.
0735: *
0736: * @param id
0737: * The unique (within the channel) message id.
0738: * @param from
0739: * The User who sent the message to the channel.
0740: * @param attachments
0741: * The message header attachments, a vector of Reference objects.
0742: */
0743: public BaseChatMessageHeaderEdit(Message msg, String id) {
0744: super (msg, id);
0745:
0746: } // BaseChatMessageHeaderEdit
0747:
0748: /**
0749: * Construct, from an already existing XML DOM element.
0750: *
0751: * @param el
0752: * The header in XML in a DOM element.
0753: */
0754: public BaseChatMessageHeaderEdit(Message msg, Element el) {
0755: super (msg, el);
0756:
0757: } // BaseChatMessageHeaderEdit
0758:
0759: /**
0760: * Construct as a copy of another header.
0761: *
0762: * @param other
0763: * The other message header to copy.
0764: */
0765: public BaseChatMessageHeaderEdit(Message msg,
0766: MessageHeader other) {
0767: super (msg, other);
0768: }
0769: }
0770:
0771: /**********************************************************************************************************************************************************************************************************************************************************
0772: * Import/Export implementation
0773: *********************************************************************************************************************************************************************************************************************************************************/
0774:
0775: /**
0776: * {@inheritDoc}
0777: */
0778: public boolean willArchiveMerge() {
0779: return true;
0780: }
0781:
0782: /**
0783: * {@inheritDoc}
0784: */
0785: public String archive(String siteId, Document doc, Stack stack,
0786: String archivePath, List attachments) {
0787: //prepare the buffer for the results log
0788: StringBuffer results = new StringBuffer();
0789: int channelCount = 0;
0790:
0791: try {
0792: // start with an element with our very own (service) name
0793: Element element = doc.createElement(serviceName());
0794: element.setAttribute(VERSION_ATTR, ARCHIVE_VERSION);
0795: ((Element) stack.peek()).appendChild(element);
0796: stack.push(element);
0797:
0798: Element chat = doc.createElement(CHAT);
0799:
0800: // get the site's user-set options
0801: Site site = SiteService.getSite(siteId);
0802: ToolConfiguration fromTool = site
0803: .getToolForCommonId("sakai.chat");
0804: Properties fromProp = fromTool.getPlacementConfig();
0805:
0806: if (fromProp != null && !fromProp.isEmpty()) {
0807: String preferredChannel = fromProp
0808: .getProperty(CHANNEL_PROP);
0809: if (preferredChannel != null
0810: && preferredChannel.trim().length() > 0) {
0811: chat.setAttribute(PREF_CHAT_ROOM, preferredChannel);
0812: }
0813:
0814: String filterType = fromProp
0815: .getProperty(FILTER_TYPE_PROP);
0816: if (filterType != null
0817: && filterType.trim().length() > 0) {
0818: chat.setAttribute(FILTER_TYPE, filterType);
0819: }
0820:
0821: String filterParam = fromProp
0822: .getProperty(FILTER_PARAM_PROP);
0823: if (filterParam != null
0824: && filterParam.trim().length() > 0) {
0825: chat.setAttribute(FILTER_PARAM, filterParam);
0826: }
0827: }
0828:
0829: List channelIdList = getChannelIds(siteId);
0830: if (channelIdList != null && !channelIdList.isEmpty()) {
0831: Iterator idIterator = channelIdList.iterator();
0832: while (idIterator.hasNext()) {
0833: String channelId = (String) idIterator.next();
0834: ChatChannel channel = null;
0835: String channelRef = channelReference(siteId,
0836: channelId);
0837: try {
0838: channel = (ChatChannel) getChannel(channelRef);
0839: } catch (IdUnusedException e) {
0840: M_log
0841: .warn("Exception archiving channel with id: "
0842: + channelId);
0843: }
0844:
0845: Element channelElement = channel.toXml(doc, stack);
0846: chat.appendChild(channelElement);
0847: channelCount++;
0848: }
0849: results.append("archiving " + getLabel() + ": ("
0850: + channelCount
0851: + ") channels archived successfully.\n");
0852:
0853: } else {
0854: results.append("archiving " + getLabel()
0855: + ": empty chat room archived.\n");
0856: }
0857:
0858: // archive the chat synoptic tool options
0859: archiveSynopticOptions(siteId, doc, chat);
0860:
0861: ((Element) stack.peek()).appendChild(chat);
0862: stack.push(chat);
0863:
0864: stack.pop();
0865: } catch (Exception any) {
0866: M_log.warn("archive: exception archiving service: "
0867: + serviceName());
0868: }
0869:
0870: stack.pop();
0871:
0872: return results.toString();
0873: }
0874:
0875: /**
0876: * {@inheritDoc}
0877: */
0878: public String merge(String siteId, Element root,
0879: String archivePath, String fromSiteId, Map attachmentNames,
0880: Map userIdTrans, Set userListAllowImport) {
0881: M_log.debug("trying to merge chat");
0882:
0883: // buffer for the results log
0884: StringBuffer results = new StringBuffer();
0885:
0886: int count = 0;
0887:
0888: if (siteId != null && siteId.trim().length() > 0) {
0889: try {
0890: NodeList allChildrenNodes = root.getChildNodes();
0891: int length = allChildrenNodes.getLength();
0892: for (int i = 0; i < length; i++) {
0893: count++;
0894: Node siteNode = allChildrenNodes.item(i);
0895: if (siteNode.getNodeType() == Node.ELEMENT_NODE) {
0896: Element chatElement = (Element) siteNode;
0897: if (chatElement.getTagName().equals(CHAT)) {
0898: Site site = SiteService.getSite(siteId);
0899: if (site.getToolForCommonId("sakai.chat") != null) {
0900: ToolConfiguration tool = site
0901: .getToolForCommonId("sakai.chat");
0902: Properties prop = tool
0903: .getPlacementConfig();
0904:
0905: // set the user-defined options
0906: String prefChatRoom = chatElement
0907: .getAttribute(PREF_CHAT_ROOM);
0908: String filterParam = chatElement
0909: .getAttribute(FILTER_PARAM);
0910: String filterType = chatElement
0911: .getAttribute(FILTER_TYPE);
0912:
0913: if (prefChatRoom != null) {
0914: int index = prefChatRoom
0915: .lastIndexOf(Entity.SEPARATOR) + 1;
0916: prefChatRoom = prefChatRoom
0917: .substring(index);
0918: if (prefChatRoom != null
0919: && prefChatRoom.length() > 0) {
0920: prefChatRoom = channelReference(
0921: siteId, prefChatRoom);
0922: prop.setProperty(CHANNEL_PROP,
0923: prefChatRoom);
0924: } else {
0925: M_log
0926: .warn("Invalid chat room preference not merged:"
0927: + chatElement
0928: .getAttribute(PREF_CHAT_ROOM));
0929: }
0930: }
0931:
0932: if (filterType != null
0933: && filterType.length() > 0)
0934: prop.setProperty(FILTER_TYPE_PROP,
0935: filterType);
0936:
0937: if (filterParam != null
0938: && inputIsValidInteger(filterParam))
0939: prop.setProperty(FILTER_PARAM_PROP,
0940: filterParam);
0941: else
0942: M_log
0943: .warn("Invalid filter parameter not merged: "
0944: + filterParam);
0945:
0946: // add the chat rooms and synoptic tool options
0947: NodeList chatNodes = chatElement
0948: .getChildNodes();
0949: int lengthChatNodes = chatNodes
0950: .getLength();
0951: for (int cn = 0; cn < lengthChatNodes; cn++) {
0952: Node chatNode = chatNodes.item(cn);
0953: if (chatNode.getNodeType() == Node.ELEMENT_NODE) {
0954: Element channelElement = (Element) chatNode;
0955: if (channelElement.getTagName()
0956: .equals(CHANNEL)) {
0957: String channelId = channelElement
0958: .getAttribute(CHANNEL_ID);
0959: if (channelId != null
0960: && channelId.trim()
0961: .length() > 0) {
0962: ChatChannel nChannel = null;
0963: String nChannelRef = channelReference(
0964: siteId,
0965: channelId);
0966: try {
0967: nChannel = (ChatChannel) getChannel(nChannelRef);
0968: } catch (IdUnusedException e) {
0969: try {
0970: commitChannel(addChatChannel(nChannelRef));
0971:
0972: try {
0973: nChannel = (ChatChannel) getChannel(nChannelRef);
0974: } catch (IdUnusedException eee) {
0975: M_log
0976: .warn("IdUnusedException while getting channel with reference "
0977: + nChannelRef
0978: + ": "
0979: + eee);
0980: }
0981: } catch (Exception ee) {
0982: M_log
0983: .warn("Exception while committing channel with reference "
0984: + nChannelRef
0985: + ": "
0986: + ee);
0987: }
0988: }
0989: }
0990: } else if (channelElement
0991: .getTagName().equals(
0992: SYNOPTIC_TOOL)) {
0993: ToolConfiguration synTool = site
0994: .getToolForCommonId("sakai.synoptic.chat");
0995: Properties synProps = synTool
0996: .getPlacementConfig();
0997:
0998: NodeList synPropNodes = channelElement
0999: .getChildNodes();
1000: for (int props = 0; props < synPropNodes
1001: .getLength(); props++) {
1002: Node propsNode = synPropNodes
1003: .item(props);
1004: if (propsNode
1005: .getNodeType() == Node.ELEMENT_NODE) {
1006: Element synPropEl = (Element) propsNode;
1007: if (synPropEl
1008: .getTagName()
1009: .equals(
1010: PROPERTIES)) {
1011: NodeList synProperties = synPropEl
1012: .getChildNodes();
1013: for (int p = 0; p < synProperties
1014: .getLength(); p++) {
1015: Node propertyNode = synProperties
1016: .item(p);
1017: if (propertyNode
1018: .getNodeType() == Node.ELEMENT_NODE) {
1019: Element propEl = (Element) propertyNode;
1020: if (propEl
1021: .getTagName()
1022: .equals(
1023: PROPERTY)) {
1024: String propName = propEl
1025: .getAttribute(NAME);
1026: String propValue = propEl
1027: .getAttribute(VALUE);
1028:
1029: if (propName != null
1030: && propName
1031: .length() > 0
1032: && propValue != null
1033: && propValue
1034: .length() > 0) {
1035: if (propName
1036: .equals(CHANNEL_PROP)) {
1037: int index = propValue
1038: .lastIndexOf(Entity.SEPARATOR);
1039: propValue = propValue
1040: .substring(index + 1);
1041: if (propValue != null
1042: && propValue
1043: .length() > 0) {
1044: String channelRef = channelReference(
1045: siteId,
1046: propValue);
1047: try {
1048: ChatChannel channel = (ChatChannel) getChannel(channelRef);
1049: synProps
1050: .setProperty(
1051: propName,
1052: channelRef
1053: .toString());
1054: } catch (IdUnusedException e) {
1055: // do not add channel b/c it does not exist in Chat tool
1056: M_log
1057: .warn("Chat Synoptic Tool Channel preference not added- "
1058: + channelRef
1059: + ":"
1060: + e);
1061: }
1062: }
1063: } else {
1064: synProps
1065: .setProperty(
1066: propName,
1067: propValue);
1068: }
1069: }
1070: }
1071: }
1072: }
1073: }
1074: }
1075: }
1076: // refresh the synoptic tool on the home page
1077: Session session = m_sessionManager
1078: .getCurrentSession();
1079: ToolSession toolSession = session
1080: .getToolSession(synTool
1081: .getId());
1082: if (toolSession
1083: .getAttribute(STATE_UPDATE) == null) {
1084: toolSession
1085: .setAttribute(
1086: STATE_UPDATE,
1087: STATE_UPDATE);
1088: }
1089: }
1090: }
1091: }
1092: SiteService.save(site);
1093:
1094: scheduleTopRefresh();
1095: }
1096: }
1097: }
1098: }
1099:
1100: results.append("merging chat " + siteId + " (" + count
1101: + ") chat items.\n");
1102: } catch (DOMException e) {
1103: M_log.error(e.getMessage(), e);
1104: results.append("merging " + getLabel()
1105: + " failed during xml parsing.\n");
1106: } catch (Exception e) {
1107: M_log.error(e.getMessage(), e);
1108: results.append("merging " + getLabel() + " failed.\n");
1109: }
1110: }
1111:
1112: return results.toString();
1113:
1114: } // merge
1115:
1116: /**
1117: * {@inheritDoc}
1118: */
1119: public void transferCopyEntities(String fromContext,
1120: String toContext, List ids) {
1121: try {
1122: // get the "from" site's user-set options
1123: Site fromSite = SiteService.getSite(fromContext);
1124: ToolConfiguration fromTool = fromSite
1125: .getToolForCommonId("sakai.chat");
1126: Properties fromProp = fromTool.getPlacementConfig();
1127:
1128: Site toSite = SiteService.getSite(toContext);
1129: ToolConfiguration tool = toSite
1130: .getToolForCommonId("sakai.chat");
1131:
1132: if (fromProp != null && !fromProp.isEmpty()) {
1133: String preferredChannel = fromProp
1134: .getProperty(CHANNEL_PROP);
1135: String filterType = fromProp
1136: .getProperty(FILTER_TYPE_PROP);
1137: String filterParam = fromProp
1138: .getProperty(FILTER_PARAM_PROP);
1139:
1140: //set these properties in the "to" site
1141: Properties toProp = tool.getPlacementConfig();
1142:
1143: if (preferredChannel != null) {
1144: int index = preferredChannel
1145: .lastIndexOf(Entity.SEPARATOR) + 1;
1146: preferredChannel = preferredChannel
1147: .substring(index);
1148: if (preferredChannel != null
1149: && preferredChannel.length() > 0) {
1150: String channelRef = channelReference(toContext,
1151: preferredChannel);
1152: toProp.setProperty(CHANNEL_PROP, channelRef);
1153: }
1154: }
1155: if (filterType != null && filterType.length() > 0) {
1156: toProp.setProperty(FILTER_TYPE_PROP, filterType);
1157: }
1158: if (filterParam != null) {
1159: toProp.setProperty(FILTER_PARAM_PROP, filterParam);
1160: }
1161:
1162: SiteService.save(toSite);
1163: }
1164:
1165: // retrieve all of the chat rooms
1166: List oChannelIdList = getChannelIds(fromContext);
1167: if (oChannelIdList != null && !oChannelIdList.isEmpty()) {
1168: Iterator idIterator = oChannelIdList.iterator();
1169: while (idIterator.hasNext()) {
1170: String oChannelId = (String) idIterator.next();
1171: ChatChannel nChannel = null;
1172: String nChannelRef = channelReference(toContext,
1173: oChannelId);
1174: try {
1175: nChannel = (ChatChannel) getChannel(nChannelRef);
1176: } catch (IdUnusedException e) {
1177: try {
1178: commitChannel(addChatChannel(nChannelRef));
1179:
1180: try {
1181: nChannel = (ChatChannel) getChannel(nChannelRef);
1182: } catch (IdUnusedException eee) {
1183: M_log
1184: .warn("IdUnusedException while getting channel with reference "
1185: + nChannelRef
1186: + ": "
1187: + eee);
1188: }
1189: } catch (Exception ee) {
1190: M_log
1191: .warn("Exception while committing channel with reference "
1192: + nChannelRef + ": " + ee);
1193: }
1194: }
1195:
1196: }
1197: }
1198:
1199: transferSynopticOptions(fromContext, toContext);
1200:
1201: scheduleTopRefresh();
1202: }
1203:
1204: catch (Exception any) {
1205: M_log.warn(
1206: ".transferCopyEntities(): exception in handling "
1207: + serviceName() + " : ", any);
1208: }
1209: }
1210:
1211: private void scheduleTopRefresh() {
1212: ToolSession session = SessionManager.getCurrentToolSession();
1213: if (session.getAttribute(ATTR_TOP_REFRESH) == null) {
1214: session.setAttribute(ATTR_TOP_REFRESH, Boolean.TRUE);
1215: }
1216: }
1217:
1218: private boolean inputIsValidInteger(String val) {
1219: try {
1220: Integer.parseInt(val);
1221: return true;
1222: } catch (Exception e) {
1223: return false;
1224: }
1225: }
1226: }
|