diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetWhiteboardingJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetWhiteboardingJabberImpl.java new file mode 100644 index 000000000..802c8ac9e --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetWhiteboardingJabberImpl.java @@ -0,0 +1,494 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import java.util.*; + +import net.java.sip.communicator.impl.protocol.jabber.extensions.whiteboard.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.service.protocol.whiteboardobjects.*; +import net.java.sip.communicator.util.*; + +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.provider.*; +import org.jivesoftware.smack.util.*; + +/** + * Provides basic functionality for white-board. + * + * @author Julien Waechter + * @author Yana Stamcheva + */ +public class OperationSetWhiteboardingJabberImpl + implements OperationSetWhiteboarding +{ + private static final Logger logger = + Logger.getLogger(OperationSetWhiteboardingJabberImpl.class); + + /** + * The provider that created us. + */ + private ProtocolProviderServiceJabberImpl jabberProvider = null; + + /** + * A list of listeners subscribed for invitations multi user chat events. + */ + private Vector invitationListeners = new Vector(); + + /** + * A list of listeners subscribed for events indicating rejection of a + * multi user chat invitation sent by us. + */ + private Vector invitationRejectionListeners = new Vector(); + + /** + * Listeners that will be notified of changes in our status in the + * room such as us being kicked, banned, or granted admin permissions. + */ + private Vector presenceListeners = new Vector(); + + private Vector whiteboardSessions = new Vector(); + + private OperationSetPersistentPresenceJabberImpl presenceOpSet; + + /** + * Creates an instance of this operation set. + * @param provider a ref to the ProtocolProviderServiceImpl + * that created us and that we'll use for retrieving the underlying aim + * connection. + */ + public OperationSetWhiteboardingJabberImpl( + ProtocolProviderServiceJabberImpl provider) + { + this.jabberProvider = provider; + + provider.addRegistrationStateChangeListener( + new RegistrationStateListener()); + + // Add the custom WhiteboardObjectJabberProvider to the Smack library + ProviderManager pManager = ProviderManager.getInstance(); + + pManager.addExtensionProvider( + WhiteboardObjectPacketExtensionImpl.ELEMENT_NAME, + WhiteboardObjectPacketExtensionImpl.NAMESPACE, + new WhiteboardObjectJabberProvider()); + } + + /** + * Adds a listener to invitation notifications. + * + * @param listener an invitation listener. + */ + public void addInvitationListener(WhiteboardInvitationListener listener) + { + synchronized(invitationListeners) + { + if (!invitationListeners.contains(listener)) + invitationListeners.add(listener); + } + } + + /** + * Removes listener from the list of invitation listeners + * registered to receive invitation events. + * + * @param listener the invitation listener to remove. + */ + public void removeInvitationListener(WhiteboardInvitationListener listener) + { + synchronized(invitationListeners) + { + invitationListeners.remove(listener); + } + } + + /** + * Subscribes listener so that it would receive events indicating + * rejection of a multi-user chat invitation that we've sent earlier. + * + * @param listener the listener that we'll subscribe for invitation + * rejection events. + */ + public void addInvitationRejectionListener( + WhiteboardInvitationRejectionListener listener) + { + synchronized(invitationRejectionListeners) + { + if (!invitationRejectionListeners.contains(listener)) + invitationRejectionListeners.add(listener); + } + } + + /** + * Removes listener from the list of invitation listeners + * registered to receive invitation rejection events. + * + * @param listener the invitation listener to remove. + */ + public void removeInvitationRejectionListener( + WhiteboardInvitationRejectionListener listener) + { + synchronized(invitationRejectionListeners) + { + invitationRejectionListeners.remove(listener); + } + } + + /** + * Adds a listener that will be notified of changes in our status in a chat + * room such as us being kicked, banned or dropped. + * + * @param listener the LocalUserChatRoomPresenceListener. + */ + public void addPresenceListener(WhiteboardSessionPresenceListener listener) + { + synchronized(presenceListeners) + { + if (!presenceListeners.contains(listener)) + presenceListeners.add(listener); + } + } + + /** + * Removes a listener that was being notified of changes in our status in + * a room such as us being kicked, banned or dropped. + * + * @param listener the LocalUserChatRoomPresenceListener. + */ + public void removePresenceListener( + WhiteboardSessionPresenceListener listener) + { + synchronized(presenceListeners) + { + presenceListeners.remove(listener); + } + } + + /** + * Creates a WhiteboardSession. For now the session is created + * locally and neither the sessionName, nor the sessionProperties are + * used. + * @param sessionName the name of the session + * @param sessionProperties the settings of the session + * @throws OperationFailedException if the room couldn't be created for some + * reason (e.g. room already exists; user already joined to an existent + * room or user has no permissions to create a chat room). + * @throws OperationNotSupportedException if chat room creation is not + * supported by this server + * @return the created white-board session + */ + public WhiteboardSession createWhiteboardSession( + String sessionName, + Hashtable sessionProperties) + throws OperationFailedException, + OperationNotSupportedException + { + WhiteboardSessionJabberImpl session + = new WhiteboardSessionJabberImpl(jabberProvider, this); + + whiteboardSessions.add(session); + + return session; + } + + /** + * Returns a reference to a WhiteboardSession named + * sessionName or null if no such session exists. + *
+ * @param sessionName the name of the WhiteboardSession that we're + * looking for. + * @return the WhiteboardSession named sessionName or null + * if no such session exists on the server that this provider is currently + * connected to. + * + * @throws OperationFailedException if an error occurs while trying to + * discover the white-board session on the server. + * @throws OperationNotSupportedException if the server does not support + * white-boarding + */ + public WhiteboardSession findWhiteboardSession(String sessionName) + throws OperationFailedException, + OperationNotSupportedException + { + // TODO: Implement findWhiteboardSession + return null; + } + + /** + * Returns a list of the white-board sessions that we have joined and are + * currently active in. + * + * @return a List of the white-board sessions where the user has + * joined using a given connection. + */ + public List getCurrentlyJoinedWhiteboards() + { + synchronized(whiteboardSessions) + { + List joinedWhiteboards + = new LinkedList(whiteboardSessions); + + Iterator joinedWhiteboardsIter = whiteboardSessions.iterator(); + + while (joinedWhiteboardsIter.hasNext()) + { + if (!((WhiteboardSession) joinedWhiteboardsIter.next()) + .isJoined()) + joinedWhiteboardsIter.remove(); + } + + return joinedWhiteboards; + } + } + + /** + * Returns a list of the WhiteboardSessions that + * WhiteboardParticipant has joined and is currently active in. + * + * @param participant the participant whose current + * WhiteboardSessions we will be querying. + * @return a list of the WhiteboardSessions that + * WhiteboardParticipant has joined and is currently active in. + * + * @throws OperationFailedException if an error occurs while trying to + * discover the session. + * @throws OperationNotSupportedException if the server does not support + * white-boarding + */ + public List getCurrentlyJoinedWhiteboards(WhiteboardParticipant participant) + throws OperationFailedException, + OperationNotSupportedException + { + // TODO: Implement getCurrentlyJoinedWhiteboards( + // WhiteboardParticipant participant) + return null; + } + + /** + * Returns true if contact supports white-board sessions. + * + * @param contact reference to the contact whose support for white-boards + * we are currently querying. + * @return a boolean indicating whether contact supports + * white-boards. + */ + public boolean isWhiteboardingSupportedByContact(Contact contact) + { + if(contact.getProtocolProvider() + .getOperationSet(OperationSetWhiteboarding.class) != null) + return true; + + return false; + } + + /** + * Informs the sender of an invitation that we decline their invitation. + * + * @param invitation the invitation we are rejecting. + * @param rejectReason the reason to reject the invitation (optional) + */ + public void rejectInvitation(WhiteboardInvitation invitation, + String rejectReason) + { + // TODO: Implement rejectInvitation(WhiteboardInvitation invitation, + // String rejectReason) + } + + /** + * Our listener that will tell us when we're registered to + */ + private class RegistrationStateListener + implements RegistrationStateChangeListener + { + /** + * The method is called by a ProtocolProvider implementation whenever + * a change in the registration state of the corresponding provider had + * occurred. + * @param evt ProviderStatusChangeEvent the event describing the status + * change. + */ + public void registrationStateChanged(RegistrationStateChangeEvent evt) + { + if (evt.getNewState() == RegistrationState.REGISTERED) + { + presenceOpSet + = (OperationSetPersistentPresenceJabberImpl) jabberProvider + .getOperationSet(OperationSetPresence.class); + + PacketExtensionFilter filterWhiteboard = + new PacketExtensionFilter( + WhiteboardObjectPacketExtensionImpl.ELEMENT_NAME, + WhiteboardObjectPacketExtensionImpl.NAMESPACE); + + jabberProvider.getConnection().addPacketListener( + new WhiteboardSmackMessageListener(), filterWhiteboard); + } + } + } + + /** + * Listens for white-board messages and checks if a white-board session + * already exists and if not simulates an invitation to the user. + */ + private class WhiteboardSmackMessageListener + implements PacketListener + { + public void processPacket(Packet packet) + { + if (!(packet instanceof org.jivesoftware.smack.packet.Message)) + return; + + PacketExtension ext = + packet.getExtension( + WhiteboardObjectPacketExtensionImpl.ELEMENT_NAME, + WhiteboardObjectPacketExtensionImpl.NAMESPACE); + + org.jivesoftware.smack.packet.Message msg = + (org.jivesoftware.smack.packet.Message) packet; + + if (ext == null) + return; + + String fromUserID = StringUtils.parseBareAddress(msg.getFrom()); + + // We check if a white-board session with the given contact already + // exists and if this is the case we don't continue. + for (int i = 0; i < whiteboardSessions.size(); i ++) + { + WhiteboardSessionJabberImpl session + = (WhiteboardSessionJabberImpl) whiteboardSessions.get(i); + + // Should be replaced by getParticipants when implementing + // the multi user white-boarding + if(session.isJoined() + && session.isParticipantContained(fromUserID)) + return; + } + + // If we're here this means that no white board session has been + // found and we will send an invitation to the user to join a + // white-board session created by us. + WhiteboardObjectPacketExtensionImpl newMessage + = (WhiteboardObjectPacketExtensionImpl) ext; + + WhiteboardSessionJabberImpl session + = new WhiteboardSessionJabberImpl( + jabberProvider, + OperationSetWhiteboardingJabberImpl.this); + + whiteboardSessions.add(session); + + ContactJabberImpl sourceContact + = (ContactJabberImpl) presenceOpSet.findContactByID(fromUserID); + + if (sourceContact == null) + { + logger.debug("Received a message from an unknown contact: " + + fromUserID); + + //create the volatile contact + sourceContact + = presenceOpSet.createVolatileContact(fromUserID); + } + + session.addWhiteboardParticipant( + new WhiteboardParticipantJabberImpl(sourceContact, session)); + + fireInvitationEvent(session, + newMessage.getWhiteboardObject(), + fromUserID, + null, + null); + } + } + + /** + * Delivers a WhiteboardInvitationEvent to all + * registered WhiteboardInvitationListeners. + * + * @param targetWhiteboard the white-board that invitation refers to + * @param whiteboardObject the white-board object that inviter send + * with this invitation and which will be shown on the white-board if the + * user accepts the invitation + * @param inviter the inviter that sent the invitation + * @param reason the reason why the inviter sent the invitation + * @param password the password to use when joining the room + */ + public void fireInvitationEvent(WhiteboardSession targetWhiteboard, + WhiteboardObject whiteboardObject, + String inviter, + String reason, + byte[] password) + { + WhiteboardInvitationJabberImpl invitation + = new WhiteboardInvitationJabberImpl( targetWhiteboard, + whiteboardObject, + inviter, + reason, + password); + + WhiteboardInvitationReceivedEvent evt + = new WhiteboardInvitationReceivedEvent(this, invitation, + new Date(System.currentTimeMillis())); + + logger.debug("Dispatching a WhiteboardInvitation event to " + + invitationListeners.size() + " listeners. event is: " + + evt.toString()); + + Iterator listeners = null; + synchronized (invitationListeners) + { + listeners = new ArrayList(invitationListeners).iterator(); + } + + while (listeners.hasNext()) + { + WhiteboardInvitationListener listener + = (WhiteboardInvitationListener) listeners.next(); + + listener.invitationReceived(evt); + } + } + + /** + * Delivers a WhiteboardSessionPresenceChangeEvent to all + * registered WhiteboardSessionPresenceChangeEvents. + * + * @param session the WhiteboardSession which has been joined, + * left, etc. + * @param eventType the type of this event; one of LOCAL_USER_JOINED, + * LOCAL_USER_LEFT, etc. + * @param reason the reason + */ + public void fireWhiteboardSessionPresenceEvent( WhiteboardSession session, + String eventType, + String reason) + { + WhiteboardSessionPresenceChangeEvent evt + = new WhiteboardSessionPresenceChangeEvent( this, + session, + eventType, + reason); + + Iterator listeners = null; + synchronized (presenceListeners) + { + listeners = new ArrayList(presenceListeners).iterator(); + } + + while (listeners.hasNext()) + { + WhiteboardSessionPresenceListener listener + = (WhiteboardSessionPresenceListener) listeners.next(); + + listener.whiteboardSessionPresenceChanged(evt); + } + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/WhiteboardInvitationJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/WhiteboardInvitationJabberImpl.java new file mode 100644 index 000000000..1675ac8ce --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/WhiteboardInvitationJabberImpl.java @@ -0,0 +1,111 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.whiteboardobjects.*; + +/** + * The Jabber implementation of the WhiteboardInvitation interface. + * + * @author Yana Stamcheva + */ +public class WhiteboardInvitationJabberImpl + implements WhiteboardInvitation +{ + private WhiteboardSession whiteboardSession; + + private WhiteboardObject firstWhiteboardObject; + + private String inviter; + + private String reason; + + private byte[] password; + + /** + * Creates an invitation for the given targetWhiteboard, from the + * given inviter. + * + * @param targetWhiteboard the WhiteboardSession for which the + * invitation is + * @param firstWhiteboardObject the white-board object that inviter send + * with this invitation and which will be shown on the white-board if the + * user accepts the invitation + * @param inviter the WhiteboardParticipant, which sent the + * invitation + * @param reason the reason of the invitation + * @param password the password to use to join the given white-board + */ + public WhiteboardInvitationJabberImpl( + WhiteboardSession targetWhiteboard, + WhiteboardObject firstWhiteboardObject, + String inviter, + String reason, + byte[] password) + { + this.whiteboardSession = targetWhiteboard; + this.firstWhiteboardObject = firstWhiteboardObject; + this.inviter = inviter; + this.reason = reason; + this.password = password; + } + + /** + * Returns the WhiteboardSession, that this invitation is about. + * + * @return the WhiteboardSession, that this invitation is about + */ + public WhiteboardSession getTargetWhiteboard() + { + return whiteboardSession; + } + + /** + * Returns the inviter, who sent this invitation. + * + * @return the inviter, who sent this invitation + */ + public String getInviter() + { + return inviter; + } + + /** + * Returns the reason of the invitation. + * + * @return the reason of the invitation + */ + public String getReason() + { + return reason; + } + + /** + * Returns the password to use in order to join the white-board, that this + * invitation is about. + * + * @return the password to use in order to join the white-board, that this + * invitation is about. + */ + public byte[] getWhiteboardPassword() + { + return password; + } + + /** + * Returns the first white-board object that the inviter would like to + * exchange with the user. If the user accepts this invitation he/she + * should see this object on his white-board. + * + * @return the first white-board object + */ + public WhiteboardObject getWhiteboardInitialObject() + { + return firstWhiteboardObject; + } +} \ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/WhiteboardParticipantJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/WhiteboardParticipantJabberImpl.java new file mode 100644 index 000000000..dff702a73 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/WhiteboardParticipantJabberImpl.java @@ -0,0 +1,420 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import java.util.*; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +/** + * The WhiteboardParticipantJabberImpl is a class that represents participants + * in a whiteboard. + * + * @author Julien Waechter + */ +public class WhiteboardParticipantJabberImpl + implements WhiteboardParticipant +{ + + private static final Logger logger = + Logger.getLogger(WhiteboardParticipantJabberImpl.class); + + /** + * The participant + */ + private ContactJabberImpl participant = null; + + /** + * The state of the whiteboard participant. + */ + protected WhiteboardParticipantState whiteboardParticipantState = + WhiteboardParticipantState.UNKNOWN; + + /** + * Indicates the date when is whiteboard participant passed into its current + * state. + */ + protected Date currentStateStartDate = new Date(); + + /** + * A byte array containing the image/photo representing the whiteboard + * participant. + */ + private byte[] image; + + /** + * A string uniquely identifying the participant. + */ + private String participantID; + + /** + * The whiteboard this participant belongs to. + */ + private WhiteboardSessionJabberImpl whiteboard; + + /** + * Creates a new whiteboard participant with address + * participantAddress. + * + * @param participant the JAIN SIP Address of the new whiteboard + * participant. + * + * @param owningWhiteboard the whiteboard that contains this whiteboard + * participant. + */ + public WhiteboardParticipantJabberImpl(ContactJabberImpl participant, + WhiteboardSessionJabberImpl owningWhiteboard) + { + this.participant = participant; + this.whiteboard = owningWhiteboard; + whiteboard.addWhiteboardParticipant(this); + + // create the uid + this.participantID = + String.valueOf(System.currentTimeMillis()) + + String.valueOf(hashCode()); + } + + /** + * Returns the contact identifier representing this contact. + * + * @return a String contact address + */ + public String getContactAddress() + { + return this.participant.getAddress(); + } + + /** + * Returns an object representing the current state of that participant. + * WhiteboardParticipantState may vary among CONNECTING, BUSY, CONNECTED... + * + * @return a WhiteboardParticipantState instance representin the + * participant's state. + */ + public WhiteboardParticipantState getState() + { + return whiteboardParticipantState; + } + + /** + * Causes this WhiteboardParticipant to enter the specified state. The + * method also sets the currentStateStartDate field and fires a + * WhiteboardParticipantChangeEvent. + * + * @param newState the state this whiteboard participant should enter. + * @param reason a string that could be set to contain a human readable + * explanation for the transition (particularly handy when moving + * into a FAILED state). + */ + protected void setState(WhiteboardParticipantState newState, String reason) + { + WhiteboardParticipantState oldState = getState(); + + if (oldState == newState) + return; + + this.whiteboardParticipantState = newState; + this.currentStateStartDate = new Date(); + fireWhiteboardParticipantChangeEvent( + WhiteboardParticipantChangeEvent.WHITEBOARD_PARTICIPANT_STATE_CHANGE, + oldState, newState); + } + + /** + * Causes this WhiteboardParticipant to enter the specified state. The + * method also sets the currentStateStartDate field and fires a + * WhiteboardParticipantChangeEvent. + * + * @param newState the state this whiteboard participant should enter. + */ + protected void setState(WhiteboardParticipantState newState) + { + setState(newState, null); + } + + /** + * Returns the date (time) when this whiteboard participant acquired its + * current status. + * + * @return a java.util.Date object containing the date when this whiteboard + * participant entered its current state. + */ + public Date getCurrentStateStartDate() + { + return currentStateStartDate; + } + + /** + * Returns a human readable name representing this participant. + * + * @return a String containing a name for that participant. + */ + public String getDisplayName() + { + String displayName = participant.getDisplayName(); + return (displayName == null) ? "" : displayName; + } + + /** + * Sets a human readable name representing this participant. + * + * @param displayName the participant's display name + */ + protected void setDisplayName(String displayName) + { + String oldName = getDisplayName(); + /* + * try { this.participant.setDisplayName(displayName); } catch + * (ParseException ex) { //couldn't happen logger.error(ex.getMessage(), + * ex); throw new IllegalArgumentException(ex.getMessage()); } + */ + // Fire the Event + fireWhiteboardParticipantChangeEvent( + WhiteboardParticipantChangeEvent.WHITEBOARD_PARTICIPANT_DISPLAY_NAME_CHANGE, + oldName, displayName); + } + + /** + * The method returns an image representation of the whiteboard participant + * (e.g. + * + * @return byte[] a byte array containing the image or null if no image is + * available. + */ + public byte[] getImage() + { + return image; + } + + /** + * Sets the byte array containing an image representation (photo or picture) + * of the whiteboard participant. + * + * @param image a byte array containing the image + */ + protected void setImage(byte[] image) + { + byte[] oldImage = getImage(); + this.image = image; + + // Fire the Event + fireWhiteboardParticipantChangeEvent( + WhiteboardParticipantChangeEvent.WHITEBOARD_PARTICIPANT_IMAGE_CHANGE, + oldImage, image); + } + + /** + * Returns a unique identifier representing this participant. + * + * @return an identifier representing this whiteboard participant. + */ + public String getParticipantID() + { + return participantID; + } + + /** + * Sets the String that serves as a unique identifier of this + * WhiteboardParticipant. + * + * @param participantID the ID of this whiteboard participant. + */ + protected void setParticipantID(String participantID) + { + this.participantID = participantID; + } + + /** + * Returns the chat room that this member is participating in. + * + * @return the WhiteboardSession instance that this member + * belongs to. + */ + public WhiteboardSession getWhiteboardSession() + { + return whiteboard; + } + + /** + * Sets the whiteboard containing this participant. + * + * @param whiteboard the whiteboard that this whiteboard participant is + * partdicipating in. + */ + protected void setWhiteboard(WhiteboardSessionJabberImpl whiteboard) + { + this.whiteboard = whiteboard; + } + + /** + * Returns the protocol provider instance that this member has originated + * in. + * + * @return the ProtocolProviderService instance that created this + * member and its containing cht room + */ + public ProtocolProviderService getProtocolProvider() + { + return this.getWhiteboardSession().getProtocolProvider(); + } + + /** + * Returns the contact corresponding to this participant or null if no + * particular contact has been associated. + *
+ *
+ * @return the Contact corresponding to this participant or null
+ * if no particular contact has been associated.
+ */
+ public Contact getContact()
+ {
+ return this.participant;
+ }
+
+ /**
+ * All the WhiteboardParticipant listeners registered with this
+ * WhiteboardParticipant.
+ */
+ protected ArrayList whiteboardParticipantListeners = new ArrayList();
+
+ /**
+ * Allows the user interface to register a listener interested in changes
+ *
+ * @param listener a listener instance to register with this participant.
+ */
+ public void addWhiteboardParticipantListener(
+ WhiteboardParticipantListener listener)
+ {
+ synchronized (whiteboardParticipantListeners)
+ {
+ if (!whiteboardParticipantListeners.contains(listener))
+ this.whiteboardParticipantListeners.add(listener);
+ }
+ }
+
+ /**
+ * Unregisters the specified listener.
+ *
+ * @param listener the listener to unregister.
+ */
+ public void removeWhiteboardParticipantListener(
+ WhiteboardParticipantListener listener)
+ {
+
+ synchronized (whiteboardParticipantListeners)
+ {
+ if (listener == null)
+ return;
+ whiteboardParticipantListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Constructs a WhiteboardParticipantChangeEvent using this
+ * whiteboard participant as source, setting it to be of type
+ * eventType and the corresponding oldValue and
+ * newValue,
+ *
+ * @param eventType the type of the event to create and dispatch.
+ * @param oldValue the value of the source property before it changed.
+ * @param newValue the current value of the source property.
+ */
+ protected void fireWhiteboardParticipantChangeEvent(String eventType,
+ Object oldValue, Object newValue)
+ {
+ this.fireWhiteboardParticipantChangeEvent(eventType, oldValue,
+ newValue, null);
+ }
+
+ /**
+ * Constructs a WhiteboardParticipantChangeEvent using this
+ * whiteboard participant as source, setting it to be of type
+ * eventType and the corresponding oldValue and
+ * newValue,
+ *
+ * @param eventType the type of the event to create and dispatch.
+ * @param oldValue the value of the source property before it changed.
+ * @param newValue the current value of the source property.
+ * @param reason a string that could be set to contain a human readable
+ * explanation for the transition (particularly handy when moving
+ * into a FAILED state).
+ */
+ protected void fireWhiteboardParticipantChangeEvent(String eventType,
+ Object oldValue, Object newValue, String reason)
+ {
+ WhiteboardParticipantChangeEvent evt =
+ new WhiteboardParticipantChangeEvent(this, eventType, oldValue,
+ newValue, reason);
+
+ logger.debug("Dispatching a WhiteboardParticipantChangeEvent event to "
+ + whiteboardParticipantListeners.size() + " listeners. event is: "
+ + evt.toString());
+
+ Iterator listeners = null;
+ synchronized (whiteboardParticipantListeners)
+ {
+ listeners =
+ new ArrayList(whiteboardParticipantListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ WhiteboardParticipantListener listener =
+ (WhiteboardParticipantListener) listeners.next();
+
+ if (eventType
+ .equals(WhiteboardParticipantChangeEvent.WHITEBOARD_PARTICIPANT_DISPLAY_NAME_CHANGE))
+ {
+ listener.participantDisplayNameChanged(evt);
+ }
+ else if (eventType
+ .equals(WhiteboardParticipantChangeEvent.WHITEBOARD_PARTICIPANT_IMAGE_CHANGE))
+ {
+ listener.participantImageChanged(evt);
+ }
+ else if (eventType
+ .equals(WhiteboardParticipantChangeEvent.WHITEBOARD_PARTICIPANT_STATE_CHANGE))
+ {
+ listener.participantStateChanged(evt);
+ }
+ }
+ }
+
+ /**
+ * Returns a string representation of the participant in the form of
+ * Display Name
+ * If the room is password-protected, the invitee will receive a password to
+ * use to join the room. If the room is members-only, the the invitee may
+ * be added to the member list.
+ *
+ * @param contactAddress the address of the user to invite to the room.
+ * (one may also invite users not on their contact list).
+ */
+ public void invite(String contactAddress)
+ {
+ OperationSetPersistentPresenceJabberImpl presenceOpSet
+ = (OperationSetPersistentPresenceJabberImpl) jabberProvider
+ .getOperationSet(OperationSetPresence.class);
+
+ // If there's no presence operation set we return, because there's
+ // not contact to associate the event with.
+ if (presenceOpSet == null)
+ return;
+
+ ContactJabberImpl sourceContact
+ = (ContactJabberImpl) presenceOpSet.findContactByID(contactAddress);
+
+ if (sourceContact == null)
+ {
+ sourceContact = presenceOpSet.createVolatileContact(contactAddress);
+ }
+
+ this.addWhiteboardParticipant(
+ new WhiteboardParticipantJabberImpl(sourceContact, this));
+
+ try
+ {
+ System.out.println("SEND WHITE BOARD OBJECT");
+ sendWhiteboardObject(
+ createWhiteboardObject(WhiteboardObjectLine.NAME));
+ }
+ catch (OperationFailedException e)
+ {
+ logger.error("Could not send an invite whiteboard object.", e);
+ }
+ }
+
+ /**
+ * returns the current WhiteboardSession
+ * @return current WhiteboardSession
+ */
+ public WhiteboardSession getWhiteboardSession()
+ {
+ return this;
+ }
+
+ /**
+ * Verifies whether the whiteboard participant has entered a state.
+ *
+ * @param evt The WhiteboardParticipantChangeEvent instance
+ * containing the source event as well as its previous and its new status.
+ */
+ public void participantStateChanged(WhiteboardParticipantChangeEvent evt)
+ {
+ if (((WhiteboardParticipantState) evt.getNewValue())
+ == WhiteboardParticipantState.DISCONNECTED
+ || ((WhiteboardParticipantState) evt.getNewValue())
+ == WhiteboardParticipantState.FAILED)
+ {
+ removeWhiteboardParticipant((WhiteboardParticipantJabberImpl) evt
+ .getSourceWhiteboardParticipant());
+ }
+ }
+
+ /**
+ * Indicates that a change has occurred in the display name of the source
+ * WhiteboardParticipant.
+ *
+ * @param evt The WhiteboardParticipantChangeEvent instance
+ * containing the source event as well as its previous and its new display
+ * names.
+ */
+ public void participantDisplayNameChanged(
+ WhiteboardParticipantChangeEvent evt)
+ {
+ }
+
+ /**
+ * Indicates that a change has occurred in the address of the source
+ * WhiteboardParticipant.
+ *
+ * @param evt The WhiteboardParticipantChangeEvent instance
+ * containing the source event as well as its previous and its new address.
+ */
+ public void participantAddressChanged(WhiteboardParticipantChangeEvent evt)
+ {
+ }
+
+ /**
+ * Indicates that a change has occurred in the transport address that we
+ * use to communicate with the participant.
+ *
+ * @param evt The WhiteboardParticipantChangeEvent instance
+ * containing the source event as well as its previous and its new transport
+ * address.
+ */
+ public void participantTransportAddressChanged(
+ WhiteboardParticipantChangeEvent evt)
+ {
+ }
+
+ /**
+ * Indicates that a change has occurred in the image of the source
+ * WhiteboardParticipant.
+ *
+ * @param evt The WhiteboardParticipantChangeEvent instance
+ * containing the source event as well as its previous and its new image.
+ */
+ public void participantImageChanged(WhiteboardParticipantChangeEvent evt)
+ {
+ }
+
+ /**
+ * Adds wbParticipant to the list of participants in this
+ * white-board.
+ * If the white-board participant is already included in the white-board,
+ * the method has no effect.
+ *
+ * @param wbParticipant the new WhiteboardParticipant
+ */
+ public void addWhiteboardParticipant(WhiteboardParticipant wbParticipant)
+ {
+ if (wbParticipants.contains(wbParticipant))
+ return;
+
+ wbParticipant.addWhiteboardParticipantListener(this);
+
+ this.wbParticipants.put(
+ wbParticipant.getContactAddress(), wbParticipant);
+
+ fireWhiteboardParticipantEvent(wbParticipant,
+ WhiteboardParticipantEvent.WHITEBOARD_PARTICIPANT_ADDED);
+ }
+
+ /**
+ * Removes whiteboardParticipant from the list of participants in
+ * this whiteboard. The method has no effect if there was no
+ * such participant in the whiteboard.
+ *
+ * @param wbParticipant the WhiteboardParticipant leaving the
+ * whiteboard;
+ */
+ public void removeWhiteboardParticipant(WhiteboardParticipant wbParticipant)
+ {
+ if (!wbParticipants.contains(wbParticipant))
+ return;
+
+ this.wbParticipants.remove(wbParticipant);
+
+ if (wbParticipant instanceof WhiteboardParticipantJabberImpl)
+ ((WhiteboardParticipantJabberImpl) wbParticipant)
+ .setWhiteboardSession(null);
+
+ wbParticipant.removeWhiteboardParticipantListener(this);
+
+ fireWhiteboardParticipantEvent(wbParticipant,
+ WhiteboardParticipantEvent.WHITEBOARD_PARTICIPANT_REMVOVED);
+
+ if (wbParticipants.size() == 0)
+ setWhiteboardSessionState(WhiteboardSessionState.WHITEBOARD_ENDED);
+ }
+
+ /**
+ * Sets the state of this whiteboard and fires a whiteboard change event
+ * notifying registered listeners for the change.
+ *
+ * @param newState a reference to the WhiteboardState instance that
+ * the whiteboard is to enter.
+ */
+ public void setWhiteboardSessionState(WhiteboardSessionState newState)
+ {
+ WhiteboardSessionState oldState = getWhiteboardSessionState();
+
+ if (oldState == newState)
+ return;
+
+ this.whiteboardState = newState;
+
+ fireWhiteboardChangeEvent(
+ WhiteboardChangeEvent.WHITEBOARD_STATE_CHANGE, oldState, newState);
+ }
+
+ /**
+ * Returns the state that this whiteboard is currently in.
+ * @return a reference to the WhiteboardState
+ * instance that the whiteboard is currently in.
+ */
+ public WhiteboardSessionState getWhiteboardSessionState()
+ {
+ return whiteboardState;
+ }
+
+ /**
+ * Registers listener so that it would receive events every time a
+ * new WhiteboardObject is received on this whiteboard.
+ *
+ *
+ * @param listener a WhiteboardObjectListener that would be
+ * notified every time a new WhiteboardObject
+ * is received on this whiteboard.
+ */
+ public void addWhiteboardObjectListener(WhiteboardObjectListener listener)
+ {
+ synchronized (messageListeners)
+ {
+ if (!messageListeners.contains(listener))
+ {
+ this.messageListeners.add(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes listener so that it won't receive
+ * any further WhiteboardObject events from this room.
+ *
+ *
+ * @param listener the WhiteboardObjectListener
+ * to remove from this room
+ */
+ public void removeWhiteboardObjectListener(
+ WhiteboardObjectListener listener)
+ {
+ synchronized (messageListeners)
+ {
+ this.messageListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Create a WhiteboardObject instance with the specified type. This method
+ * only creates the object locally and it would not be visible to other
+ * session participants until it is resolved with the
+ * sendWhiteboardObject(WhiteboardObject) method.
+ *
+ * @param name the name of the object to create (should be one of the
+ * WhiteboardObjectXXX.NAME fields).
+ *
+ * @return the newly created WhiteboardObject with an id
+ */
+ public WhiteboardObject createWhiteboardObject(String name)
+ {
+ WhiteboardObjectJabberImpl wbObj = null;
+ logger.debug("[log] WhiteboardObjectXXX.NAME: " + name);
+ if (name.equals(WhiteboardObjectPath.NAME))
+ {
+ wbObj = new WhiteboardObjectPathJabberImpl();
+ }
+ else if (name.equals(WhiteboardObjectPolyLine.NAME))
+ {
+ wbObj = new WhiteboardObjectPolyLineJabberImpl();
+ }
+ else if (name.equals(WhiteboardObjectPolygon.NAME))
+ {
+ wbObj = new WhiteboardObjectPolygonJabberImpl();
+ }
+ else if (name.equals(WhiteboardObjectLine.NAME))
+ {
+ wbObj = new WhiteboardObjectLineJabberImpl();
+ }
+ else if (name.equals(WhiteboardObjectRect.NAME))
+ {
+ wbObj = new WhiteboardObjectRectJabberImpl();
+ }
+ else if (name.equals(WhiteboardObjectCircle.NAME))
+ {
+ wbObj = new WhiteboardObjectCircleJabberImpl();
+ }
+ else if (name.equals(WhiteboardObjectText.NAME))
+ {
+ wbObj = new WhiteboardObjectTextJabberImpl();
+ }
+ else if (name.equals(WhiteboardObjectImage.NAME))
+ {
+ wbObj = new WhiteboardObjectImageJabberImpl();
+ }
+ whiteboardObjects.add(wbObj);
+ return wbObj;
+ }
+
+ /**
+ * Returns the id of the specified Whiteboard.
+ *
+ * @return a String uniquely identifying the whiteboard.
+ */
+ public String getWhiteboardID()
+ {
+ return whiteboardID;
+ }
+
+ /**
+ * Determines wheter the protocol provider (or the protocol itself) support
+ * sending and receiving offline messages. Most often this method would
+ * return true for protocols that support offline messages and false for
+ * those that don't. It is however possible for a protocol to support these
+ * messages and yet have a particular account that does not (i.e. feature
+ * not enabled on the protocol server). In cases like this it is possible
+ * for this method to return true even when offline messaging is not
+ * supported, and then have the sendMessage method throw an
+ * OperationFailedException with code - OFFLINE_MESSAGES_NOT_SUPPORTED.
+ *
+ * @return true if the protocol supports offline messages and
+ * false otherwise.
+ */
+ public boolean isOfflineMessagingSupported()
+ {
+ return true;
+ }
+
+ /**
+ * Sends a WhiteboardObject to modify
+ * and modifies the local WhiteboardObject
+ *
+ * @param obj the WhiteboardObject to send and modify
+ * @throws OperationFailedException if sending
+ * the WhiteboardObject fails for some reason.
+ */
+ public void moveWhiteboardObject(WhiteboardObject obj)
+ throws OperationFailedException
+ {
+ WhiteboardObject wbObj = updateWhiteboardObjects(obj);
+ if (wbObj != null)
+ sendWhiteboardObject(wbObj);
+ }
+
+ /**
+ * Sends a WhiteboardObject to delete
+ * and delete the local WhiteboardObject
+ *
+ * @param obj the WhiteboardObject to send and delete
+ * @throws OperationFailedException if sending
+ * the WhiteboardObject fails for some reason.
+ */
+ public void deleteWhiteboardObject(WhiteboardObject obj)
+ throws OperationFailedException
+ {
+ Iterator participants = getWhiteboardParticipants();
+ if (!participants.hasNext())
+ return;
+
+ WhiteboardParticipantJabberImpl participant
+ = (WhiteboardParticipantJabberImpl) participants.next();
+
+ Contact contact = participant.getContact();
+
+ try
+ {
+ assertConnected();
+
+ org.jivesoftware.smack.MessageListener msgListener =
+ new org.jivesoftware.smack.MessageListener()
+ {
+ public void processMessage(Chat arg0,
+ org.jivesoftware.smack.packet.Message arg1)
+ {
+ }
+ };
+
+ Chat chat
+ = jabberProvider.getConnection().getChatManager()
+ .createChat(contact.getAddress(), msgListener);
+
+ org.jivesoftware.smack.packet.Message msg =
+ new org.jivesoftware.smack.packet.Message();
+
+ WhiteboardObjectPacketExtensionImpl messageJI =
+ new WhiteboardObjectPacketExtensionImpl(obj.getID(),
+ WhiteboardObjectPacketExtensionImpl.ACTION_DELETE);
+
+ msg.addExtension(messageJI);
+ msg.addExtension(new Version());
+
+ MessageEventManager.addNotificationsRequests(msg, true, false,
+ false, true);
+
+ chat.sendMessage(msg);
+
+ WhiteboardObjectDeliveredEvent msgDeliveredEvt =
+ new WhiteboardObjectDeliveredEvent(
+ this, obj, contact, new Date());
+
+ fireMessageEvent(msgDeliveredEvt);
+
+ int i = 0;
+ while (i < whiteboardObjects.size())
+ {
+ WhiteboardObjectJabberImpl wbObj =
+ (WhiteboardObjectJabberImpl) whiteboardObjects.get(i);
+ if (wbObj.getID().equals(obj.getID()))
+ whiteboardObjects.remove(i);
+ else
+ i++;
+ }
+ }
+ catch (XMPPException ex)
+ {
+ ex.printStackTrace();
+ logger.error("message not send", ex);
+ }
+
+ }
+
+ /**
+ * Sends the message to the destination indicated by the
+ * to contact.
+ * @param to the Contact to send message to
+ * @param message the Message to send.
+ * @throws java.lang.IllegalStateException if the underlying stack is
+ * not registered and initialized.
+ * @throws java.lang.IllegalArgumentException if to is not an
+ * instance of ContactImpl.
+ */
+ public void sendWhiteboardObject(WhiteboardObject message)
+ throws OperationFailedException
+ {
+ Iterator participants = getWhiteboardParticipants();
+
+ if (!participants.hasNext())
+ return;
+
+ WhiteboardParticipantJabberImpl participant
+ = (WhiteboardParticipantJabberImpl) participants.next();
+
+ Contact contact = participant.getContact();
+
+ try
+ {
+ assertConnected();
+
+ org.jivesoftware.smack.MessageListener msgListener =
+ new org.jivesoftware.smack.MessageListener()
+ {
+ public void processMessage(Chat arg0,
+ org.jivesoftware.smack.packet.Message arg1)
+ {
+ }
+ };
+
+ Chat chat =
+ jabberProvider.getConnection().getChatManager().createChat(
+ contact.getAddress(), msgListener);
+
+ org.jivesoftware.smack.packet.Message msg =
+ new org.jivesoftware.smack.packet.Message();
+
+ WhiteboardObjectPacketExtensionImpl messageJI =
+ new WhiteboardObjectPacketExtensionImpl(
+ (WhiteboardObjectJabberImpl) message,
+ WhiteboardObjectPacketExtensionImpl.ACTION_DRAW);
+
+ msg.addExtension(messageJI);
+ msg.addExtension(new Version());
+
+ MessageEventManager.addNotificationsRequests(msg, true, false,
+ false, true);
+
+ chat.sendMessage(msg);
+
+ WhiteboardObjectDeliveredEvent msgDeliveredEvt =
+ new WhiteboardObjectDeliveredEvent(
+ this, message, contact, new Date());
+
+ fireMessageEvent(msgDeliveredEvt);
+ }
+ catch (XMPPException ex)
+ {
+ ex.printStackTrace();
+ logger.error("message not send", ex);
+ }
+ }
+
+ /**
+ * Utility method throwing an exception if the stack is not properly
+ * initialized.
+ * @throws java.lang.IllegalStateException if the underlying stack is
+ * not registered and initialized.
+ */
+ private void assertConnected() throws IllegalStateException
+ {
+ if (jabberProvider == null)
+ throw new IllegalStateException(
+ "The provider must be non-null and signed on the "
+ + "service before being able to communicate.");
+ if (!jabberProvider.isRegistered())
+ throw new IllegalStateException(
+ "The provider must be signed on the service before "
+ + "being able to communicate.");
+ }
+
+ /**
+ * Compares the specified object with this whiteboard and returns true if it
+ * the specified object is an instance of a Whiteboard object and if the
+ * extending telephony protocol considers the whiteboards represented by
+ * both objects to be the same.
+ *
+ * @param obj the whiteboard to compare this one with.
+ * @return true in case both objects are pertaining to the same whiteboard
+ * and false otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null || !(obj instanceof WhiteboardSession))
+ return false;
+ if (obj == this
+ || ((WhiteboardSession) obj).getWhiteboardID().equals(
+ getWhiteboardID()))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Returns a hash code value for this whiteboard.
+ *
+ * @return a hash code value for this whiteboard.
+ */
+ public int hashCode()
+ {
+ return getWhiteboardID().hashCode();
+ }
+
+ /**
+ * Returns a string textually representing this Whiteboard.
+ *
+ * @return a string representation of the object.
+ */
+ public String toString()
+ {
+ return "Whiteboard: id=" + getWhiteboardID() + " participants="
+ + getWhiteboardParticipantsCount();
+ }
+
+ /**
+ * Adds a whiteboard change listener to this whiteboard so that it could
+ * receive events on new whiteboard participants, theme changes and others.
+ *
+ * @param listener the listener to register
+ */
+ public void addWhiteboardChangeListener(WhiteboardChangeListener listener)
+ {
+ synchronized (whiteboardListeners)
+ {
+ if (!whiteboardListeners.contains(listener))
+ this.whiteboardListeners.add(listener);
+ }
+ }
+
+ /**
+ * Removes listener to this whiteboard so that it won't receive
+ * further WhiteboardChangeEvents.
+ *
+ * @param listener the listener to register
+ */
+ public void removeWhiteboardChangeListener(WhiteboardChangeListener listener)
+ {
+ synchronized (whiteboardListeners)
+ {
+ this.whiteboardListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Returns a reference to the ProtocolProviderService instance
+ * that created this whiteboard.
+ *
+ * @return a reference to the ProtocolProviderService instance that
+ * created this whiteboard.
+ */
+ public ProtocolProviderService getProtocolProvider()
+ {
+ return this.jabberProvider;
+ }
+
+ /**
+ * Creates a WhiteboardParticipantEvent with
+ * sourceWhiteboardParticipant and eventID and dispatches
+ * it on all currently registered listeners.
+ *
+ * @param sourceWhiteboardParticipant the source
+ * WhiteboardParticipant for the newly created event.
+ * @param eventID the ID of the event to create (see CPE member ints)
+ */
+ public void fireWhiteboardParticipantEvent(
+ WhiteboardParticipant sourceWhiteboardParticipant, int eventID)
+ {
+
+ WhiteboardParticipantEvent cpEvent =
+ new WhiteboardParticipantEvent(this, sourceWhiteboardParticipant,
+ eventID);
+
+ logger.debug("Dispatching a WhiteboardParticipant event to "
+ + whiteboardListeners.size() + " listeners. event is: "
+ + cpEvent.toString());
+
+ Iterator listeners = null;
+ synchronized (whiteboardListeners)
+ {
+ listeners = new ArrayList(whiteboardListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ WhiteboardChangeListener listener =
+ (WhiteboardChangeListener) listeners.next();
+
+ if (eventID
+ == WhiteboardParticipantEvent
+ .WHITEBOARD_PARTICIPANT_ADDED)
+ listener.whiteboardParticipantAdded(cpEvent);
+ else if (eventID
+ == WhiteboardParticipantEvent
+ .WHITEBOARD_PARTICIPANT_REMVOVED)
+ listener.whiteboardParticipantRemoved(cpEvent);
+
+ }
+ }
+
+ /**
+ * Creates a WhiteboardChangeEvent with this class as
+ * sourceWhiteboard, and the specified eventID and old
+ * and new values and dispatches it on all currently registered listeners.
+ *
+ * @param type the type of the event to create (see WhiteboardChangeEvent
+ * member ints)
+ * @param oldValue the value of the Whiteboard property that changed, before
+ * the event had occurred.
+ * @param newValue the value of the Whiteboard property that changed, after
+ * the event has occurred.
+ */
+ public void fireWhiteboardChangeEvent(String type, Object oldValue,
+ Object newValue)
+ {
+ WhiteboardChangeEvent ccEvent =
+ new WhiteboardChangeEvent(this, type, oldValue, newValue);
+
+ logger.debug("Dispatching a WhiteboardChange event to "
+ + whiteboardListeners.size() + " listeners. event is: "
+ + ccEvent.toString());
+
+ Iterator listeners = null;
+ synchronized (whiteboardListeners)
+ {
+ listeners = new ArrayList(whiteboardListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ WhiteboardChangeListener listener =
+ (WhiteboardChangeListener) listeners.next();
+
+ if (type.equals(WhiteboardChangeEvent.WHITEBOARD_STATE_CHANGE))
+ listener.whiteboardStateChanged(ccEvent);
+ }
+ }
+
+ /**
+ * Returns the WhiteboardObjects in this whiteboard session.
+ * @return an Vector of WhiteboardObjects associated
+ * with this whiteboard.
+ */
+ public Vector getWhiteboardObjects()
+ {
+ return whiteboardObjects;
+ }
+
+ /**
+ * Sets the state of this whiteboard
+ *
+ * @param newState a reference to the WhiteboardState instance that
+ * the whiteboard is to enter.
+ */
+ public void setState(WhiteboardSessionState newState)
+ {
+ this.whiteboardState = newState;
+ }
+
+ /**
+ * Returns the state that this whiteboard is currently in.
+ *
+ * @return a reference to the WhiteboardState instance
+ * that the whiteboard is currently in.
+ */
+ public WhiteboardSessionState getState()
+ {
+ return this.whiteboardState;
+ }
+
+ /**
+ * Delivers the specified event to all registered message listeners.
+ * @param evt the EventObject that we'd like delivered to all
+ * registered message listeners.
+ */
+ public void fireMessageEvent(EventObject evt)
+ {
+ logger.debug("Dispatching a WhiteboardMessageEvent event to "
+ + messageListeners.size() + " listeners. event is: "
+ + evt.toString());
+
+ Iterator listeners = null;
+ synchronized (messageListeners)
+ {
+ listeners = new ArrayList(messageListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ WhiteboardObjectListener listener =
+ (WhiteboardObjectListener) listeners.next();
+
+ if (evt instanceof WhiteboardObjectDeliveredEvent)
+ {
+ listener.whiteboardObjectDelivered(
+ (WhiteboardObjectDeliveredEvent) evt);
+ }
+ else if (evt instanceof WhiteboardObjectReceivedEvent)
+ {
+ WhiteboardObjectJabberImpl wbObj =
+ (WhiteboardObjectJabberImpl) (
+ (WhiteboardObjectReceivedEvent) evt)
+ .getSourceWhiteboardObject();
+ /*
+ for(int i = 0; i < whiteboardObjects.size (); i++)
+ {
+ WhiteboardObjectJabberImpl obj =
+ (WhiteboardObjectJabberImpl) whiteboardObjects.get (i);
+ if(wbObj.getID ().equals (obj.getID ()))
+ {
+ whiteboardObjects.set (i, wbObj);
+ listener.whiteboardObjecModified (
+ (WhiteboardObjectModifiedEvent) evt);
+ return;
+ }
+ }
+ */
+ listener.whiteboardObjectReceived(
+ (WhiteboardObjectReceivedEvent) evt);
+
+ whiteboardObjects.add(wbObj);
+ }
+ else if (evt instanceof WhiteboardObjectDeletedEvent)
+ {
+ String wbObjID = ((WhiteboardObjectDeletedEvent) evt).getId();
+
+ listener
+ .whiteboardObjectDeleted((WhiteboardObjectDeletedEvent) evt);
+ int i = 0;
+ while (i < whiteboardObjects.size())
+ {
+ WhiteboardObjectJabberImpl wbObj
+ = (WhiteboardObjectJabberImpl) whiteboardObjects.get(i);
+ if (wbObj.getID().equals(wbObjID))
+ whiteboardObjects.remove(i);
+ else
+ i++;
+ }
+
+ }
+ else if (evt instanceof WhiteboardObjectModifiedEvent)
+ {
+ WhiteboardObjectJabberImpl wbObj
+ = (WhiteboardObjectJabberImpl)
+ ((WhiteboardObjectReceivedEvent) evt)
+ .getSourceWhiteboardObject();
+
+ listener.whiteboardObjecModified(
+ (WhiteboardObjectModifiedEvent) evt);
+
+ whiteboardObjects.remove(wbObj);//remove the old id object
+ whiteboardObjects.add(wbObj); //add the new object for this id
+ }
+ else if (evt instanceof WhiteboardObjectDeliveryFailedEvent)
+ {
+ listener.whiteboardObjectDeliveryFailed(
+ (WhiteboardObjectDeliveryFailedEvent) evt);
+ }
+ }
+ }
+
+ private WhiteboardObject updateWhiteboardObjects(WhiteboardObject ws)
+ {
+ WhiteboardObjectJabberImpl wbObj = null;
+ int i = 0;
+ while (i < whiteboardObjects.size())
+ {
+ WhiteboardObjectJabberImpl wbObjTmp =
+ (WhiteboardObjectJabberImpl) whiteboardObjects.get(i);
+ if (wbObjTmp.getID().equals(ws.getID()))
+ {
+ wbObj = wbObjTmp;
+ break;
+ }
+ else
+ i++;
+ }
+ if (wbObj == null)
+ return null;
+
+ if (ws instanceof WhiteboardObjectPath)
+ {
+ WhiteboardObjectPathJabberImpl obj =
+ (WhiteboardObjectPathJabberImpl) wbObj;
+ obj.setPoints(((WhiteboardObjectPath) ws).getPoints());
+ obj.setColor(ws.getColor());
+ obj.setThickness(ws.getThickness());
+ }
+ else if (ws instanceof WhiteboardObjectPolyLine)
+ {
+ WhiteboardObjectPolyLineJabberImpl obj =
+ (WhiteboardObjectPolyLineJabberImpl) wbObj;
+ obj.setPoints(((WhiteboardObjectPolyLine) ws).getPoints());
+ obj.setColor(ws.getColor());
+ obj.setThickness(ws.getThickness());
+ }
+ else if (ws instanceof WhiteboardObjectPolygon)
+ {
+ WhiteboardObjectPolygonJabberImpl obj =
+ (WhiteboardObjectPolygonJabberImpl) wbObj;
+ obj.setPoints(((WhiteboardObjectPolygon) ws).getPoints());
+ obj.setBackgroundColor(((WhiteboardObjectPolygon) ws)
+ .getBackgroundColor());
+ obj.setFill(((WhiteboardObjectPolygon) ws).isFill());
+ obj.setColor(ws.getColor());
+ obj.setThickness(ws.getThickness());
+ }
+ else if (ws instanceof WhiteboardObjectLine)
+ {
+ WhiteboardObjectLineJabberImpl obj =
+ (WhiteboardObjectLineJabberImpl) wbObj;
+ obj.setWhiteboardPointStart(((WhiteboardObjectLine) ws)
+ .getWhiteboardPointStart());
+ obj.setWhiteboardPointEnd(((WhiteboardObjectLine) ws)
+ .getWhiteboardPointEnd());
+ obj.setColor(ws.getColor());
+ obj.setThickness(ws.getThickness());
+ }
+ else if (ws instanceof WhiteboardObjectRect)
+ {
+ WhiteboardObjectRectJabberImpl obj =
+ (WhiteboardObjectRectJabberImpl) wbObj;
+ obj.setFill(((WhiteboardObjectRect) ws).isFill());
+ obj.setHeight(((WhiteboardObjectRect) ws).getHeight());
+ obj.setWhiteboardPoint(((WhiteboardObjectRect) ws)
+ .getWhiteboardPoint());
+ obj.setWidth((((WhiteboardObjectRect) ws)).getWidth());
+ obj.setColor(ws.getColor());
+ obj.setThickness(ws.getThickness());
+ }
+ else if (ws instanceof WhiteboardObjectCircle)
+ {
+ WhiteboardObjectCircleJabberImpl obj =
+ (WhiteboardObjectCircleJabberImpl) wbObj;
+ obj.setFill(((WhiteboardObjectCircle) ws).isFill());
+ obj.setRadius(((WhiteboardObjectCircle) ws).getRadius());
+ obj.setWhiteboardPoint(((WhiteboardObjectCircle) ws)
+ .getWhiteboardPoint());
+ obj.setBackgroundColor((((WhiteboardObjectCircle) ws))
+ .getBackgroundColor());
+ obj.setColor(ws.getColor());
+ obj.setThickness(ws.getThickness());
+ }
+ else if (ws instanceof WhiteboardObjectText)
+ {
+ WhiteboardObjectTextJabberImpl obj =
+ (WhiteboardObjectTextJabberImpl) wbObj;
+ obj.setFontName(((WhiteboardObjectText) ws).getFontName());
+ obj.setFontSize(((WhiteboardObjectText) ws).getFontSize());
+ obj.setText(((WhiteboardObjectText) ws).getText());
+ obj.setWhiteboardPoint(((WhiteboardObjectText) ws)
+ .getWhiteboardPoint());
+ obj.setColor(ws.getColor());
+ obj.setThickness(ws.getThickness());
+ }
+ else if (ws instanceof WhiteboardObjectImage)
+ {
+ WhiteboardObjectImageJabberImpl obj =
+ (WhiteboardObjectImageJabberImpl) wbObj;
+ obj.setBackgroundImage(((WhiteboardObjectImage) ws)
+ .getBackgroundImage());
+ obj.setHeight(((WhiteboardObjectImage) ws).getHeight());
+ obj.setWhiteboardPoint(((WhiteboardObjectImage) ws)
+ .getWhiteboardPoint());
+ obj.setWidth(((WhiteboardObjectImage) ws).getWidth());
+ obj.setColor(ws.getColor());
+ obj.setThickness(ws.getThickness());
+ }
+ whiteboardObjects.set(i, wbObj);
+ return wbObj;
+ }
+
+ /**
+ * Returns all the type of WhiteboardObject that this whiteboard support.
+ *
+ * @return all the WhiteboardObject supported by this WhiteboardSession.
+ */
+ public String[] getSupportedWhiteboardObjects()
+ {
+ String[] type = new String[8];
+ type[0] = WhiteboardObjectPath.NAME;
+ type[1] = WhiteboardObjectPolyLine.NAME;
+ type[2] = WhiteboardObjectPolygon.NAME;
+ type[3] = WhiteboardObjectLine.NAME;
+ type[4] = WhiteboardObjectRect.NAME;
+ type[5] = WhiteboardObjectCircle.NAME;
+ type[6] = WhiteboardObjectText.NAME;
+ type[7] = WhiteboardObjectImage.NAME;
+
+ return type;
+ }
+
+ /**
+ * Listens for white-board messages and fires the appropriate events to
+ * notify all interested listeners.
+ */
+ private class WhiteboardSmackMessageListener
+ implements PacketListener
+ {
+ public void processPacket(Packet packet)
+ {
+ if (!(packet instanceof org.jivesoftware.smack.packet.Message))
+ return;
+
+ PacketExtension ext =
+ packet.getExtension(
+ WhiteboardObjectPacketExtensionImpl.ELEMENT_NAME,
+ WhiteboardObjectPacketExtensionImpl.NAMESPACE);
+
+ org.jivesoftware.smack.packet.Message msg =
+ (org.jivesoftware.smack.packet.Message) packet;
+
+ if (ext == null)
+ return;
+
+ String fromUserID = StringUtils.parseBareAddress(msg.getFrom());
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("Received from " + fromUserID + " the message "
+ + msg.toXML());
+ }
+
+ OperationSetPersistentPresenceJabberImpl presenceOpSet
+ = (OperationSetPersistentPresenceJabberImpl) jabberProvider
+ .getOperationSet(OperationSetPresence.class);
+
+ // If there's no presence operation set we return, because there's
+ // not contact to associate the event with.
+ if (presenceOpSet == null)
+ return;
+
+ Contact sourceContact
+ = presenceOpSet.findContactByID(fromUserID);
+
+ // If the sender is not our contact we don't care of this message
+ if (!wbParticipants.containsKey(sourceContact.getAddress()))
+ return;
+
+ WhiteboardObjectPacketExtensionImpl newMessage
+ = (WhiteboardObjectPacketExtensionImpl) ext;
+
+ if (msg.getType()
+ == org.jivesoftware.smack.packet.Message.Type.error)
+ {
+ logger.info("WBObject error received from " + fromUserID);
+
+ int errorCode = packet.getError().getCode();
+ int errorResultCode =
+ WhiteboardObjectDeliveryFailedEvent.UNKNOWN_ERROR;
+
+ if (errorCode == 503)
+ {
+ org.jivesoftware.smackx.packet.MessageEvent msgEvent =
+ (org.jivesoftware.smackx.packet.MessageEvent) packet
+ .getExtension("x", "jabber:x:event");
+ if (msgEvent != null && msgEvent.isOffline())
+ {
+ errorResultCode
+ = WhiteboardObjectDeliveryFailedEvent
+ .OFFLINE_MESSAGES_NOT_SUPPORTED;
+ }
+ }
+
+ WhiteboardObjectDeliveryFailedEvent evt =
+ new WhiteboardObjectDeliveryFailedEvent(
+ WhiteboardSessionJabberImpl.this,
+ newMessage.getWhiteboardObject(),
+ sourceContact,
+ errorResultCode,
+ new Date());
+
+ fireMessageEvent(evt);
+
+ return;
+ }
+
+ if (newMessage.getAction().equals(
+ WhiteboardObjectPacketExtensionImpl.ACTION_DELETE))
+ {
+ WhiteboardObjectDeletedEvent msgDeletedEvt
+ = new WhiteboardObjectDeletedEvent(
+ WhiteboardSessionJabberImpl.this,
+ newMessage.getWhiteboardObjectID(),
+ sourceContact,
+ new Date());
+
+ fireMessageEvent(msgDeletedEvt);
+ }
+ else if (newMessage.getAction().equals(
+ WhiteboardObjectPacketExtensionImpl.ACTION_DRAW))
+ {
+ WhiteboardObjectReceivedEvent msgReceivedEvt
+ = new WhiteboardObjectReceivedEvent(
+ WhiteboardSessionJabberImpl.this,
+ newMessage.getWhiteboardObject(),
+ sourceContact,
+ new Date());
+
+ fireMessageEvent(msgReceivedEvt);
+ }
+ }
+ }
+
+ /**
+ * Checks if the participant given by participantName is contained
+ * in this white-board session.
+ *
+ * @param participantName the name of the participant to search for
+ * @return true if a participant with the given name is
+ * contained in this session, false - otherwise
+ */
+ public boolean isParticipantContained(String participantName)
+ {
+ if (wbParticipants.containsKey(participantName))
+ return true;
+
+ return false;
+ }
+}
\ No newline at end of file