Commit 1dbe2e49 authored by Daniel Henninger's avatar Daniel Henninger Committed by dhenninger

[JM-1217] Couple more improvements to multiple connection support.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@9777 b35dd754-fafc-0310-a699-88a17e54d16e
parent 8cb0cdad
...@@ -1150,8 +1150,12 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -1150,8 +1150,12 @@ public class SessionManager extends BasicModule implements ClusterEventListener
finally { finally {
// Remove the session // Remove the session
localSessionManager.getComponentsSessions().remove(session); localSessionManager.getComponentsSessions().remove(session);
// Remove track of the cluster node hosting the external component // Remove track of the cluster node hosting the external component
componentSessionsCache.remove(session.getAddress().toString()); // if no more components are handling it.
if (!InternalComponentManager.getInstance().hasComponent(session.getAddress())) {
componentSessionsCache.remove(session.getAddress().toString());
}
} }
} }
} }
......
...@@ -47,7 +47,7 @@ import java.util.concurrent.TimeUnit; ...@@ -47,7 +47,7 @@ import java.util.concurrent.TimeUnit;
*/ */
public class InternalComponentManager extends BasicModule implements ComponentManager, RoutableChannelHandler { public class InternalComponentManager extends BasicModule implements ComponentManager, RoutableChannelHandler {
private Map<String, RoutableComponent> routables = new ConcurrentHashMap<String, RoutableComponent>(); final private Map<String, RoutableComponents> routables = new ConcurrentHashMap<String, RoutableComponents>();
private Map<String, IQ> componentInfo = new ConcurrentHashMap<String, IQ>(); private Map<String, IQ> componentInfo = new ConcurrentHashMap<String, IQ>();
private Map<JID, JID> presenceMap = new ConcurrentHashMap<JID, JID>(); private Map<JID, JID> presenceMap = new ConcurrentHashMap<JID, JID>();
/** /**
...@@ -104,107 +104,112 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -104,107 +104,112 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
} }
public void addComponent(String subdomain, Component component) throws ComponentException { public void addComponent(String subdomain, Component component) throws ComponentException {
RoutableComponent routable = routables.get(subdomain); synchronized (routables) {
if (routable != null && routable.hasComponent(component)) { RoutableComponents routable = routables.get(subdomain);
// This component has already registered with this subdomain. if (routable != null && routable.hasComponent(component)) {
// TODO: Is this all we should do? Should we return an error? // This component has already registered with this subdomain.
return; // TODO: Is this all we should do? Should we return an error?
} return;
Log.debug("InternalComponentManager: Registering component for domain: " + subdomain); }
JID componentJID = new JID(subdomain + "." + serverDomain); Log.debug("InternalComponentManager: Registering component for domain: " + subdomain);
if (routable != null) { JID componentJID = new JID(subdomain + "." + serverDomain);
routable.addComponent(component); if (routable != null) {
} routable.addComponent(component);
else { }
routable = new RoutableComponent(componentJID, component); else {
routables.put(subdomain, routable); routable = new RoutableComponents(componentJID, component);
routables.put(subdomain, routable);
// Add the route to the new service provided by the component
XMPPServer.getInstance().getRoutingTable().addComponentRoute(componentJID, routable);
}
// Initialize the new component
try {
component.initialize(componentJID, this);
component.start();
// Notify listeners that a new component has been registered // Add the route to the new service provided by the component
for (ComponentEventListener listener : listeners) { XMPPServer.getInstance().getRoutingTable().addComponentRoute(componentJID, routable);
listener.componentRegistered(component, componentJID);
} }
// Check for potential interested users. // Initialize the new component
checkPresences(); try {
// Send a disco#info request to the new component. If the component provides information component.initialize(componentJID, this);
// then it will be added to the list of discoverable server items. component.start();
checkDiscoSupport(component, componentJID);
Log.debug("InternalComponentManager: Component registered for domain: " + subdomain); // Notify listeners that a new component has been registered
} for (ComponentEventListener listener : listeners) {
catch (Exception e) { listener.componentRegistered(component, componentJID);
// Unregister the component's domain }
routable.removeComponent(component);
if (e instanceof ComponentException) { // Check for potential interested users.
checkPresences();
// Send a disco#info request to the new component. If the component provides information
// then it will be added to the list of discoverable server items.
checkDiscoSupport(component, componentJID);
Log.debug("InternalComponentManager: Component registered for domain: " + subdomain);
}
catch (Exception e) {
// Unregister the component's domain
routable.removeComponent(component);
if (e instanceof ComponentException) {
// Rethrow the exception
throw (ComponentException)e;
}
// Rethrow the exception // Rethrow the exception
throw (ComponentException)e; throw new ComponentException(e);
} }
// Rethrow the exception finally {
throw new ComponentException(e); if (routable.numberOfComponents() == 0) {
} // If there are no more components associated with this subdomain, remove it.
finally { routables.remove(subdomain);
if (routable.numberOfComponents() == 0) { // Remove the route
// If there are no more components associated with this subdomain, remove it. XMPPServer.getInstance().getRoutingTable().removeComponentRoute(componentJID);
routables.remove(subdomain); }
// Remove the route
XMPPServer.getInstance().getRoutingTable().removeComponentRoute(componentJID);
} }
} }
} }
public void removeComponent(String subdomain) { public void removeComponent(String subdomain) {
Log.debug("InternalComponentManager: Unregistering all components for domain: " + subdomain); synchronized (routables) {
RoutableComponent routable = routables.get(subdomain); Log.debug("InternalComponentManager: Unregistering all components for domain: " + subdomain);
routable.removeAllComponents(); RoutableComponents routable = routables.get(subdomain);
routables.remove(subdomain); routable.removeAllComponents();
routables.remove(subdomain);
}
} }
public void removeComponent(String subdomain, Component component) { public void removeComponent(String subdomain, Component component) {
Log.debug("InternalComponentManager: Unregistering component for domain: " + subdomain); synchronized (routables) {
RoutableComponent routable = routables.get(subdomain); Log.debug("InternalComponentManager: Unregistering component for domain: " + subdomain);
routable.removeComponent(component); RoutableComponents routable = routables.get(subdomain);
if (routable.numberOfComponents() == 0) { routable.removeComponent(component);
routables.remove(subdomain); if (routable.numberOfComponents() == 0) {
routables.remove(subdomain);
// Remove any info stored with the component being removed // Remove any info stored with the component being removed
componentInfo.remove(subdomain); componentInfo.remove(subdomain);
JID componentJID = new JID(subdomain + "." + serverDomain); JID componentJID = new JID(subdomain + "." + serverDomain);
// Remove the route for the service provided by the component // Remove the route for the service provided by the component
RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable(); RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable();
if (routingTable != null) { if (routingTable != null) {
routingTable.removeComponentRoute(componentJID); routingTable.removeComponentRoute(componentJID);
} }
// Remove the disco item from the server for the component that is being removed // Remove the disco item from the server for the component that is being removed
IQDiscoItemsHandler iqDiscoItemsHandler = XMPPServer.getInstance().getIQDiscoItemsHandler(); IQDiscoItemsHandler iqDiscoItemsHandler = XMPPServer.getInstance().getIQDiscoItemsHandler();
if (iqDiscoItemsHandler != null) { if (iqDiscoItemsHandler != null) {
iqDiscoItemsHandler.removeComponentItem(componentJID.toBareJID()); iqDiscoItemsHandler.removeComponentItem(componentJID.toBareJID());
} }
// Ask the component to shutdown // Ask the component to shutdown
if (component != null) { if (component != null) {
component.shutdown(); component.shutdown();
} }
// Notify listeners that an existing component has been unregistered // Notify listeners that an existing component has been unregistered
for (ComponentEventListener listener : listeners) { for (ComponentEventListener listener : listeners) {
listener.componentUnregistered(component, componentJID); listener.componentUnregistered(component, componentJID);
}
Log.debug("InternalComponentManager: Component unregistered for domain: " + subdomain);
}
else {
Log.debug("InternalComponentManager: Other components still tied to domain: " + subdomain);
} }
Log.debug("InternalComponentManager: Component unregistered for domain: " + subdomain);
}
else {
Log.debug("InternalComponentManager: Other components still tied to domain: " + subdomain);
} }
} }
...@@ -212,7 +217,7 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -212,7 +217,7 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
if (packet != null && packet.getFrom() == null) { if (packet != null && packet.getFrom() == null) {
throw new IllegalArgumentException("Packet with no FROM address was received from component."); throw new IllegalArgumentException("Packet with no FROM address was received from component.");
} }
PacketRouter router = XMPPServer.getInstance().getPacketRouter(); PacketRouter router = XMPPServer.getInstance().getPacketRouter();
if (router != null) { if (router != null) {
router.route(packet); router.route(packet);
...@@ -259,9 +264,9 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -259,9 +264,9 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
public void addListener(ComponentEventListener listener) { public void addListener(ComponentEventListener listener) {
listeners.add(listener); listeners.add(listener);
// Notify the new listener about existing components // Notify the new listener about existing components
for (Map.Entry<String, RoutableComponent> entry : routables.entrySet()) { for (Map.Entry<String, RoutableComponents> entry : routables.entrySet()) {
String subdomain = entry.getKey(); String subdomain = entry.getKey();
RoutableComponent routable = entry.getValue(); RoutableComponents routable = entry.getValue();
for (Component component : routable.getComponents()) { for (Component component : routable.getComponents()) {
JID componentJID = new JID(subdomain + "." + serverDomain); JID componentJID = new JID(subdomain + "." + serverDomain);
listener.componentRegistered(component, componentJID); listener.componentRegistered(component, componentJID);
...@@ -366,26 +371,28 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -366,26 +371,28 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
* @return the component with the specified id. * @return the component with the specified id.
*/ */
private Component getComponent(JID componentJID) { private Component getComponent(JID componentJID) {
if (componentJID.getNode() != null) { synchronized (routables) {
return null; if (componentJID.getNode() != null) {
} return null;
RoutableComponent routable = routables.get(componentJID.getDomain()); }
if (routable != null) { RoutableComponents routable = routables.get(componentJID.getDomain());
return routable.getNextComponent(); if (routable != null) {
} return routable.getNextComponent();
else { }
// Search again for those JIDs whose domain include the server name but this else {
// time remove the server name from the JID's domain // Search again for those JIDs whose domain include the server name but this
String serverName = componentJID.getDomain(); // time remove the server name from the JID's domain
int index = serverName.lastIndexOf("." + serverDomain); String serverName = componentJID.getDomain();
if (index > -1) { int index = serverName.lastIndexOf("." + serverDomain);
routable = routables.get(serverName.substring(0, index)); if (index > -1) {
if (routable != null) { routable = routables.get(serverName.substring(0, index));
return routable.getNextComponent(); if (routable != null) {
return routable.getNextComponent();
}
} }
} }
return null;
} }
return null;
} }
/** /**
...@@ -396,13 +403,15 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -396,13 +403,15 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
* @return true if a component is associated to the specified address. * @return true if a component is associated to the specified address.
*/ */
public boolean hasComponent(JID componentJID) { public boolean hasComponent(JID componentJID) {
if (componentJID.getNode() != null || componentJID.getResource() != null) { synchronized (routables) {
return false; if (componentJID.getNode() != null || componentJID.getResource() != null) {
return false;
}
// if (componentJID.getDomain().lastIndexOf("." + serverDomain) == -1) {
// componentJID = new JID(componentJID.getDomain() + "." + serverDomain);
// }
return routingTable.hasComponentRoute(componentJID);
} }
// if (componentJID.getDomain().lastIndexOf("." + serverDomain) == -1) {
// componentJID = new JID(componentJID.getDomain() + "." + serverDomain);
// }
return routingTable.hasComponentRoute(componentJID);
} }
/** /**
...@@ -446,7 +455,8 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -446,7 +455,8 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
iq.setChildElement("query", "http://jabber.org/protocol/disco#info"); iq.setChildElement("query", "http://jabber.org/protocol/disco#info");
// Send the disco#info request to the component. The reply (if any) will be processed in // Send the disco#info request to the component. The reply (if any) will be processed in
// #process(Packet) // #process(Packet)
sendPacket(component, iq); // sendPacket(component, iq);
component.processPacket(iq);
} }
public JID getAddress() { public JID getAddress() {
...@@ -468,39 +478,38 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -468,39 +478,38 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
if (packet instanceof IQ && IQ.Type.result == ((IQ) packet).getType()) { if (packet instanceof IQ && IQ.Type.result == ((IQ) packet).getType()) {
IQ iq = (IQ) packet; IQ iq = (IQ) packet;
Element childElement = iq.getChildElement(); Element childElement = iq.getChildElement();
String namespace = null;
if (childElement != null) { if (childElement != null) {
namespace = childElement.getNamespaceURI(); String namespace = childElement.getNamespaceURI();
} if ("http://jabber.org/protocol/disco#info".equals(namespace)) {
if ("http://jabber.org/protocol/disco#info".equals(namespace)) { // Add a disco item to the server for the component that supports disco
// Add a disco item to the server for the component that supports disco Element identity = childElement.element("identity");
Element identity = childElement.element("identity"); if (identity == null) {
if (identity == null) { // Do nothing since there are no identities in the disco#info packet
// Do nothing since there are no identities in the disco#info packet return;
return; }
} try {
try { XMPPServer.getInstance().getIQDiscoItemsHandler().addComponentItem(packet.getFrom()
XMPPServer.getInstance().getIQDiscoItemsHandler().addComponentItem(packet.getFrom() .toBareJID(),
.toBareJID(), identity.attributeValue("name"));
identity.attributeValue("name")); if (component instanceof ComponentSession.ExternalComponent) {
if (component instanceof ComponentSession.ExternalComponent) { ComponentSession.ExternalComponent externalComponent =
ComponentSession.ExternalComponent externalComponent = (ComponentSession.ExternalComponent) component;
(ComponentSession.ExternalComponent) component; externalComponent.setName(identity.attributeValue("name"));
externalComponent.setName(identity.attributeValue("name")); externalComponent.setType(identity.attributeValue("type"));
externalComponent.setType(identity.attributeValue("type")); externalComponent.setCategory(identity.attributeValue("category"));
externalComponent.setCategory(identity.attributeValue("category")); }
}
catch (Exception e) {
Log.error("Error processing disco packet of component: " + component +
" - " + packet.toXML(), e);
}
// Store the IQ disco#info returned by the component
String subdomain = packet.getFrom().getDomain().replace("." + serverDomain, "");
componentInfo.put(subdomain, iq);
// Notify listeners that a component answered the disco#info request
for (ComponentEventListener listener : listeners) {
listener.componentInfoReceived(component, iq);
} }
}
catch (Exception e) {
Log.error("Error processing disco packet of component: " + component +
" - " + packet.toXML(), e);
}
// Store the IQ disco#info returned by the component
String subdomain = packet.getFrom().getDomain().replace("." + serverDomain, "");
componentInfo.put(subdomain, iq);
// Notify listeners that a component answered the disco#info request
for (ComponentEventListener listener : listeners) {
listener.componentInfoReceived(component, iq);
} }
} }
} }
...@@ -510,12 +519,12 @@ public class InternalComponentManager extends BasicModule implements ComponentMa ...@@ -510,12 +519,12 @@ public class InternalComponentManager extends BasicModule implements ComponentMa
/** /**
* Exposes a Component as a RoutableChannelHandler. * Exposes a Component as a RoutableChannelHandler.
*/ */
public static class RoutableComponent implements RoutableChannelHandler { private static class RoutableComponents implements RoutableChannelHandler {
private JID jid; private JID jid;
final private List<Component> components; final private List<Component> components;
public RoutableComponent(JID jid, Component component) { public RoutableComponents(JID jid, Component component) {
this.jid = jid; this.jid = jid;
this.components = new ArrayList<Component>(); this.components = new ArrayList<Component>();
addComponent(component); addComponent(component);
......
...@@ -111,11 +111,11 @@ public class ComponentSocketReader extends SocketReader { ...@@ -111,11 +111,11 @@ public class ComponentSocketReader extends SocketReader {
return false; return false;
} }
boolean createSession(String namespace, Boolean allowMultiple) throws UnauthorizedException, XmlPullParserException, boolean createSession(String namespace) throws UnauthorizedException, XmlPullParserException,
IOException { IOException {
if ("jabber:component:accept".equals(namespace)) { if ("jabber:component:accept".equals(namespace)) {
// The connected client is a component so create a ComponentSession // The connected client is a component so create a ComponentSession
session = LocalComponentSession.createSession(serverName, reader, connection, allowMultiple); session = LocalComponentSession.createSession(serverName, reader, connection);
return true; return true;
} }
return false; return false;
......
...@@ -204,9 +204,8 @@ public class ServerSocketReader extends SocketReader { ...@@ -204,9 +204,8 @@ public class ServerSocketReader extends SocketReader {
threadPool.shutdown(); threadPool.shutdown();
} }
boolean createSession(String namespace, Boolean allowMultiple) throws UnauthorizedException, XmlPullParserException, boolean createSession(String namespace) throws UnauthorizedException, XmlPullParserException,
IOException { IOException {
// TODO: Should we ever consider allowing multiple of this?
if ("jabber:server".equals(namespace)) { if ("jabber:server".equals(namespace)) {
// The connected client is a server so create an IncomingServerSession // The connected client is a server so create an IncomingServerSession
session = LocalIncomingServerSession.createSession(serverName, reader, connection); session = LocalIncomingServerSession.createSession(serverName, reader, connection);
......
...@@ -231,6 +231,7 @@ public abstract class SocketReader implements Runnable { ...@@ -231,6 +231,7 @@ public abstract class SocketReader implements Runnable {
* another thread. * another thread.
* *
* @param packet the received packet. * @param packet the received packet.
* @throws UnauthorizedException if the connection required security but was not secured.
*/ */
protected void processIQ(IQ packet) throws UnauthorizedException { protected void processIQ(IQ packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required // Ensure that connection was secured if TLS was required
...@@ -253,6 +254,7 @@ public abstract class SocketReader implements Runnable { ...@@ -253,6 +254,7 @@ public abstract class SocketReader implements Runnable {
* another thread. * another thread.
* *
* @param packet the received packet. * @param packet the received packet.
* @throws UnauthorizedException if the connection required security but was not secured.
*/ */
protected void processPresence(Presence packet) throws UnauthorizedException { protected void processPresence(Presence packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required // Ensure that connection was secured if TLS was required
...@@ -275,6 +277,7 @@ public abstract class SocketReader implements Runnable { ...@@ -275,6 +277,7 @@ public abstract class SocketReader implements Runnable {
* another thread. * another thread.
* *
* @param packet the received packet. * @param packet the received packet.
* @throws UnauthorizedException if the connection required security but was not secured.
*/ */
protected void processMessage(Message packet) throws UnauthorizedException { protected void processMessage(Message packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required // Ensure that connection was secured if TLS was required
...@@ -348,6 +351,10 @@ public abstract class SocketReader implements Runnable { ...@@ -348,6 +351,10 @@ public abstract class SocketReader implements Runnable {
* If the connection remains open, the XPP will be set to be ready for the * If the connection remains open, the XPP will be set to be ready for the
* first packet. A call to next() should result in an START_TAG state with * first packet. A call to next() should result in an START_TAG state with
* the first packet in the stream. * the first packet in the stream.
*
* @throws UnauthorizedException if the connection required security but was not secured.
* @throws XmlPullParserException if there was an XML error while creating the session.
* @throws IOException if an IO error occured while creating the session.
*/ */
protected void createSession() protected void createSession()
throws UnauthorizedException, XmlPullParserException, IOException { throws UnauthorizedException, XmlPullParserException, IOException {
...@@ -360,7 +367,6 @@ public abstract class SocketReader implements Runnable { ...@@ -360,7 +367,6 @@ public abstract class SocketReader implements Runnable {
// subdomain. If the value of the 'to' attribute is not valid then return a host-unknown // subdomain. If the value of the 'to' attribute is not valid then return a host-unknown
// error and close the underlying connection. // error and close the underlying connection.
String host = reader.getXPPParser().getAttributeValue("", "to"); String host = reader.getXPPParser().getAttributeValue("", "to");
String allowMultiple = reader.getXPPParser().getAttributeValue("", "allowMultiple");
if (validateHost() && isHostUnknown(host)) { if (validateHost() && isHostUnknown(host)) {
StringBuilder sb = new StringBuilder(250); StringBuilder sb = new StringBuilder(250);
sb.append("<?xml version='1.0' encoding='"); sb.append("<?xml version='1.0' encoding='");
...@@ -388,7 +394,7 @@ public abstract class SocketReader implements Runnable { ...@@ -388,7 +394,7 @@ public abstract class SocketReader implements Runnable {
// Create the correct session based on the sent namespace. At this point the server // Create the correct session based on the sent namespace. At this point the server
// may offer the client to secure the connection. If the client decides to secure // may offer the client to secure the connection. If the client decides to secure
// the connection then a <starttls> stanza should be received // the connection then a <starttls> stanza should be received
else if (!createSession(xpp.getNamespace(null), allowMultiple != null)) { else if (!createSession(xpp.getNamespace(null))) {
// No session was created because of an invalid namespace prefix so answer a stream // No session was created because of an invalid namespace prefix so answer a stream
// error and close the underlying connection // error and close the underlying connection
StringBuilder sb = new StringBuilder(250); StringBuilder sb = new StringBuilder(250);
...@@ -457,12 +463,11 @@ public abstract class SocketReader implements Runnable { ...@@ -457,12 +463,11 @@ public abstract class SocketReader implements Runnable {
* Creates the appropriate {@link org.jivesoftware.openfire.session.Session} subclass based on the specified namespace. * Creates the appropriate {@link org.jivesoftware.openfire.session.Session} subclass based on the specified namespace.
* *
* @param namespace the namespace sent in the stream element. eg. jabber:client. * @param namespace the namespace sent in the stream element. eg. jabber:client.
* @param allowMultiple Allow multiple bindings to the specified domain.
* @return the created session or null. * @return the created session or null.
* @throws UnauthorizedException * @throws UnauthorizedException if the connection required security but was not secured.
* @throws XmlPullParserException * @throws XmlPullParserException if there was an XML error while creating the session.
* @throws IOException * @throws IOException if an IO error occured while creating the session.
*/ */
abstract boolean createSession(String namespace, Boolean allowMultiple) throws UnauthorizedException, abstract boolean createSession(String namespace) throws UnauthorizedException,
XmlPullParserException, IOException; XmlPullParserException, IOException;
} }
...@@ -55,15 +55,18 @@ public class LocalComponentSession extends LocalSession implements ComponentSess ...@@ -55,15 +55,18 @@ public class LocalComponentSession extends LocalSession implements ComponentSess
* @param serverName the name of the server where the session is connecting to. * @param serverName the name of the server where the session is connecting to.
* @param reader the reader that is reading the provided XML through the connection. * @param reader the reader that is reading the provided XML through the connection.
* @param connection the connection with the component. * @param connection the connection with the component.
* @param allowMultiple the specified domain is allowed to be connected to multiple times.
* @return a newly created session between the server and a component. * @return a newly created session between the server and a component.
* @throws UnauthorizedException if the connection required security but was not secured.
* @throws XmlPullParserException if there was an XML error while creating the session.
* @throws IOException if an IO error occured while creating the session.
*/ */
public static LocalComponentSession createSession(String serverName, XMPPPacketReader reader, public static LocalComponentSession createSession(String serverName, XMPPPacketReader reader,
SocketConnection connection, Boolean allowMultiple) throws UnauthorizedException, IOException, SocketConnection connection) throws UnauthorizedException, IOException,
XmlPullParserException XmlPullParserException
{ {
XmlPullParser xpp = reader.getXPPParser(); XmlPullParser xpp = reader.getXPPParser();
String domain = xpp.getAttributeValue("", "to"); String domain = xpp.getAttributeValue("", "to");
Boolean allowMultiple = reader.getXPPParser().getAttributeValue("", "allowMultiple") != null;
Log.debug("LocalComponentSession: [ExComp] Starting registration of new external component for domain: " + domain); Log.debug("LocalComponentSession: [ExComp] Starting registration of new external component for domain: " + domain);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment