Issue #2562 moved session data from chat to packet extension

delegated compression to smack
added timeout for http config
fixed getting all joined venues
fixed room invitation from non-cave client
create session checks for session name already used


Former-commit-id: 80650337ce [formerly 80650337ce [formerly 3781483ef6dd1889aa0ecd6ccc83bfb2461713b5]]
Former-commit-id: ce0a34b53c
Former-commit-id: 4015dc23ee
This commit is contained in:
Brian Clements 2013-12-10 17:00:04 -06:00
parent 110b7c67dc
commit aa8d869635
18 changed files with 1371 additions and 391 deletions

View file

@ -21,8 +21,6 @@ package com.raytheon.uf.viz.collaboration.comm.identity.event;
import java.util.regex.Pattern;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
/**
* Used to store constants that are used to validate, analyze, and parse status
* and configuration messages associated with the AWIPS II httpd collaboration
@ -35,6 +33,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 7, 2012 bkowal Initial creation
* Dec 18, 2013 2562 bclement removed preamble from patterns
*
* </pre>
*
@ -48,20 +47,16 @@ public interface IHttpdXmppMessage {
public static final String ERROR_PARAMETER_NAME = "error";
// Regex
static final String PREABMLE_REGEX = Tools.CONFIG_PREAMBLE.replace("[",
"\\[");
static final String SUFFIX_REGEX = " : .+" + Tools.DIRECTIVE_SUFFIX;
static final String SUFFIX_REGEX = " : .+";
static final String COLLABORATION_URL_REGEX = "http://.+:[1-9][0-9]*/session_data/";
// Regex Patterns
public static final Pattern configErrorPattern = Pattern
.compile(PREABMLE_REGEX + ERROR_PARAMETER_NAME + SUFFIX_REGEX);
.compile(ERROR_PARAMETER_NAME + SUFFIX_REGEX);
public static final Pattern configURLPattern = Pattern
.compile(PREABMLE_REGEX + URL_PARAMETER_NAME + SUFFIX_REGEX);
.compile(URL_PARAMETER_NAME + SUFFIX_REGEX);
public static final Pattern urlPattern = Pattern
.compile(COLLABORATION_URL_REGEX);

View file

@ -32,6 +32,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.user.IQualifiedID;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 21, 2012 jkorman Initial creation
* Dec 18, 2013 2562 bclement removed subject getter (subject in invite)
*
* </pre>
*
@ -42,8 +43,9 @@ import com.raytheon.uf.viz.collaboration.comm.identity.user.IQualifiedID;
public interface IVenueInvitationEvent {
/**
* room id for venue
*
* @return room id for venue
* @return id in {room}@conference.{host} format
*/
public IQualifiedID getRoomId();
@ -53,13 +55,9 @@ public interface IVenueInvitationEvent {
*/
public IQualifiedID getInviter();
/**
* @return subject for venue, may be empty
*/
public String getSubject();
/**
* Get detailed invitation which includes subject and message if provided
*
* @return
*/
public VenueInvite getInvite();

View file

@ -19,11 +19,15 @@
**/
package com.raytheon.uf.viz.collaboration.comm.provider;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.UnmarshallerHandler;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
@ -31,14 +35,15 @@ import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.xmlpull.v1.XmlPullParser;
import com.raytheon.uf.common.serialization.JAXBManager;
import com.raytheon.uf.common.serialization.SerializationException;
import com.raytheon.uf.common.serialization.jaxb.JAXBClassLocator;
import com.raytheon.uf.common.serialization.jaxb.JaxbDummyObject;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.core.procedures.ProcedureXmlManager;
import com.raytheon.uf.viz.core.reflect.SubClassLocator;
@ -53,13 +58,14 @@ import com.raytheon.uf.viz.core.reflect.SubClassLocator;
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Oct 31, 2013 2491 bsteffen Initial creation
* Dec 18, 2013 2562 bclement extend jaxb manager, xpp/fragment support
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class CollaborationXmlManager {
public class CollaborationXmlManager extends JAXBManager {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(CollaborationXmlManager.class);
@ -68,13 +74,24 @@ public class CollaborationXmlManager {
private static CollaborationXmlManager instance;
private final JAXBManager manager;
private CollaborationXmlManager() {
manager = initManager();
/**
* Not for external use. Get instance using static methods.
*
* @param jaxbClasses
* @throws JAXBException
*/
protected CollaborationXmlManager(Class<?>[] jaxbClasses)
throws JAXBException {
super(jaxbClasses);
}
private JAXBManager initManager() {
/**
* Create and configure an XML manager using xmlRoot objects defined in the
* extension point {@link CollaborationXmlManager#EXTENSION_ID}
*
* @return
*/
private static CollaborationXmlManager initManager() {
List<Class<?>> baseClasses = new ArrayList<Class<?>>();
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint point = registry.getExtensionPoint(EXTENSION_ID);
@ -110,7 +127,7 @@ public class CollaborationXmlManager {
jaxbClasses[0] = JaxbDummyObject.class;
try {
return new JAXBManager(jaxbClasses);
return new CollaborationXmlManager(jaxbClasses);
} catch (JAXBException e) {
statusHandler.handle(Priority.PROBLEM,
ProcedureXmlManager.class.getSimpleName()
@ -120,34 +137,61 @@ public class CollaborationXmlManager {
}
private JAXBManager getManager() throws SerializationException {
if (manager == null) {
throw new SerializationException(
ProcedureXmlManager.class.getSimpleName()
+ " Failed to initialize.");
}
return manager;
}
public Object unmarshal(String xml) throws SerializationException {
/**
* Unmarshal to object using Xml Pull Parser as input to JAXB
*
* @param parser
* @return
* @throws CollaborationException
*/
public Object unmarshalFromXPP(XmlPullParser parser)
throws CollaborationException {
Unmarshaller unmarshaller = null;
try {
return getManager().unmarshalFromXml(xml);
} catch (JAXBException e) {
throw new SerializationException(e);
unmarshaller = getUnmarshaller();
UnmarshallerHandler handler = unmarshaller.getUnmarshallerHandler();
PullParserJaxbAdapter adapter = new PullParserJaxbAdapter(parser, handler);
return adapter.unmarshal();
} catch (Exception e) {
throw new CollaborationException("Unable to unmarshal data", e);
} finally {
// TODO magic number 10 because QUEUE_SIZE isn't visible
if ((unmarshaller != null) && (unmarshallers.size() < 10)) {
unmarshallers.add(unmarshaller);
}
}
}
public String marshal(Object obj) throws SerializationException {
/**
* Marshal object to unformatted (not pretty-printed) XML fragment (no XML
* preamble)
*
* @param obj
* @return
* @throws JAXBException
*/
public String marshalToFragment(Object obj) throws JAXBException {
Marshaller msh = getMarshaller();
try {
return getManager().marshalToXml(obj);
} catch (JAXBException e) {
throw new SerializationException(e);
StringWriter writer = new StringWriter();
msh.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);
msh.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
msh.marshal(obj, writer);
return writer.toString();
} finally {
// TODO magic number 10 because QUEUE_SIZE isn't visible
if ((msh != null) && (marshallers.size() < 10)) {
marshallers.add(msh);
}
}
}
/**
* @return singleton XML manager instance
*/
public static synchronized CollaborationXmlManager getInstance() {
if (instance == null) {
instance = new CollaborationXmlManager();
instance = initManager();
}
return instance;
}

View file

@ -0,0 +1,292 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshallerHandler;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
/**
* Adapts xml pull parser to JAXB content handler. Treats XML input as fragment
* (parsed tags do not inherit namespace of tags higher in parse stack)
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 17, 2013 2562 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class PullParserJaxbAdapter {
private final XmlPullParser parser;
private final UnmarshallerHandler handler;
private final Set<String> parentNamespaces = new HashSet<String>();
private final int[] startAndLength = new int[2];
/**
* Adapts pull parser to sax locator
*/
private final Locator locator = new Locator() {
@Override
public String getSystemId() {
return null;
}
@Override
public String getPublicId() {
return null;
}
@Override
public int getLineNumber() {
return parser.getLineNumber();
}
@Override
public int getColumnNumber() {
return parser.getColumnNumber();
}
};
/**
* Adapts pull parser to sax attributes
*/
private final Attributes attributes = new Attributes() {
@Override
public String getValue(String uri, String localName) {
int index = getIndex(uri, localName);
return index < 0 ? null : getValue(index);
}
@Override
public String getValue(String qName) {
int index = getIndex(qName);
return index < 0 ? null : getValue(index);
}
@Override
public String getValue(int index) {
return parser.getAttributeValue(index);
}
@Override
public String getURI(int index) {
return parser.getAttributeNamespace(index);
}
@Override
public String getType(String uri, String localName) {
int index = getIndex(uri, localName);
return index < 0 ? null : getType(index);
}
@Override
public String getType(String qName) {
int index = getIndex(qName);
return index < 0 ? null : getType(index);
}
@Override
public String getType(int index) {
return parser.getAttributeType(index);
}
@Override
public String getQName(int index) {
String name = parser.getAttributeName(index);
String prefix = parser.getAttributePrefix(index);
if (prefix != null) {
name = prefix + ":" + name;
}
return name;
}
@Override
public String getLocalName(int index) {
return parser.getAttributeName(index);
}
@Override
public int getLength() {
return parser.getAttributeCount();
}
@Override
public int getIndex(String uri, String localName) {
for (int i = 0, len = getLength(); i < len; ++i) {
if (getLocalName(i).equals(localName) && getURI(i).equals(uri)) {
return i;
}
}
return -1;
}
@Override
public int getIndex(String qName) {
for (int i = 0, len = getLength(); i < len; ++i) {
if (getQName(i).equals(qName)) {
return i;
}
}
return -1;
}
};
/**
* @param parser
* @param handler
* JAXB unmarshaller content handler
*/
public PullParserJaxbAdapter(XmlPullParser parser, UnmarshallerHandler handler) {
this.parser = parser;
this.handler = handler;
handler.setDocumentLocator(locator);
}
/**
* Unmarshal XML from pull parser and get the result from the handler.
* Treats XML input as fragment (parsed tags do not inherit namespace of
* tags higher in parse stack)
*
* @throws SAXException
* @throws XmlPullParserException
* @throws IOException
* @throws JAXBException
* @throws IllegalStateException
*/
public Object unmarshal() throws SAXException, XmlPullParserException,
IOException, IllegalStateException, JAXBException {
for (int i = 0, count = parser.getNamespaceCount(parser.getDepth() - 1); i < count; ++i) {
parentNamespaces.add(parser.getNamespaceUri(i));
}
handler.startDocument();
parseElement();
handler.endDocument();
return handler.getResult();
}
/**
* Begin namespace prefix mapping
*
* @param start
* starting index in parser for mapping
* @param end
* ending index in parser (not included in mapping)
* @throws XmlPullParserException
* @throws SAXException
*/
private void startPrefix(int start, int end) throws XmlPullParserException,
SAXException {
for (int i = start; i < end; ++i) {
String prefix = parser.getNamespacePrefix(i);
if (prefix == null) {
prefix = "";
}
String namespaceUri = parser.getNamespaceUri(i);
handler.startPrefixMapping(prefix, namespaceUri);
}
}
/**
* End namespace prefix mapping, ends mapping in reverse order
*
* @param start
* starting index in parser for mapping
* @param end
* ending index in parser (not included in mapping)
* @throws XmlPullParserException
* @throws SAXException
*/
private void endPrefix(int start, int end) throws XmlPullParserException,
SAXException {
for (int i = end - 1; i >= start; --i) {
String prefix = parser.getNamespacePrefix(i);
if (prefix == null) {
prefix = "";
}
handler.endPrefixMapping(prefix);
}
}
/**
* Recursive parsing method
*
* @throws XmlPullParserException
* @throws SAXException
* @throws IOException
*/
private void parseElement() throws XmlPullParserException, SAXException,
IOException {
int startNs = parser.getNamespaceCount(parser.getDepth() - 1);
int endNs = parser.getNamespaceCount(parser.getDepth());
String name = parser.getName();
String prefix = parser.getPrefix();
String qname = (prefix == null ? name : prefix + ":" + name);
String ns = parser.getNamespace();
if (parentNamespaces.contains(ns)) {
// namespace inherited from parent tag, ignore to treat xml as
// fragment
ns = "";
}
startPrefix(startNs, endNs);
handler.startElement(ns, name, qname, attributes);
while (true) {
switch (parser.next()) {
case XmlPullParser.TEXT:
char[] text = parser.getTextCharacters(startAndLength);
handler.characters(text, startAndLength[0], startAndLength[1]);
break;
case XmlPullParser.START_TAG:
parseElement();
break;
case XmlPullParser.END_TAG:
handler.endElement(ns, name, qname);
endPrefix(startNs, endNs);
return;
}
}
}
}

View file

@ -19,7 +19,6 @@
**/
package com.raytheon.uf.viz.collaboration.comm.provider;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import javax.xml.bind.annotation.XmlRootElement;
@ -27,7 +26,7 @@ import javax.xml.bind.annotation.XmlRootElement;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
/**
*
* Serialization mechanisms for collaboration data
*
* <pre>
*
@ -36,6 +35,7 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 23, 2012 jkorman Initial creation
* Dec 18, 2013 2562 bclement removed java serialization mode
*
* </pre>
*
@ -44,15 +44,19 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
*/
public enum SerializationMode {
THRIFT, JAXB, JAVA, STRING, NONE, ISNULL;
THRIFT, JAXB, STRING, NONE, ISNULL;
/**
* Uses reflection to determine serialization mode for object's type
*
* @param object
* @return {@link SerializationMode#NONE} if no match found
*/
public static SerializationMode getMode(Object object) {
SerializationMode mode = ISNULL;
if (object != null) {
if (object instanceof String) {
mode = STRING;
} else if (object instanceof Serializable) {
mode = JAVA;
} else {
// We may override the serialization type
Class<?> clazz = object.getClass();

View file

@ -0,0 +1,223 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.util.Base64;
import com.raytheon.uf.common.serialization.SerializationUtil;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
/**
* XMPP packet extension for collaboration session data
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 11, 2013 2562 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class SessionPayload implements PacketExtension {
private static final IUFStatusHandler log = UFStatus
.getHandler(SessionPayload.class);
public static enum PayloadType {
Config, Command, Invitation;
};
public static final String XMLNS = "urn:uf:viz:collaboration";
public static final String ELEMENT_NAME = "SessionData";
public static final String TYPE_ATTRIBUTE = "payloadtype";
public static final String ENCODING_ATTRIBUTE = "encoding";
private final PayloadType payloadType;
private final SerializationMode mode;
private final Object data;
/**
* @param type
* type of message
* @param mode
* encoding for message
* @param data
* message object
*/
public SessionPayload(PayloadType type, SerializationMode mode, Object data) {
this.payloadType = type;
this.mode = mode;
this.data = data;
}
/**
* Serialization mode will be determine by reflection on object
*
* @param type
* type of message
* @param data
* message object
*/
public SessionPayload(PayloadType type, Object data) {
this(type, SerializationMode.getMode(data), data);
}
/**
* Create collaboration extension payload XML
*
* @param type
* type of message
* @param mode
* encoding for message
* @param data
* message object
* @return XML packet fragment
* @throws CollaborationException
*/
public static String createXml(PayloadType type, SerializationMode mode,
Object data) throws CollaborationException {
StringBuilder builder = new StringBuilder();
builder = new StringBuilder();
builder.append("<").append(ELEMENT_NAME).append(" ");
appendAttribute(builder, "xmlns", XMLNS);
appendAttribute(builder, TYPE_ATTRIBUTE, type.name());
appendAttribute(builder, ENCODING_ATTRIBUTE, mode.name());
builder.append(">");
switch (mode) {
case THRIFT:
try {
byte[] arr = SerializationUtil.transformToThrift(data);
builder.append(Base64.encodeBytes(arr));
} catch (Exception e) {
throw new CollaborationException(
"[THRIFT] Could not serialize object", e);
}
break;
case JAXB:
try {
CollaborationXmlManager jaxb = CollaborationXmlManager
.getInstance();
String xml = jaxb.marshalToFragment(data);
builder.append(xml);
} catch (Exception je) {
throw new CollaborationException(
"[JAXB] Could not serialize object", je);
}
break;
case STRING:
builder.append(data.toString());
break;
case NONE:
throw new CollaborationException("Serialization of "
+ data.getClass().getName() + " not supported");
case ISNULL:
break;
}
builder.append("</").append(ELEMENT_NAME).append(">");
return builder.toString();
}
/**
* Format XML attribute name/value pair and append to string builder
*
* @param sb
* @param name
* @param value
*/
private static void appendAttribute(StringBuilder sb, String name,
String value) {
sb.append(name).append("='").append(value).append("' ");
}
/**
* @return the payloadType
*/
public PayloadType getPayloadType() {
return payloadType;
}
/**
* @return the data encoding mode
*/
public SerializationMode getMode() {
return mode;
}
/**
* @return the data object
*/
public Object getData() {
return data;
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.smack.packet.PacketExtension#getElementName()
*/
@Override
public String getElementName() {
return ELEMENT_NAME;
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.smack.packet.PacketExtension#getNamespace()
*/
@Override
public String getNamespace() {
return XMLNS;
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.smack.packet.PacketExtension#toXML()
*/
@Override
public String toXML() {
try {
return createXml(payloadType, mode, data);
} catch (CollaborationException e) {
log.error("Unable to marshall payload to XML", e);
// this method will be called by smack and the result appended to a
// string buffer, this will result in an empty packet which will be
// ignored
return "";
}
}
}

View file

@ -0,0 +1,185 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider;
import java.io.IOException;
import javax.xml.bind.JAXBException;
import org.apache.commons.lang.StringUtils;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.util.Base64;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import com.raytheon.uf.common.serialization.SerializationException;
import com.raytheon.uf.common.serialization.SerializationUtil;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadType;
/**
* XMPP packet extension parsing provider for collaboration session data
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 16, 2013 2562 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class SessionPayloadProvider implements PacketExtensionProvider {
/* (non-Javadoc)
* @see org.jivesoftware.smack.provider.PacketExtensionProvider#parseExtension(org.xmlpull.v1.XmlPullParser)
*/
@Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception {
String typeString = parser.getAttributeValue(null,
SessionPayload.TYPE_ATTRIBUTE);
String modeString = parser.getAttributeValue(null,
SessionPayload.ENCODING_ATTRIBUTE);
checkAttribute(SessionPayload.TYPE_ATTRIBUTE, typeString);
checkAttribute(SessionPayload.ENCODING_ATTRIBUTE, modeString);
SerializationMode mode;
try {
mode = SerializationMode.valueOf(modeString);
} catch (IllegalArgumentException e) {
throw new CollaborationException("Unsupported payload encoding: "
+ modeString, e);
}
PayloadType t;
try {
t = PayloadType.valueOf(typeString);
} catch (IllegalArgumentException e) {
throw new CollaborationException("Unsupported IQ payload type: "
+ typeString, e);
}
Object data;
switch (mode) {
case THRIFT:
String text = getText(parser);
data = unmarshalThrift(text);
break;
case JAXB:
data = unmarshalJaxb(parser);
break;
case STRING:
data = getText(parser);
break;
default:
throw new CollaborationException("Could not deserialize object");
}
return new SessionPayload(t, mode, data);
}
/**
* Unmarshal base64 encoded thrift data
*
* @param data
* @return
* @throws CollaborationException
*/
public static Object unmarshalThrift(String data)
throws CollaborationException {
try {
byte[] b = Base64.decode(data);
return SerializationUtil.transformFromThrift(Object.class, b);
} catch (SerializationException e) {
throw new CollaborationException("Could not deserialize object", e);
}
}
/**
* Unmarshal XML sub tags using JAXB
*
* @param parser
* @return
* @throws XmlPullParserException
* @throws IOException
* @throws CollaborationException
* @throws JAXBException
*/
private static Object unmarshalJaxb(XmlPullParser parser)
throws XmlPullParserException, IOException, CollaborationException,
JAXBException {
int tag = parser.next();
if (tag != XmlPullParser.START_TAG) {
throw new CollaborationException(
"Encountered JAXB payload without XML as data");
}
CollaborationXmlManager manager = CollaborationXmlManager.getInstance();
return manager.unmarshalFromXPP(parser);
}
/**
* Get any text elements under current tag
*
* @param parser
* @return
* @throws XmlPullParserException
* @throws IOException
*/
private static String getText(XmlPullParser parser)
throws XmlPullParserException, IOException {
boolean done = false;
StringBuilder payloadText = new StringBuilder();
int tag = parser.next();
while (!done) {
if (tag == XmlPullParser.END_TAG
&& parser.getName().equals(SessionPayload.ELEMENT_NAME)) {
done = true;
continue;
} else if (parser.getEventType() == XmlPullParser.TEXT) {
payloadText.append(parser.getText());
}
tag = parser.next();
}
return payloadText.toString();
}
/**
* Assert that value is not null or empty
*
* @param name
* used for error message
* @param value
* @throws CollaborationException
* if value is null or empty
*/
public static void checkAttribute(String name, String value)
throws CollaborationException {
if (StringUtils.isBlank(value)) {
throw new CollaborationException("Missing attribute: " + name);
}
}
}

View file

@ -27,11 +27,6 @@ import java.util.regex.Pattern;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.util.Base64;
import com.raytheon.uf.common.serialization.SerializationException;
import com.raytheon.uf.common.serialization.SerializationUtil;
import com.raytheon.uf.viz.collaboration.comm.compression.CompressionUtil;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
/**
* Provides some utility methods for parsing and serializing/deserializing data.
*
@ -44,7 +39,9 @@ import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
* Mar 07, 2012 jkorman Initial creation
* Oct 31, 2013 2491 bsteffen Use CollaborationXmlManager for xml
* serialization.
* Dec 6, 2013 2561 bclement removed ECF
* Dec 6, 2013 2561 bclement removed ECF
* Dec 16, 2013 2562 bclement moved compression to smack,
* moved marshalling to session payload
*
*
* </pre>
@ -55,10 +52,6 @@ import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
public abstract class Tools {
public static final String TAG_INVITE = "[[INVITEID#";
public static final String TAG_INVITE_ID = TAG_INVITE + "%s]]%s";
public static final String PROP_SESSION_ID = "sessionId";
public static final String CMD_PREAMBLE = "[[COMMAND#";
@ -67,27 +60,6 @@ public abstract class Tools {
public static final String DIRECTIVE_SUFFIX = "]]";
private static final String ENV_THRIFT = CMD_PREAMBLE
+ SerializationMode.THRIFT.name() + "]]";
private static final String ENV_THRIFT_COMPRESSED = CMD_PREAMBLE
+ SerializationMode.THRIFT.name() + "-COMPRESSED]]";
private static final String ENV_JAXB = CMD_PREAMBLE
+ SerializationMode.JAXB.name() + "]]";
private static final String ENV_JAXB_COMPRESSED = CMD_PREAMBLE
+ SerializationMode.JAXB.name() + "-COMPRESSED]]";
private static final String ENV_STRING = CMD_PREAMBLE
+ SerializationMode.STRING.name() + "]]";
private static final String ENV_JAVA = CMD_PREAMBLE
+ SerializationMode.JAVA.name() + "]]";
private static final String ENV_NONE = CMD_PREAMBLE
+ SerializationMode.NONE.name() + "]]";
public static final String VENUE_SUBJECT_PROP = "subject";
public static final String NAME_DELIM = "@";
@ -96,18 +68,6 @@ public abstract class Tools {
public static final String RESOURCE_DELIM = "/";
public static boolean COMPRESSION_OFF = false;
static {
try {
COMPRESSION_OFF = Boolean
.getBoolean("collaboration.compressionOff");
} catch (Exception e) {
// must not have permission to access system properties. ignore and
// use default.
}
}
public static final Pattern JID_RESERVED_CHARACTERS = Pattern
.compile("[ \"&'/:<>@]");
@ -235,159 +195,6 @@ public abstract class Tools {
return Base64.encodeBytes(message);
}
/**
*
* @param data
* @return
*/
public static String marshallData(Object data)
throws CollaborationException {
String marshalledData = null;
if (data != null) {
StringBuilder sb = new StringBuilder();
byte[] marshalledBinary = null;
SerializationMode mode = SerializationMode.getMode(data);
switch (mode) {
case THRIFT: {
try {
if (COMPRESSION_OFF) {
marshalledBinary = SerializationUtil
.transformToThrift(data);
sb.append(ENV_THRIFT);
} else {
/*
* compress(thrift(data))
*/
byte[] marshalledThrift = SerializationUtil
.transformToThrift(data);
marshalledBinary = CompressionUtil
.compress(marshalledThrift);
sb.append(ENV_THRIFT_COMPRESSED);
}
} catch (Exception e) {
throw new CollaborationException(
"[THRIFT] Could not serialize object", e);
}
break;
}
case JAXB: {
try {
CollaborationXmlManager jaxb = CollaborationXmlManager
.getInstance();
if (COMPRESSION_OFF) {
String s = jaxb.marshal(data);
if (s != null) {
sb.append(ENV_JAXB);
sb.append(s);
}
} else {
String rawString = jaxb.marshal(data);
marshalledBinary = CompressionUtil.compress(rawString
.getBytes());
sb.append(ENV_JAXB_COMPRESSED);
}
} catch (Exception je) {
throw new CollaborationException(
"[JAXB] Could not serialize object", je);
}
break;
}
case JAVA: {
break;
}
case STRING: {
sb.append(ENV_STRING);
sb.append(data);
break;
}
case NONE: {
throw new CollaborationException("Serialization of "
+ data.getClass().getName() + " not supported");
}
case ISNULL: {
break;
}
}
if (marshalledBinary != null) {
sb.append(encodeToBase64(marshalledBinary));
}
if (sb.length() > 0) {
marshalledData = sb.toString();
}
}
return marshalledData;
}
/**
*
* @param data
* @return
* @throws CollaborationException
*/
public static Object unMarshallData(String data)
throws CollaborationException {
Object unMarshalledData = null;
if (data != null) {
// look for the envelope header first
if (data.startsWith(ENV_THRIFT)) {
String s = data.substring(ENV_THRIFT.length());
try {
byte[] b = decodeFromBase64(s);
unMarshalledData = SerializationUtil.transformFromThrift(
Object.class, b);
} catch (SerializationException e) {
throw new CollaborationException(
"Could not deserialize object", e);
}
} else if (data.startsWith(ENV_THRIFT_COMPRESSED)) {
String s = data.substring(ENV_THRIFT_COMPRESSED.length());
try {
byte[] rawBytes = decodeFromBase64(s);
byte[] uncompressedBytes = CompressionUtil
.uncompress(rawBytes);
unMarshalledData = SerializationUtil.transformFromThrift(
Object.class, uncompressedBytes);
// unMarshalledData = SerializationUtil
// .transformFromThrift(createCompressionInputStream(rawBytes));
} catch (Exception e) {
throw new CollaborationException(
"Could not deserialize object", e);
}
} else if (data.startsWith(ENV_JAXB)) {
String s = data.substring(ENV_JAXB.length());
try {
unMarshalledData = CollaborationXmlManager.getInstance()
.unmarshal(s);
} catch (SerializationException je) {
throw new CollaborationException(
"[JAXB] Could not deserialize object", je);
}
} else if (data.startsWith(ENV_JAXB_COMPRESSED)) {
String rawString = data.substring(ENV_JAXB_COMPRESSED.length());
try {
byte[] rawBytes = decodeFromBase64(rawString);
unMarshalledData = CollaborationXmlManager.getInstance()
.unmarshal(
new String(CompressionUtil
.uncompress(rawBytes)));
// unMarshalledData = SerializationUtil
// .unmarshalFromXml(createCompressionInputStream(rawBytes));
} catch (Exception je) {
throw new CollaborationException(
"[JAXB] Could not deserialize object", je);
}
} else if (data.startsWith(ENV_STRING)) {
unMarshalledData = data.substring(ENV_STRING.length());
} else if (data.startsWith(ENV_JAVA)) {
throw new CollaborationException("Could not deserialize object");
} else if (data.startsWith(ENV_NONE)) {
throw new CollaborationException("Could not deserialize object");
}
}
return unMarshalledData;
}
/**
* Add properties to packet
*

View file

@ -33,6 +33,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.user.IQualifiedID;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 27, 2012 jkorman Initial creation
* Dec 18, 2013 2562 bclement removed subject (subject in invite)
*
* </pre>
*
@ -46,8 +47,6 @@ public class VenueInvitationEvent implements IVenueInvitationEvent {
private IQualifiedID invitor;
private String subject;
private VenueInvite invite;
/**
@ -58,10 +57,9 @@ public class VenueInvitationEvent implements IVenueInvitationEvent {
* @param body
*/
public VenueInvitationEvent(IQualifiedID venueId, IQualifiedID invitor,
String subject, VenueInvite invite) {
VenueInvite invite) {
this.venueId = venueId;
this.invitor = invitor;
this.subject = subject;
this.invite = invite;
}
@ -83,14 +81,6 @@ public class VenueInvitationEvent implements IVenueInvitationEvent {
return invitor;
}
/**
* @see com.raytheon.uf.viz.collaboration.comm.identity.event.IVenueInvitationEvent#getSubject()
*/
@Override
public String getSubject() {
return subject;
}
public VenueInvite getInvite() {
return invite;
}

View file

@ -25,7 +25,9 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterListener;
@ -36,6 +38,7 @@ import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Mode;
import org.jivesoftware.smack.packet.Presence.Type;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.muc.InvitationListener;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.RoomInfo;
@ -57,6 +60,9 @@ import com.raytheon.uf.viz.collaboration.comm.identity.info.IVenueInfo;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.SharedDisplayVenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IQualifiedID;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayloadProvider;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.event.VenueInvitationEvent;
@ -93,6 +99,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueId;
* Feb 24, 2012 jkorman Initial creation
* Apr 18, 2012 njensen Major cleanup
* Dec 6, 2013 2561 bclement removed ECF
* Dec 18, 2013 2562 bclement added smack compression, fixed invite parsing
*
* </pre>
*
@ -103,6 +110,12 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueId;
public class CollaborationConnection implements IEventPublisher {
static {
ProviderManager.getInstance().addExtensionProvider(
SessionPayload.ELEMENT_NAME, SessionPayload.XMLNS,
new SessionPayloadProvider());
}
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(CollaborationConnection.class);
@ -130,6 +143,17 @@ public class CollaborationConnection implements IEventPublisher {
private XMPPConnection connection;
public static boolean COMPRESS = true;
static {
try {
COMPRESS = Boolean.getBoolean("collaboration.compression");
} catch (Exception e) {
// must not have permission to access system properties. ignore and
// use default.
}
}
private CollaborationConnection(CollaborationConnectionData connectionData)
throws CollaborationException {
this.connectionData = connectionData;
@ -148,7 +172,11 @@ public class CollaborationConnection implements IEventPublisher {
eventBus = new EventBus();
sessions = new HashMap<String, ISession>();
connection = new XMPPConnection(connectionData.getServer());
ConnectionConfiguration conConfig = new ConnectionConfiguration(
connectionData.getServer());
conConfig.setCompressionEnabled(COMPRESS);
connection = new XMPPConnection(conConfig);
this.user = new UserId(connectionData.getUserName(),
connectionData.getServer());
@ -410,7 +438,7 @@ public class CollaborationConnection implements IEventPublisher {
Collection<IVenueInfo> info = new ArrayList<IVenueInfo>();
if (isConnected()) {
Iterator<String> joinedRooms = MultiUserChat.getJoinedRooms(
connection, user.getNormalizedId());
connection, connection.getUser());
while (joinedRooms.hasNext()) {
String room = joinedRooms.next();
RoomInfo roomInfo;
@ -512,46 +540,66 @@ public class CollaborationConnection implements IEventPublisher {
if (isConnected()) {
MultiUserChat.addInvitationListener(connection,
new InvitationListener() {
@Override
public void invitationReceived(Connection conn,
String room, String inviter, String reason,
String password, Message message) {
// TODO handle password protected rooms
IQualifiedID venueId = new VenueId();
venueId.setName(Tools.parseName(room));
UserId invitor = IDConverter.convertFrom(inviter);
VenueInvite received;
try {
received = (VenueInvite) Tools
.unMarshallData(reason);
// TODO handle invite from generic client
String subject = message.getSubject();
if (received != null && subject == null) {
subject = received.getSubject();
if (subject == null) {
RoomInfo roomInfo = MultiUserChat
.getRoomInfo(conn, room);
subject = roomInfo.getSubject();
}
IVenueInvitationEvent invite = new VenueInvitationEvent(
venueId, invitor, subject, received);
eventBus.post(invite);
if (message != null) {
SessionPayload payload = (SessionPayload) message
.getExtension(SessionPayload.XMLNS);
if (payload != null) {
handleCollabInvite(venueId, invitor,
payload);
return;
}
} catch (Exception e) {
statusHandler
.handle(Priority.PROBLEM,
"Error handling received invite message",
e);
}
if ( reason.startsWith(Tools.CMD_PREAMBLE)){
reason = "Shared display invitation from incompatible version of CAVE. "
+ "Session will be chat-only if invitation is accepted";
}
handleChatRoomInvite(venueId, invitor, reason,
message);
}
});
}
}
private void handleChatRoomInvite(IQualifiedID venueId, UserId invitor,
String reason, Message message) {
VenueInvite invite = new VenueInvite();
if (!StringUtils.isBlank(reason)) {
invite.setMessage(reason);
} else if (!StringUtils.isBlank(message.getBody())) {
invite.setMessage(message.getBody());
} else {
invite.setMessage("");
}
invite.setSubject(message.getSubject());
IVenueInvitationEvent event = new VenueInvitationEvent(venueId,
invitor, invite);
eventBus.post(event);
}
private void handleCollabInvite(IQualifiedID venueId, UserId invitor,
SessionPayload payload) {
Object obj = payload.getData();
if (obj == null
|| !payload.getPayloadType().equals(PayloadType.Invitation)
|| !(obj instanceof VenueInvite)) {
statusHandler.warn("Received unsupported invite payload");
return;
}
VenueInvite invite = (VenueInvite) obj;
IVenueInvitationEvent event = new VenueInvitationEvent(venueId,
invitor, invite);
eventBus.post(event);
}
/**
* Register an event handler with this
*

View file

@ -27,12 +27,12 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.collaboration.comm.Activator;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IHttpdCollaborationConfigurationEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IHttpdXmppMessage;
import com.raytheon.uf.viz.collaboration.comm.identity.event.ITextMessageEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IQualifiedID;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.ChatMessageEvent;
@ -50,6 +50,8 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
* ------------ ---------- ----------- --------------------------
* Mar 28, 2012 jkorman Initial creation
* Dec 6, 2013 2561 bclement removed ECF
* Dec 18, 2013 2562 bclement added timeout for HTTP config,
* data now in packet extension
*
* </pre>
*
@ -65,14 +67,30 @@ public class PeerToPeerCommHelper implements PacketListener {
private static Object httpServerLockObj = new Object();
private static String httpServer;
private static long HTTP_SERVER_TIMEOUT = 10 * 1000; // 10 seconds
/**
* Get HTTP server address. This method blocks until the address has been
* received from the chat server or a timeout has expired.
*
* @return
*/
public static String getCollaborationHttpServer() {
/**
* Wait for initialization of field httpServer.
*/
synchronized (httpServerLockObj) {
long start = System.currentTimeMillis();
try {
while (httpServer == null) {
if (System.currentTimeMillis() - start > HTTP_SERVER_TIMEOUT) {
// TODO should we get fallback server address from
// localization?
statusHandler
.error("HTTP URL configuration not received from server");
break;
}
httpServerLockObj.wait(500);
}
} catch (InterruptedException e) {
@ -111,37 +129,48 @@ public class PeerToPeerCommHelper implements PacketListener {
return;
}
String body = msg.getBody();
Activator.getDefault().getNetworkStats()
.log(Activator.PEER_TO_PEER, 0, body.length());
if (body != null) {
if (body.startsWith(Tools.CMD_PREAMBLE)) {
routeData(msg);
} else if (body.startsWith(Tools.CONFIG_PREAMBLE)) {
Activator.getDefault().getNetworkStats()
.log(Activator.PEER_TO_PEER, 0, body.length());
if (body.startsWith(Tools.CONFIG_PREAMBLE)) {
// TODO Legacy config support
body = body.substring(Tools.CONFIG_PREAMBLE.length(),
body.length() - Tools.DIRECTIVE_SUFFIX.length());
this.handleConfiguration(body);
} else {
// anything else pass to the normal text
routeMessage(msg);
}
} else {
SessionPayload payload = (SessionPayload) msg
.getExtension(SessionPayload.XMLNS);
if (payload != null) {
switch (payload.getPayloadType()) {
case Command:
routeData(payload,
(String) msg.getProperty(Tools.PROP_SESSION_ID));
break;
case Config:
handleConfiguration(payload.getData().toString());
break;
default:
// do nothing
}
}
}
}
}
/**
* Post data as event either to associated session, or general event bus
*
* @param message
* @param payload
* @param sessionId
*/
private void routeData(Message message) {
Object object = null;
try {
object = Tools.unMarshallData(message.getBody());
} catch (CollaborationException e) {
statusHandler.handle(Priority.PROBLEM,
"Error unmarshalling PeerToPeer data", e);
}
private void routeData(SessionPayload payload, String sessionId) {
Object object = payload.getData();
if (object != null) {
String sessionId = (String) message
.getProperty(Tools.PROP_SESSION_ID);
if (sessionId == null) {
manager.postEvent(object);
} else {
@ -158,6 +187,7 @@ public class PeerToPeerCommHelper implements PacketListener {
}
/**
* Post text message to chat
*
* @param message
*/
@ -190,6 +220,11 @@ public class PeerToPeerCommHelper implements PacketListener {
}
}
/**
* Parse server configuration and notify general event bus of config event
*
* @param body
*/
private void handleConfiguration(String body) {
// Determine if an error has occurred.
if (IHttpdXmppMessage.configErrorPattern.matcher(body).matches()) {
@ -237,18 +272,23 @@ public class PeerToPeerCommHelper implements PacketListener {
manager.postEvent(configurationEvent);
}
/**
* Parse config parameter value from key:value string
*
* @param body
* @param parameterName
* @return
*/
private String getCollaborationConfigurationParameterValue(String body,
String parameterName) {
// Eliminate the preamble.
String encodedConfiguration = body.replace(Tools.CONFIG_PREAMBLE, "");
// Eliminate the suffix: ]]
encodedConfiguration = encodedConfiguration.substring(0,
encodedConfiguration.length() - 2);
// Remove the parameter name.
return encodedConfiguration.replace(parameterName + " :", "").trim();
return body.replace(parameterName + " :", "").trim();
}
/**
* Notify general event bus that shared display is disabled
*/
private void disableSharedDisplaySession() {
// ensure that the shared session displays will be disabled
IHttpdCollaborationConfigurationEvent configurationEvent = new HttpdCollaborationConfigurationEvent(

View file

@ -19,11 +19,45 @@
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.pubsub.AccessModel;
import org.jivesoftware.smackx.pubsub.Affiliation;
import org.jivesoftware.smackx.pubsub.ConfigureForm;
import org.jivesoftware.smackx.pubsub.FormType;
import org.jivesoftware.smackx.pubsub.Item;
import org.jivesoftware.smackx.pubsub.ItemDeleteEvent;
import org.jivesoftware.smackx.pubsub.ItemPublishEvent;
import org.jivesoftware.smackx.pubsub.LeafNode;
import org.jivesoftware.smackx.pubsub.NodeType;
import org.jivesoftware.smackx.pubsub.PayloadItem;
import org.jivesoftware.smackx.pubsub.PubSubManager;
import org.jivesoftware.smackx.pubsub.PublishModel;
import org.jivesoftware.smackx.pubsub.Subscription;
import org.jivesoftware.smackx.pubsub.Subscription.State;
import org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener;
import org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
import com.google.common.eventbus.EventBus;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.identity.info.IVenueInfo;
import com.raytheon.uf.viz.collaboration.comm.identity.user.SharedDisplayRole;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
@ -37,6 +71,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 18, 2012 njensen Initial creation
* Dec 18, 2013 2562 bclement moved data to packet extension
*
* </pre>
*
@ -45,46 +80,122 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
*/
public class SharedDisplaySession extends VenueSession implements
ISharedDisplaySession {
ISharedDisplaySession, ItemEventListener<Item>, ItemDeleteListener {
private static final transient IUFStatusHandler log = UFStatus
.getHandler(SharedDisplaySession.class);
private UserId sessionLeader = null;
private UserId dataProvider = null;
private PubSubManager pubsubMgr;
private LeafNode topic;
private XMPPConnection conn;
public SharedDisplaySession(EventBus externalBus,
CollaborationConnection manager) throws CollaborationException {
super(externalBus, manager);
init();
}
public SharedDisplaySession(EventBus externalBus,
CollaborationConnection manager, String sessionId)
throws CollaborationException {
super(externalBus, manager, sessionId);
init();
}
@Override
public void sendObjectToVenue(Object obj) throws CollaborationException {
if (obj != null) {
String message = Tools.marshallData(obj);
if (message != null) {
sendMessageToVenue(message);
/**
* perform setup/management tasks before connecting to venue
*/
private void init() {
this.conn = getConnection().getXmppConnection();
pubsubMgr = new PubSubManager(conn);
cleanupOldTopics();
}
/**
* Delete orphaned topic from sessions this user started that are not
* currently running on this client
*/
private void cleanupOldTopics() {
Collection<ISession> sessions = getConnection().getSessions();
Set<String> sessionIds = new HashSet<String>(sessions.size());
for ( ISession s : sessions){
sessionIds.add(s.getSessionId());
}
List<Affiliation> affiliations;
try {
affiliations = pubsubMgr.getAffiliations();
} catch (XMPPException e) {
// openfire returns a 404 if there are no topic affiliations for
// this user. Smack turns that into an exception.
log.debug("Unable to get affiliations from server: "
+ e.getLocalizedMessage());
return;
}
for (Affiliation aff : affiliations) {
if (aff.getType().equals(
org.jivesoftware.smackx.pubsub.Affiliation.Type.owner)) {
if (!sessionIds.contains(aff.getNodeId())) {
// TODO should we check to see if the topic is a certain age
// before cleanup?
log.info("Deleting old topic: " + aff.getNodeId());
try {
pubsubMgr.deleteNode(aff.getNodeId());
} catch (XMPPException e) {
log.error(
"Problem cleaning up old topic: "
+ aff.getNodeId(), e);
}
}
}
}
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession
* #sendObjectToVenue(java.lang.Object)
*/
@Override
public void sendObjectToVenue(Object obj) throws CollaborationException {
if (obj == null) {
return;
}
SessionPayload payload = new SessionPayload(PayloadType.Command, obj);
topic.publish(new PayloadItem<SessionPayload>(payload));
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession
* #sendObjectToPeer
* (com.raytheon.uf.viz.collaboration.comm.identity.user.IQualifiedID,
* java.lang.Object)
*/
@Override
public void sendObjectToPeer(
com.raytheon.uf.viz.collaboration.comm.identity.user.IQualifiedID participant,
Object obj) throws CollaborationException {
PeerToPeerChat session = getP2PSession();
if (session != null) {
String message = Tools.marshallData(obj);
if (message != null) {
TextMessage msg = new TextMessage(participant, message);
msg.setProperty(Tools.PROP_SESSION_ID, getSessionId());
session.sendPeerToPeer(msg);
}
// TODO should only send to CAVE clients
if (obj == null) {
return;
}
SessionPayload payload = new SessionPayload(PayloadType.Command, obj);
Message msg = new Message(participant.getFQName(), Type.normal);
msg.addExtension(payload);
msg.setFrom(conn.getUser());
msg.setProperty(Tools.PROP_SESSION_ID, getSessionId());
conn.sendPacket(msg);
}
/**
@ -125,13 +236,240 @@ public class SharedDisplaySession extends VenueSession implements
return result;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession
* #setCurrentSessionLeader
* (com.raytheon.uf.viz.collaboration.comm.provider.user.UserId)
*/
@Override
public void setCurrentSessionLeader(UserId id) {
sessionLeader = id;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession
* #setCurrentDataProvider
* (com.raytheon.uf.viz.collaboration.comm.provider.user.UserId)
*/
@Override
public void setCurrentDataProvider(UserId id) {
dataProvider = id;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession#
* configureVenue(java.lang.String)
*/
@Override
protected IVenueInfo configureVenue(String venueName)
throws CollaborationException {
IVenueInfo rval = super.configureVenue(venueName);
try {
configureSubscription();
} catch (XMPPException e) {
throw new CollaborationException(
"Unable to configure subscription", e);
}
return rval;
}
/**
* Setup data subscription for this client
*
* @throws XMPPException
* @throws CollaborationException
*/
private void configureSubscription() throws XMPPException,
CollaborationException {
topic = pubsubMgr.getNode(getSessionId());
topic.addItemEventListener(this);
topic.addItemDeleteListener(this);
Subscription sub = findSubscription(getUserID());
if (sub == null) {
sub = topic.subscribe(conn.getUser());
}
if ( !sub.getState().equals(State.subscribed)){
String msg = String.format(
"Problem subscribing to topic %s. Current state: %s",
topic.getId(), sub.getState().toString());
throw new CollaborationException(msg);
}
}
/**
* Find subscriptions this user has on the current topic
*
* @param user
* @return null if none found
* @throws XMPPException
*/
protected Subscription findSubscription(UserId user) throws XMPPException {
Subscription rval = null;
for (Subscription sub : topic.getSubscriptions()) {
if (user.isSameUser(sub.getJid())) {
log.info("found sub: " + sub.toXML());
rval = sub;
}
}
return rval;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession#
* createVenue(java.lang.String, java.lang.String)
*/
@Override
protected IVenueInfo createVenue(String venueName, String subject)
throws CollaborationException {
IVenueInfo rval = super.createVenue(venueName, subject);
try {
createNode(getSessionId());
} catch (XMPPException e) {
throw new CollaborationException("Unable to create topic", e);
}
try {
configureSubscription();
} catch (XMPPException e) {
throw new CollaborationException(
"Unable to configure subscription", e);
}
return rval;
}
/**
* Create and configure new topic for data subscriptions
*
* @param topicName
* @throws XMPPException
*/
private void createNode(String topicName) throws XMPPException {
ConfigureForm form = new ConfigureForm(FormType.submit);
form.setAccessModel(AccessModel.open);
form.setDeliverPayloads(true);
form.setNodeType(NodeType.leaf);
form.setTitle(topicName);
form.setSubscribe(true);
form.setPublishModel(PublishModel.open);
form.setPresenceBasedDelivery(false);
form.setPersistentItems(false);
form.setNotifyDelete(true);
form.setNotifyConfig(true);
form.setNotifyRetract(true);
form.setMaxPayloadSize(Short.MAX_VALUE);
pubsubMgr.createNode(topicName, form);
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.smackx.pubsub.listener.ItemEventListener#
* handlePublishedItems(org.jivesoftware.smackx.pubsub.ItemPublishEvent)
*/
@Override
public void handlePublishedItems(ItemPublishEvent<Item> items) {
for (Item i : items.getItems()) {
if (i instanceof PayloadItem<?>) {
PacketExtension payload = ((PayloadItem<?>) i).getPayload();
handlePayload(payload);
}
}
}
/**
* Process session data payload
*
* @param payload
*/
private void handlePayload(PacketExtension payload) {
if (payload instanceof SessionPayload) {
SessionPayload sp = (SessionPayload) payload;
Object obj = sp.getData();
postEvent(obj);
}
}
/**
* @return true if session data topic exists
*/
private boolean topicExists() {
try {
DiscoverInfo info = new DiscoverInfo();
info.setTo("pubsub." + conn.getServiceName());
info.setNode(topic.getId());
SyncPacketSend.getReply(conn, info);
return true;
} catch (XMPPException e) {
return false;
}
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession#
* close()
*/
@Override
public void close() {
super.close();
if (pubsubMgr == null || topic == null || !topicExists()) {
return;
}
try {
Subscription sub = findSubscription(getUserID());
if (sub == null) {
return;
}
topic.unsubscribe(sub.getJid(), sub.getId());
topic.removeItemDeleteListener(this);
topic.removeItemEventListener(this);
if (hasRole(SharedDisplayRole.SESSION_LEADER)) {
pubsubMgr.deleteNode(topic.getId());
}
topic = null;
pubsubMgr = null;
} catch (XMPPException e) {
log.error("Unable to close subscription", e);
}
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener#handleDeletedItems
* (org.jivesoftware.smackx.pubsub.ItemDeleteEvent)
*/
@Override
public void handleDeletedItems(ItemDeleteEvent items) {
// TODO this method should be able to tell the client if the topic is
// deleted, either smack or openfire doesn't support that feature, so we
// use topicExists() instead
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener#handlePurge()
*/
@Override
public void handlePurge() {
// we don't persist data packets to topics
}
}

View file

@ -19,17 +19,22 @@
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.ParticipantStatusListener;
import org.jivesoftware.smackx.packet.DiscoverItems;
import com.google.common.eventbus.EventBus;
import com.raytheon.uf.common.status.IUFStatusHandler;
@ -44,6 +49,8 @@ import com.raytheon.uf.viz.collaboration.comm.identity.info.IVenue;
import com.raytheon.uf.viz.collaboration.comm.identity.info.IVenueInfo;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.provider.CollaborationMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.VenueParticipantEvent;
@ -75,6 +82,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Feb 24, 2012 jkorman Initial creation
* Apr 17, 2012 njensen Major refactor
* Dec 6, 2013 2561 bclement removed ECF
* Dec 18, 2013 2562 bclement moved data to packet extension
*
* </pre>
*
@ -90,8 +98,6 @@ public class VenueSession extends BaseSession implements IVenueSession {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(VenueSession.class);
private static final String SEND_CMD = "[[COMMAND";
private static final String SEND_TXT = "[[TEXT]]";
public static final String SEND_HISTORY = "[[HISTORY]]";
@ -120,8 +126,8 @@ public class VenueSession extends BaseSession implements IVenueSession {
* @param container
* @param eventBus
*/
protected VenueSession(EventBus externalBus,
CollaborationConnection manager) throws CollaborationException {
protected VenueSession(EventBus externalBus, CollaborationConnection manager)
throws CollaborationException {
super(externalBus, manager);
}
@ -179,8 +185,20 @@ public class VenueSession extends BaseSession implements IVenueSession {
@Override
public void sendInvitation(UserId id, VenueInvite invite)
throws CollaborationException {
String msgBody = Tools.marshallData(invite);
muc.invite(id.getNormalizedId(), msgBody);
SessionPayload payload = new SessionPayload(PayloadType.Invitation,
invite);
Message msg = new Message();
msg.setTo(id.getNormalizedId());
msg.setFrom(getUserID().getNormalizedId());
msg.setType(Type.normal);
msg.addExtension(payload);
String reason = "";
if (!StringUtils.isBlank(invite.getMessage())) {
reason = invite.getMessage();
} else if (!StringUtils.isBlank(invite.getSubject())) {
reason = invite.getSubject();
}
muc.invite(msg, id.getNormalizedId(), reason);
}
/**
@ -209,21 +227,12 @@ public class VenueSession extends BaseSession implements IVenueSession {
@Override
public void sendChatMessage(String message) throws CollaborationException {
this.sendMessageToVenue(message);
}
protected void sendMessageToVenue(String message)
throws CollaborationException {
// Assume success
if ((muc != null) && (message != null)) {
Activator.getDefault().getNetworkStats()
.log(Activator.VENUE, message.length(), 0);
try {
if (message.startsWith(SEND_CMD)) {
muc.sendMessage(message);
} else {
muc.sendMessage(SEND_TXT + message);
}
muc.sendMessage(message);
} catch (XMPPException e) {
throw new CollaborationException("Error sending messge", e);
}
@ -256,7 +265,7 @@ public class VenueSession extends BaseSession implements IVenueSession {
* @param roomName
* @return
*/
private String getRoomId(String host, String roomName){
private String getRoomId(String host, String roomName) {
return roomName + "@conference." + host;
}
@ -275,10 +284,12 @@ public class VenueSession extends BaseSession implements IVenueSession {
CollaborationConnection manager = getSessionManager();
XMPPConnection conn = manager.getXmppConnection();
String roomId = getRoomId(conn.getHost(), venueName);
if (roomExistsOnServer(roomId)) {
throw new CollaborationException("Session name already in use");
}
this.muc = new MultiUserChat(conn, roomId);
createListeners();
UserId user = manager.getUser();
// TODO check if room already exists
muc.create(user.getName());
muc.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));
muc.changeSubject(subject);
@ -291,6 +302,29 @@ public class VenueSession extends BaseSession implements IVenueSession {
}
}
/**
* @param roomId
* @return true if room exists on server
* @throws XMPPException
*/
protected boolean roomExistsOnServer(String roomId) throws XMPPException {
String host = Tools.parseHost(roomId);
CollaborationConnection manager = getSessionManager();
XMPPConnection conn = manager.getXmppConnection();
ServiceDiscoveryManager serviceDiscoveryManager = new ServiceDiscoveryManager(
conn);
DiscoverItems result = serviceDiscoveryManager.discoverItems(host);
for (Iterator<DiscoverItems.Item> items = result.getItems(); items
.hasNext();) {
DiscoverItems.Item item = items.next();
if (roomId.equals(item.getEntityID())) {
return true;
}
}
return false;
}
/**
* register chat room listeners with muc
*/
@ -476,6 +510,9 @@ public class VenueSession extends BaseSession implements IVenueSession {
if (!body.startsWith(SEND_HISTORY) && fromUser.isSameUser(account)) {
// ignore from ourselves except for history
return false;
} else if (body.startsWith(Tools.CMD_PREAMBLE)
|| body.startsWith(Tools.CONFIG_PREAMBLE)) {
return false;
}
return true;
@ -490,28 +527,7 @@ public class VenueSession extends BaseSession implements IVenueSession {
String body = message.getBody();
if (body != null) {
if (body.startsWith(SEND_CMD)) {
Object o = null;
try {
o = Tools.unMarshallData(body);
if (o != null) {
this.postEvent(o);
}
} catch (CollaborationException ce) {
statusHandler.error(
"Error deserializing received message on venue "
+ muc.getRoom(), ce);
}
} else if (body.startsWith(SEND_TXT)) {
body = body.substring(SEND_TXT.length());
message.setBody(body);
TextMessage msg = new TextMessage(message.getTo(),
message.getBody());
msg.setFrom(message.getFrom());
this.postEvent(msg);
} else if (body.startsWith(SEND_HISTORY)) {
if (body.startsWith(SEND_HISTORY)) {
String[] vars = body.split("\\|");
String timeString = vars[0]
.substring(SEND_HISTORY.length());
@ -523,7 +539,7 @@ public class VenueSession extends BaseSession implements IVenueSession {
// three pipe characters
String moddedBody = body.substring(SEND_HISTORY.length()
+ timeString.length() + username.length()
+ site.length() + SEND_TXT.length() + 3);
+ site.length() + 3);
message.setBody(moddedBody);
TextMessage msg = new TextMessage(message.getFrom(),
message.getBody());
@ -535,9 +551,6 @@ public class VenueSession extends BaseSession implements IVenueSession {
msg.setStatus(SEND_HISTORY);
this.postEvent(msg);
} else {
// attempt to handle outside clients as text only since the
// SEND_TXT won't be appended to the first portion of the
// body
message.setBody(body);
TextMessage msg = new TextMessage(message.getTo(),
message.getBody());
@ -561,12 +574,22 @@ public class VenueSession extends BaseSession implements IVenueSession {
String body = msg.getBody();
if (body != null) {
if (body.startsWith(SEND_TXT)) {
body = body.substring(SEND_TXT.length());
}
message = new CollaborationMessage(null, body);
message.setFrom(IDConverter.convertFromRoom(muc, msg.getFrom()));
}
return message;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession#sendPresence
* (org.jivesoftware.smack.packet.Presence)
*/
@Override
public void sendPresence(Presence presence) throws CollaborationException {
presence.setTo(venue.getInfo().getVenueID());

View file

@ -287,7 +287,6 @@ public class CollaborationDrawingResource extends
event.setType(lockingDrawing ? CollaborationEventType.LOCK_USERS
: CollaborationEventType.UNLOCK_USERS);
sendEvent(event);
handleDrawEvent(event);
}
}
}

View file

@ -153,7 +153,6 @@ public class CollaborationDrawingToolLayer extends DrawingToolLayer {
event.setCoordinates(new ArrayList<Coordinate>(coordinates));
resource.sendEvent(event);
coordinates.clear();
resource.handleDrawEvent(event);
}
private void sendSimpleEvent(CollaborationEventType type) {
@ -162,7 +161,6 @@ public class CollaborationDrawingToolLayer extends DrawingToolLayer {
event.setType(type);
event.setUserName(resource.getMyUser());
resource.sendEvent(event);
resource.handleDrawEvent(event);
}
public Stack<Collection<Geometry>> getUndoStack() {

View file

@ -39,6 +39,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.event.IHttpdCollaboration
import com.raytheon.uf.viz.collaboration.comm.identity.event.ITextMessageEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IVenueInvitationEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.SharedDisplayVenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IQualifiedID;
import com.raytheon.uf.viz.collaboration.comm.identity.user.SharedDisplayRole;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
@ -65,6 +66,7 @@ import com.raytheon.viz.ui.views.CaveWorkbenchPageManager;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 8, 2012 njensen Initial creation
* Dec 18, 2013 2562 bclement fixed venue invite
*
* </pre>
*
@ -159,17 +161,17 @@ public class ConnectionSubscriber {
}
@Subscribe
public void handleInvitationEvent(IVenueInvitationEvent event) {
final IVenueInvitationEvent invitation = event;
public void handleInvitationEvent(final IVenueInvitationEvent event) {
VizApp.runAsync(new Runnable() {
@Override
public void run() {
IQualifiedID inviter = invitation.getInviter();
IQualifiedID room = invitation.getRoomId();
IQualifiedID inviter = event.getInviter();
IQualifiedID room = event.getRoomId();
Shell shell = new Shell(Display.getCurrent());
StringBuilder sb = new StringBuilder();
boolean sharedDisplay = invitation.getInvite() instanceof SharedDisplayVenueInvite;
VenueInvite invite = event.getInvite();
boolean sharedDisplay = invite instanceof SharedDisplayVenueInvite;
sb.append("You are invited to a ");
if (sharedDisplay) {
sb.append("collaboration session.");
@ -177,8 +179,8 @@ public class ConnectionSubscriber {
sb.append("chat room.");
}
InviteDialog inviteBox = new InviteDialog(shell, inviter
.getName(), invitation.getSubject(), room.getName(), sb
.toString(), invitation.getInvite().getMessage());
.getName(), invite.getSubject(), room.getName(), sb
.toString(), invite.getMessage());
if (!(Boolean) inviteBox.open()) {
return;
}
@ -186,33 +188,27 @@ public class ConnectionSubscriber {
CollaborationConnection connection = CollaborationConnection
.getConnection();
try {
IVenueSession session = connection
.joinCollaborationVenue(invitation);
String sessionId = session.getSessionId();
IVenueSession session;
if (sharedDisplay) {
session = connection.joinCollaborationVenue(event);
ISharedDisplaySession displaySession = (ISharedDisplaySession) session;
SessionColorManager man = new SessionColorManager();
SharedDisplaySessionMgr.joinSession(displaySession,
SharedDisplayRole.PARTICIPANT, man);
CaveWorkbenchPageManager.getActiveInstance().showView(
CollaborationSessionView.ID, sessionId,
CollaborationSessionView.ID, session.getSessionId(),
IWorkbenchPage.VIEW_ACTIVATE);
} else {
session = connection.joinTextOnlyVenue(room.getName());
CaveWorkbenchPageManager.getActiveInstance().showView(
SessionView.ID, sessionId,
SessionView.ID, session.getSessionId(),
IWorkbenchPage.VIEW_ACTIVATE);
}
} catch (CollaborationException e) {
// TODO Auto-generated catch block. Please revise as
// appropriate.
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
statusHandler.error("Unable to join session venue", e);
} catch (PartInitException e) {
// TODO Auto-generated catch block. Please revise as
// appropriate.
statusHandler.handle(Priority.PROBLEM,
e.getLocalizedMessage(), e);
statusHandler.error("Unable to display session view", e);
}
}
});

View file

@ -210,7 +210,6 @@ public class CollaborationSessionView extends SessionView implements
ColorChangeEvent event = new ColorChangeEvent(entry, rgb);
try {
session.sendObjectToVenue(event);
CollaborationSessionView.this.modifyColors(event);
} catch (CollaborationException e) {
statusHandler.handle(Priority.PROBLEM,
"Unable to send color change to venue", e);

View file

@ -58,4 +58,5 @@ Export-Package: org.jivesoftware.smack,
org.jivesoftware.smackx.workgroup.packet,
org.jivesoftware.smackx.workgroup.settings,
org.jivesoftware.smackx.workgroup.user,
org.jivesoftware.smackx.workgroup.util
org.jivesoftware.smackx.workgroup.util,
org.xmlpull.v1