Commit 2ff9c063 authored by daryl herzmann's avatar daryl herzmann

Merge pull request #180 from tevans/OF-879

OF-879: Update hazelcast namespace, dependencies
parents 2778db9b dc97a815
...@@ -94,7 +94,7 @@ public class CacheFactory { ...@@ -94,7 +94,7 @@ public class CacheFactory {
localCacheFactoryClass = JiveGlobals.getProperty(LOCAL_CACHE_PROPERTY_NAME, localCacheFactoryClass = JiveGlobals.getProperty(LOCAL_CACHE_PROPERTY_NAME,
"org.jivesoftware.util.cache.DefaultLocalCacheStrategy"); "org.jivesoftware.util.cache.DefaultLocalCacheStrategy");
clusteredCacheFactoryClass = JiveGlobals.getProperty(CLUSTERED_CACHE_PROPERTY_NAME, clusteredCacheFactoryClass = JiveGlobals.getProperty(CLUSTERED_CACHE_PROPERTY_NAME,
"com.jivesoftware.util.cache.ClusteredCacheFactory"); "org.jivesoftware.openfire.plugin.util.cache.ClusteredCacheFactory");
cacheNames.put("Favicon Hits", "faviconHits"); cacheNames.put("Favicon Hits", "faviconHits");
cacheNames.put("Favicon Misses", "faviconMisses"); cacheNames.put("Favicon Misses", "faviconMisses");
......
...@@ -44,6 +44,13 @@ ...@@ -44,6 +44,13 @@
Hazelcast Clustering Plugin Changelog Hazelcast Clustering Plugin Changelog
</h1> </h1>
<p><b>2.0.0</b> -- February 6, 2015</p>
<p>Hazelcast update:</p>
<ul>
<li>Updated Hazelcast to latest release (3.4).</li>
<li>Repackaged to use Openfire's org.jivesoftware.openfire namespace prefix (rather than com.jivesoftware.openfire).</li>
</ul>
<p><b>1.3.4</b> -- January 10, 2015</p> <p><b>1.3.4</b> -- January 10, 2015</p>
<p>Bug fixes:</p> <p>Bug fixes:</p>
<ul> <ul>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
~ limitations under the License. ~ limitations under the License.
--> -->
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.3.xsd" <hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.4.xsd"
xmlns="http://www.hazelcast.com/schema/config" xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<group> <group>
...@@ -59,7 +59,20 @@ ...@@ -59,7 +59,20 @@
Any integer between 0 and Integer.MAX_VALUE. 0 means Any integer between 0 and Integer.MAX_VALUE. 0 means
Integer.MAX_VALUE. Default is 0. Integer.MAX_VALUE. Default is 0.
--> -->
<max-size-per-jvm>0</max-size-per-jvm> <max-size>0</max-size>
<!--
Number of backups. If 1 is set as the backup-count for example,
then all entries of the map will be copied to another JVM for
fail-safety. 0 means no backup.
-->
<backup-count>1</backup-count>
<!--
Number of async backups. 0 means no backup.
-->
<async-backup-count>0</async-backup-count>
<empty-queue-ttl>-1</empty-queue-ttl>
<!-- <!--
Name of the map configuration that will be used for the backing distributed Name of the map configuration that will be used for the backing distributed
map for this queue. map for this queue.
...@@ -70,6 +83,15 @@ ...@@ -70,6 +83,15 @@
Default Hazelcast cache configuration for Openfire. Default Hazelcast cache configuration for Openfire.
--> -->
<map name="default"> <map name="default">
<!--
Data type that will be used for storing recordMap.
Possible values:
BINARY (default): keys and values will be stored as binary data
OBJECT : values will be stored in their object forms
NATIVE : values will be stored in non-heap region of JVM
-->
<in-memory-format>BINARY</in-memory-format>
<!-- <!--
Number of backups. If 1 is set as the backup-count for example, Number of backups. If 1 is set as the backup-count for example,
then all entries of the map will be copied to another JVM for then all entries of the map will be copied to another JVM for
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<plugin> <plugin>
<class>com.jivesoftware.openfire.HazelcastPlugin</class> <class>org.jivesoftware.openfire.plugin.HazelcastPlugin</class>
<name>${plugin.name}</name> <name>${plugin.name}</name>
<description>${plugin.description}</description> <description>${plugin.description}</description>
<author>Tom Evans</author> <author>Tom Evans</author>
<version>1.3.4</version> <version>2.0.0</version>
<date>01/10/2015</date> <date>02/06/2015</date>
<minServerVersion>3.9.4</minServerVersion> <minServerVersion>3.9.4</minServerVersion>
</plugin> </plugin>
...@@ -65,7 +65,32 @@ open source <a href="http://www.hazelcast.org">Hazelcast</a> data distribution ...@@ -65,7 +65,32 @@ open source <a href="http://www.hazelcast.org">Hazelcast</a> data distribution
framework in lieu of an expensive proprietary third-party product. framework in lieu of an expensive proprietary third-party product.
</p> </p>
<p> <p>
The current Hazelcast release is version 3.3.3. The current Hazelcast release is version 3.4.
</p>
<h3>Clustering vs. Federation</h3>
<p>XMPP is designed to scale in ways that are similar to email. Each Openfire
installation supports a single XMPP domain, and a server-to-server (S2S)
protocol as described in the specification is provided to link multiple XMPP
domains together. This is known as federation. It represents a powerful way to
"scale out" XMPP, as it allows an XMPP user to communicate securely with any
user in any other such federated domain. These federations may be public or
private as appropriate. Federated domains may exchange XMPP stanzas
across the Internet (WAN) and may even discover one another using DNS-based
service lookup and address resolution.
</p>
<p>By contrast, clustering is a technique used to "scale up" a single XMPP domain.
The server members within a cluster all share an identical configuration. Each
member will allow any user within the domain to connect, authenticate, and exchange
stanzas. Clustered servers all share a single database, and are also required to
be resident within the same LAN-based (low latency) network infrastructure. This
type of deployment is suitable to provide runtime redundancy and will support a
larger number of users and connections (within a single domain) than a single
server would be able to provide.
</p>
<p>For very large Openfire deployments, a combination of federation and clustering will
provide the best results. Whereas a single clustered XMPP domain will be able to
support tens or even hundreds of thousands of users, a federated deployment will be
needed to reach true Internet scale of millions of concurrent XMPP connections.
</p> </p>
<h2>Installation</h2> <h2>Installation</h2>
<p> <p>
...@@ -181,10 +206,10 @@ that will be added to the plugin's classpath. This allows a custom Hazelcast ...@@ -181,10 +206,10 @@ that will be added to the plugin's classpath. This allows a custom Hazelcast
configuration file to be located outside the Openfire home directory.</li> configuration file to be located outside the Openfire home directory.</li>
<li><i>hazelcast.config.jmx.enabled</i> (false): Enables JMX support for <li><i>hazelcast.config.jmx.enabled</i> (false): Enables JMX support for
the Hazelcast cluster if JMX has been enabled via the Openfire admin console. the Hazelcast cluster if JMX has been enabled via the Openfire admin console.
Refer to the <a href="http://docs.hazelcast.org/docs/3.3/manual/html/monitoringwithjmx.html"> Refer to the <a href="http://docs.hazelcast.org/docs/3.4/manual/html/monitoringwithjmx.html">
Hazelcast JMX docs</a> for additional information.</li> Hazelcast JMX docs</a> for additional information.</li>
</ol> </ol>
<p>The Hazelcast plugin uses the <a href="http://docs.hazelcast.org/docs/3.3/manual/html/config.html"> <p>The Hazelcast plugin uses the <a href="http://docs.hazelcast.org/docs/3.4/manual/html/configurationoverview.html">
XML configuration builder</a> to initialize the cluster from the XML file described above. XML configuration builder</a> to initialize the cluster from the XML file described above.
By default the cluster members will attempt to discover each other via multicast at the By default the cluster members will attempt to discover each other via multicast at the
following location: following location:
...@@ -210,8 +235,33 @@ following alternative: ...@@ -210,8 +235,33 @@ following alternative:
&lt;/join&gt; &lt;/join&gt;
... ...
</pre> </pre>
<p>Please refer to the <a href="http://docs.hazelcast.org/docs/3.3/manual/html-single/"> <p>Please refer to the <a href="http://docs.hazelcast.org/docs/3.4/manual/html-single/">
Hazelcast reference manual</a> for more information. Hazelcast reference manual</a> for more information.
</p> </p>
<h3>A Word About Garbage Collection</h3>
<p>Hazelcast is quite sensitive to delays that may be caused by long-running GC cycles which are typical
of servers using a default runtime JVM configuration. In most cases it will be preferable to activate the
concurrent garbage collector (CMS) or the new G1 garbage collector to minimize blocking within the JVM.
When using CMS, you may be able to counter the effects of heap fragmentation by using JMX to invoke
System.gc() when the cluster is relatively idle (e.g. overnight). This has the effect of temporarily
interrupting the concurrent GC algortithm in favor of the default GC to collect and compact the heap.
</p>
<p>In addition, the runtime characteristics of your Openfire cluster will vary greatly depending on the
number and type of clients that are connected, and which XMPP services you are using in your deployment.
However, note that because many of the objects allocated on the heap are of the short-lived variety,
increasing the proportion of young generation (eden) space may also have a positive impact on performance.
As an example, the following OPENFIRE_OPTS have been shown to be suitable in a three-node cluster of
servers (four CPUs each), supporting approximately 50k active users:
</p>
<pre>
OPENFIRE_OPTS="-Xmx4G -Xms4G -XX:NewRatio=1 -XX:SurvivorRatio=4
-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled -XX:CMSFullGCsBeforeCompaction=1
-XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly
-XX:+PrintGCDetails -XX:+PrintPromotionFailure"
</pre>
<p>This GC configuration will also emit helpful GC diagnostic information to the console to aid further
tuning and troubleshooting as appropriate for your deployment.
</p>
</body> </body>
</html> </html>
/** /**
* $RCSfile$ * $RCSfile$
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2004-2009 Jive Software. All rights reserved. * Copyright (C) 2004-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire; package org.jivesoftware.openfire.plugin;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.util.TimerTask; import java.util.TimerTask;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.ClusterManager; import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.container.Plugin; import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager; import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.TaskEngine; import org.jivesoftware.util.TaskEngine;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Hazelcast clustering plugin. This implementation is based upon * Hazelcast clustering plugin. This implementation is based upon
* (and borrows heavily from) the original Openfire clustering plugin. * (and borrows heavily from) the original Openfire clustering plugin.
* See this plugin's README file for more information. * See this plugin's README file for more information.
* *
* @author Tom Evans * @author Tom Evans
* @author Matt Tucker * @author Matt Tucker
*/ */
public class HazelcastPlugin extends TimerTask implements Plugin { public class HazelcastPlugin extends TimerTask implements Plugin {
private static Logger logger = LoggerFactory.getLogger(HazelcastPlugin.class); private static Logger logger = LoggerFactory.getLogger(HazelcastPlugin.class);
private static final long CLUSTER_STARTUP_DELAY_TIME = private static final long CLUSTER_STARTUP_DELAY_TIME =
JiveGlobals.getLongProperty("hazelcast.startup.delay.seconds", 5); JiveGlobals.getLongProperty("hazelcast.startup.delay.seconds", 5);
public void initializePlugin(PluginManager manager, File pluginDirectory) { public void initializePlugin(PluginManager manager, File pluginDirectory) {
// start cluster using a separate thread after a short delay // start cluster using a separate thread after a short delay
// this will allow other plugins to initialize during startup // this will allow other plugins to initialize during startup
TaskEngine.getInstance().schedule(this, CLUSTER_STARTUP_DELAY_TIME*1000); TaskEngine.getInstance().schedule(this, CLUSTER_STARTUP_DELAY_TIME*1000);
} }
@Override @Override
public void run() { public void run() {
System.out.println("Starting Hazelcast Clustering Plugin"); System.out.println("Starting Hazelcast Clustering Plugin");
// Check if another cluster is installed and stop loading this plugin if found // Check if another cluster is installed and stop loading this plugin if found
File pluginDir = new File(JiveGlobals.getHomeDirectory(), "plugins"); File pluginDir = new File(JiveGlobals.getHomeDirectory(), "plugins");
File[] jars = pluginDir.listFiles(new FileFilter() { File[] jars = pluginDir.listFiles(new FileFilter() {
public boolean accept(File pathname) { public boolean accept(File pathname) {
String fileName = pathname.getName().toLowerCase(); String fileName = pathname.getName().toLowerCase();
return (fileName.equalsIgnoreCase("enterprise.jar") || return (fileName.equalsIgnoreCase("enterprise.jar") ||
fileName.equalsIgnoreCase("coherence.jar")); fileName.equalsIgnoreCase("coherence.jar"));
} }
}); });
if (jars.length > 0) { if (jars.length > 0) {
// Do not load this plugin if a conflicting implementation exists // Do not load this plugin if a conflicting implementation exists
logger.warn("Conflicting clustering plugins found; remove Coherence and/or Enterprise jar files"); logger.warn("Conflicting clustering plugins found; remove Coherence and/or Enterprise jar files");
throw new IllegalStateException("Clustering plugin configuration conflict (Coherence)"); throw new IllegalStateException("Clustering plugin configuration conflict (Coherence)");
} }
ClusterManager.startup(); ClusterManager.startup();
} }
public void destroyPlugin() { public void destroyPlugin() {
// Shutdown is initiated by XMPPServer before unloading plugins // Shutdown is initiated by XMPPServer before unloading plugins
if (!XMPPServer.getInstance().isShuttingDown()) { if (!XMPPServer.getInstance().isShuttingDown()) {
ClusterManager.shutdown(); ClusterManager.shutdown();
} }
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.NodeID; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.session.ClientSession; import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.spi.ClientRoute; import org.jivesoftware.openfire.spi.ClientRoute;
import org.jivesoftware.openfire.spi.RoutingTableImpl; import org.jivesoftware.openfire.spi.RoutingTableImpl;
import org.jivesoftware.util.cache.Cache; import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheFactory; import org.jivesoftware.util.cache.CacheFactory;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
/** /**
* Class that defines possible remote operations that could be performed * Class that defines possible remote operations that could be performed
* on remote client sessions. * on remote client sessions.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class ClientSessionTask extends RemoteSessionTask { public class ClientSessionTask extends RemoteSessionTask {
private static Logger logger = LoggerFactory.getLogger(ClientSessionTask.class); private static Logger logger = LoggerFactory.getLogger(ClientSessionTask.class);
private JID address; private JID address;
private transient Session session; private transient Session session;
public ClientSessionTask() { public ClientSessionTask() {
super(); super();
} }
protected ClientSessionTask(JID address, Operation operation) { protected ClientSessionTask(JID address, Operation operation) {
super(operation); super(operation);
this.address = address; this.address = address;
} }
Session getSession() { Session getSession() {
if (session == null) { if (session == null) {
session = XMPPServer.getInstance().getRoutingTable().getClientRoute(address); session = XMPPServer.getInstance().getRoutingTable().getClientRoute(address);
} }
return session; return session;
} }
public void run() { public void run() {
if (getSession() == null || getSession().isClosed()) { if (getSession() == null || getSession().isClosed()) {
logger.error("Session not found for JID: " + address); logger.error("Session not found for JID: " + address);
return; return;
} }
super.run(); super.run();
ClientSession session = (ClientSession) getSession(); ClientSession session = (ClientSession) getSession();
if (session instanceof RemoteClientSession) { if (session instanceof RemoteClientSession) {
// The session is being hosted by other cluster node so log this unexpected case // The session is being hosted by other cluster node so log this unexpected case
Cache<String, ClientRoute> usersCache = CacheFactory.createCache(RoutingTableImpl.C2S_CACHE_NAME); Cache<String, ClientRoute> usersCache = CacheFactory.createCache(RoutingTableImpl.C2S_CACHE_NAME);
ClientRoute route = usersCache.get(address.toString()); ClientRoute route = usersCache.get(address.toString());
NodeID nodeID = route.getNodeID(); NodeID nodeID = route.getNodeID();
logger.warn("Found remote session instead of local session. JID: " + address + " found in Node: " + logger.warn("Found remote session instead of local session. JID: " + address + " found in Node: " +
nodeID.toByteArray() + " and local node is: " + XMPPServer.getInstance().getNodeID().toByteArray()); nodeID.toByteArray() + " and local node is: " + XMPPServer.getInstance().getNodeID().toByteArray());
} }
if (operation == Operation.isInitialized) { if (operation == Operation.isInitialized) {
if (session instanceof RemoteClientSession) { if (session instanceof RemoteClientSession) {
// Something is wrong since the session shoud be local instead of remote // Something is wrong since the session shoud be local instead of remote
// Assume some default value // Assume some default value
result = true; result = true;
} }
else { else {
result = session.isInitialized(); result = session.isInitialized();
} }
} }
else if (operation == Operation.incrementConflictCount) { else if (operation == Operation.incrementConflictCount) {
if (session instanceof RemoteClientSession) { if (session instanceof RemoteClientSession) {
// Something is wrong since the session shoud be local instead of remote // Something is wrong since the session shoud be local instead of remote
// Assume some default value // Assume some default value
result = 2; result = 2;
} }
else { else {
result = session.incrementConflictCount(); result = session.incrementConflictCount();
} }
} }
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, address); ExternalizableUtil.getInstance().writeSerializable(out, address);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
address = (JID) ExternalizableUtil.getInstance().readSerializable(in); address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
} }
public String toString() { public String toString() {
return super.toString() + " operation: " + operation + " address: " + address; return super.toString() + " operation: " + operation + " address: " + address;
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.ComponentSession; import org.jivesoftware.openfire.session.ComponentSession;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
/** /**
* Class that defines possible remote operations that could be performed * Class that defines possible remote operations that could be performed
* on remote component sessions (for external components only). * on remote component sessions (for external components only).
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class ComponentSessionTask extends RemoteSessionTask { public class ComponentSessionTask extends RemoteSessionTask {
private JID address; private JID address;
public ComponentSessionTask() { public ComponentSessionTask() {
} }
protected ComponentSessionTask(JID address, Operation operation) { protected ComponentSessionTask(JID address, Operation operation) {
super(operation); super(operation);
this.address = address; this.address = address;
} }
Session getSession() { Session getSession() {
return SessionManager.getInstance().getComponentSession(address.getDomain()); return SessionManager.getInstance().getComponentSession(address.getDomain());
} }
public void run() { public void run() {
super.run(); super.run();
if (operation == Operation.getType) { if (operation == Operation.getType) {
result = ((ComponentSession) getSession()).getExternalComponent().getType(); result = ((ComponentSession) getSession()).getExternalComponent().getType();
} }
else if (operation == Operation.getCategory) { else if (operation == Operation.getCategory) {
result = ((ComponentSession) getSession()).getExternalComponent().getCategory(); result = ((ComponentSession) getSession()).getExternalComponent().getCategory();
} }
else if (operation == Operation.getInitialSubdomain) { else if (operation == Operation.getInitialSubdomain) {
result = ((ComponentSession) getSession()).getExternalComponent().getInitialSubdomain(); result = ((ComponentSession) getSession()).getExternalComponent().getInitialSubdomain();
} }
else if (operation == Operation.getSubdomains) { else if (operation == Operation.getSubdomains) {
result = ((ComponentSession) getSession()).getExternalComponent().getSubdomains(); result = ((ComponentSession) getSession()).getExternalComponent().getSubdomains();
} }
else if (operation == Operation.getName) { else if (operation == Operation.getName) {
result = ((ComponentSession) getSession()).getExternalComponent().getName(); result = ((ComponentSession) getSession()).getExternalComponent().getName();
} }
else if (operation == Operation.getDescription) { else if (operation == Operation.getDescription) {
result = ((ComponentSession) getSession()).getExternalComponent().getDescription(); result = ((ComponentSession) getSession()).getExternalComponent().getDescription();
} }
else if (operation == Operation.start) { else if (operation == Operation.start) {
((ComponentSession) getSession()).getExternalComponent().start(); ((ComponentSession) getSession()).getExternalComponent().start();
} }
else if (operation == Operation.shutdown) { else if (operation == Operation.shutdown) {
((ComponentSession) getSession()).getExternalComponent().shutdown(); ((ComponentSession) getSession()).getExternalComponent().shutdown();
} }
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, address); ExternalizableUtil.getInstance().writeSerializable(out, address);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
address = (JID) ExternalizableUtil.getInstance().readSerializable(in); address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
} }
public String toString() { public String toString() {
return super.toString() + " operation: " + operation + " address: " + address; return super.toString() + " operation: " + operation + " address: " + address;
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
/** /**
* Class that defines possible remote operations that could be performed * Class that defines possible remote operations that could be performed
* on remote connection manager sessions. * on remote connection manager sessions.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class ConnectionMultiplexerSessionTask extends RemoteSessionTask { public class ConnectionMultiplexerSessionTask extends RemoteSessionTask {
private JID address; private JID address;
public ConnectionMultiplexerSessionTask() { public ConnectionMultiplexerSessionTask() {
} }
protected ConnectionMultiplexerSessionTask(JID address, Operation operation) { protected ConnectionMultiplexerSessionTask(JID address, Operation operation) {
super(operation); super(operation);
this.address = address; this.address = address;
} }
Session getSession() { Session getSession() {
return SessionManager.getInstance().getConnectionMultiplexerSession(address); return SessionManager.getInstance().getConnectionMultiplexerSession(address);
} }
public String toString() { public String toString() {
return super.toString() + " operation: " + operation + " address: " + address; return super.toString() + " operation: " + operation + " address: " + address;
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
/** /**
* Cluster task that will ask a remote cluster node to deliver some raw text to a local session. * Cluster task that will ask a remote cluster node to deliver some raw text to a local session.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class DeliverRawTextTask implements ClusterTask { public class DeliverRawTextTask implements ClusterTask {
private SessionType sessionType; private SessionType sessionType;
private JID address; private JID address;
private String streamID; private String streamID;
private String text; private String text;
public DeliverRawTextTask() { public DeliverRawTextTask() {
super(); super();
} }
protected DeliverRawTextTask(RemoteSession remoteSession, JID address, String text) { protected DeliverRawTextTask(RemoteSession remoteSession, JID address, String text) {
if (remoteSession instanceof RemoteClientSession) { if (remoteSession instanceof RemoteClientSession) {
this.sessionType = SessionType.client; this.sessionType = SessionType.client;
} }
else if (remoteSession instanceof RemoteOutgoingServerSession) { else if (remoteSession instanceof RemoteOutgoingServerSession) {
this.sessionType = SessionType.outgoingServer; this.sessionType = SessionType.outgoingServer;
} }
else if (remoteSession instanceof RemoteComponentSession) { else if (remoteSession instanceof RemoteComponentSession) {
this.sessionType = SessionType.component; this.sessionType = SessionType.component;
} }
else if (remoteSession instanceof RemoteConnectionMultiplexerSession) { else if (remoteSession instanceof RemoteConnectionMultiplexerSession) {
this.sessionType = SessionType.connectionManager; this.sessionType = SessionType.connectionManager;
} }
else { else {
Log.error("Invalid RemoteSession was used for task: " + remoteSession); Log.error("Invalid RemoteSession was used for task: " + remoteSession);
} }
this.address = address; this.address = address;
this.text = text; this.text = text;
} }
public DeliverRawTextTask(String streamID, String text) { public DeliverRawTextTask(String streamID, String text) {
this.sessionType = SessionType.incomingServer; this.sessionType = SessionType.incomingServer;
this.streamID = streamID; this.streamID = streamID;
this.text = text; this.text = text;
} }
public Object getResult() { public Object getResult() {
return null; return null;
} }
public void run() { public void run() {
getSession().deliverRawText(text); getSession().deliverRawText(text);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSafeUTF(out, text); ExternalizableUtil.getInstance().writeSafeUTF(out, text);
ExternalizableUtil.getInstance().writeInt(out, sessionType.ordinal()); ExternalizableUtil.getInstance().writeInt(out, sessionType.ordinal());
ExternalizableUtil.getInstance().writeBoolean(out, address != null); ExternalizableUtil.getInstance().writeBoolean(out, address != null);
if (address != null) { if (address != null) {
ExternalizableUtil.getInstance().writeSerializable(out, address); ExternalizableUtil.getInstance().writeSerializable(out, address);
} }
ExternalizableUtil.getInstance().writeBoolean(out, streamID != null); ExternalizableUtil.getInstance().writeBoolean(out, streamID != null);
if (streamID != null) { if (streamID != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, streamID); ExternalizableUtil.getInstance().writeSafeUTF(out, streamID);
} }
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
text = ExternalizableUtil.getInstance().readSafeUTF(in); text = ExternalizableUtil.getInstance().readSafeUTF(in);
sessionType = SessionType.values()[ExternalizableUtil.getInstance().readInt(in)]; sessionType = SessionType.values()[ExternalizableUtil.getInstance().readInt(in)];
if (ExternalizableUtil.getInstance().readBoolean(in)) { if (ExternalizableUtil.getInstance().readBoolean(in)) {
address = (JID) ExternalizableUtil.getInstance().readSerializable(in); address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
} }
if (ExternalizableUtil.getInstance().readBoolean(in)) { if (ExternalizableUtil.getInstance().readBoolean(in)) {
streamID = ExternalizableUtil.getInstance().readSafeUTF(in); streamID = ExternalizableUtil.getInstance().readSafeUTF(in);
} }
} }
Session getSession() { Session getSession() {
if (sessionType == SessionType.client) { if (sessionType == SessionType.client) {
return XMPPServer.getInstance().getRoutingTable().getClientRoute(address); return XMPPServer.getInstance().getRoutingTable().getClientRoute(address);
} }
else if (sessionType == SessionType.component) { else if (sessionType == SessionType.component) {
return SessionManager.getInstance().getComponentSession(address.getDomain()); return SessionManager.getInstance().getComponentSession(address.getDomain());
} }
else if (sessionType == SessionType.connectionManager) { else if (sessionType == SessionType.connectionManager) {
return SessionManager.getInstance().getConnectionMultiplexerSession(address); return SessionManager.getInstance().getConnectionMultiplexerSession(address);
} }
else if (sessionType == SessionType.outgoingServer) { else if (sessionType == SessionType.outgoingServer) {
return SessionManager.getInstance().getOutgoingServerSession(address.getDomain()); return SessionManager.getInstance().getOutgoingServerSession(address.getDomain());
} }
else if (sessionType == SessionType.incomingServer) { else if (sessionType == SessionType.incomingServer) {
return SessionManager.getInstance().getIncomingServerSession(streamID); return SessionManager.getInstance().getIncomingServerSession(streamID);
} }
Log.error("Found unknown session type: " + sessionType); Log.error("Found unknown session type: " + sessionType);
return null; return null;
} }
public String toString() { public String toString() {
return super.toString() + " sessionType: " + sessionType + " address: " + address; return super.toString() + " sessionType: " + sessionType + " address: " + address;
} }
private enum SessionType { private enum SessionType {
client, client,
outgoingServer, outgoingServer,
incomingServer, incomingServer,
component, component,
connectionManager connectionManager
} }
} }
\ No newline at end of file
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.IncomingServerSession; import org.jivesoftware.openfire.session.IncomingServerSession;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
/** /**
* Class that defines possible remote operations that could be performed * Class that defines possible remote operations that could be performed
* on remote incoming server sessions. * on remote incoming server sessions.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class IncomingServerSessionTask extends RemoteSessionTask { public class IncomingServerSessionTask extends RemoteSessionTask {
private String streamID; private String streamID;
public IncomingServerSessionTask() { public IncomingServerSessionTask() {
super(); super();
} }
protected IncomingServerSessionTask(Operation operation, String streamID) { protected IncomingServerSessionTask(Operation operation, String streamID) {
super(operation); super(operation);
this.streamID = streamID; this.streamID = streamID;
} }
Session getSession() { Session getSession() {
return SessionManager.getInstance().getIncomingServerSession(streamID); return SessionManager.getInstance().getIncomingServerSession(streamID);
} }
public void run() { public void run() {
super.run(); super.run();
if (operation == Operation.getLocalDomain) { if (operation == Operation.getLocalDomain) {
result = ((IncomingServerSession) getSession()).getLocalDomain(); result = ((IncomingServerSession) getSession()).getLocalDomain();
} }
else if (operation == Operation.getAddress) { else if (operation == Operation.getAddress) {
result = getSession().getAddress(); result = getSession().getAddress();
} }
else if (operation == Operation.isUsingServerDialback) { else if (operation == Operation.isUsingServerDialback) {
result = ((IncomingServerSession) getSession()).isUsingServerDialback(); result = ((IncomingServerSession) getSession()).isUsingServerDialback();
} }
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF(out, streamID); ExternalizableUtil.getInstance().writeSafeUTF(out, streamID);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
streamID = ExternalizableUtil.getInstance().readSafeUTF(in); streamID = ExternalizableUtil.getInstance().readSafeUTF(in);
} }
public String toString() { public String toString() {
return super.toString() + " operation: " + operation + " streamID: " + streamID; return super.toString() + " operation: " + operation + " streamID: " + streamID;
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.OutgoingServerSession; import org.jivesoftware.openfire.session.OutgoingServerSession;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
/** /**
* Class that defines possible remote operations that could be performed * Class that defines possible remote operations that could be performed
* on remote outgoing server sessions. * on remote outgoing server sessions.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class OutgoingServerSessionTask extends RemoteSessionTask { public class OutgoingServerSessionTask extends RemoteSessionTask {
private JID address; private JID address;
public OutgoingServerSessionTask() { public OutgoingServerSessionTask() {
} }
protected OutgoingServerSessionTask(JID address, Operation operation) { protected OutgoingServerSessionTask(JID address, Operation operation) {
super(operation); super(operation);
this.address = address; this.address = address;
} }
Session getSession() { Session getSession() {
return SessionManager.getInstance().getOutgoingServerSession(address.getDomain()); return SessionManager.getInstance().getOutgoingServerSession(address.getDomain());
} }
public void run() { public void run() {
super.run(); super.run();
if (operation == Operation.getAuthenticatedDomains) { if (operation == Operation.getAuthenticatedDomains) {
result = ((OutgoingServerSession) getSession()).getAuthenticatedDomains(); result = ((OutgoingServerSession) getSession()).getAuthenticatedDomains();
} }
else if (operation == Operation.getHostnames) { else if (operation == Operation.getHostnames) {
result = ((OutgoingServerSession) getSession()).getHostnames(); result = ((OutgoingServerSession) getSession()).getHostnames();
} }
else if (operation == Operation.isUsingServerDialback) { else if (operation == Operation.isUsingServerDialback) {
result = ((OutgoingServerSession) getSession()).isUsingServerDialback(); result = ((OutgoingServerSession) getSession()).isUsingServerDialback();
} }
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, address); ExternalizableUtil.getInstance().writeSerializable(out, address);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
address = (JID) ExternalizableUtil.getInstance().readSerializable(in); address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
} }
public String toString() { public String toString() {
return super.toString() + " operation: " + operation + " address: " + address; return super.toString() + " operation: " + operation + " address: " + address;
} }
} }
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.tree.DefaultElement; import org.dom4j.tree.DefaultElement;
......
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.tree.DefaultElement; import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.privacy.PrivacyList; import org.jivesoftware.openfire.privacy.PrivacyList;
import org.jivesoftware.openfire.privacy.PrivacyListManager; import org.jivesoftware.openfire.privacy.PrivacyListManager;
import org.jivesoftware.openfire.session.ClientSession; import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.ClientSessionInfo; import org.jivesoftware.openfire.session.ClientSessionInfo;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.cache.Cache; import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
/** /**
* Surrogate for client sessions hosted in some remote cluster node. * Surrogate for client sessions hosted in some remote cluster node.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class RemoteClientSession extends RemoteSession implements ClientSession { public class RemoteClientSession extends RemoteSession implements ClientSession {
private long initialized = -1; private long initialized = -1;
private boolean messageCarbonsEnabled; private boolean messageCarbonsEnabled;
public RemoteClientSession(byte[] nodeID, JID address) { public RemoteClientSession(byte[] nodeID, JID address) {
super(nodeID, address); super(nodeID, address);
} }
public PrivacyList getActiveList() { public PrivacyList getActiveList() {
Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache(); Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
ClientSessionInfo sessionInfo = cache.get(getAddress().toString()); ClientSessionInfo sessionInfo = cache.get(getAddress().toString());
if (sessionInfo != null && sessionInfo.getActiveList() != null) { if (sessionInfo != null && sessionInfo.getActiveList() != null) {
return PrivacyListManager.getInstance().getPrivacyList(address.getNode(), sessionInfo.getActiveList()); return PrivacyListManager.getInstance().getPrivacyList(address.getNode(), sessionInfo.getActiveList());
} }
return null; return null;
} }
public void setActiveList(PrivacyList activeList) { public void setActiveList(PrivacyList activeList) {
// Highly unlikely that a list is change to a remote session but still possible // Highly unlikely that a list is change to a remote session but still possible
doClusterTask(new SetPrivacyListTask(address, true, activeList)); doClusterTask(new SetPrivacyListTask(address, true, activeList));
} }
public PrivacyList getDefaultList() { public PrivacyList getDefaultList() {
Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache(); Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
ClientSessionInfo sessionInfo = cache.get(getAddress().toString()); ClientSessionInfo sessionInfo = cache.get(getAddress().toString());
if (sessionInfo != null && sessionInfo.getDefaultList() != null) { if (sessionInfo != null && sessionInfo.getDefaultList() != null) {
return PrivacyListManager.getInstance().getPrivacyList(address.getNode(), sessionInfo.getDefaultList()); return PrivacyListManager.getInstance().getPrivacyList(address.getNode(), sessionInfo.getDefaultList());
} }
return null; return null;
} }
public void setDefaultList(PrivacyList defaultList) { public void setDefaultList(PrivacyList defaultList) {
// Highly unlikely that a list is change to a remote session but still possible // Highly unlikely that a list is change to a remote session but still possible
doClusterTask(new SetPrivacyListTask(address, false, defaultList)); doClusterTask(new SetPrivacyListTask(address, false, defaultList));
} }
public String getUsername() throws UserNotFoundException { public String getUsername() throws UserNotFoundException {
return address.getNode(); return address.getNode();
} }
public boolean isAnonymousUser() { public boolean isAnonymousUser() {
return SessionManager.getInstance().isAnonymousRoute(getAddress()); return SessionManager.getInstance().isAnonymousRoute(getAddress());
} }
public boolean isInitialized() { public boolean isInitialized() {
if (initialized == -1) { if (initialized == -1) {
Presence presence = getPresence(); Presence presence = getPresence();
if (presence != null && presence.isAvailable()) { if (presence != null && presence.isAvailable()) {
// Optimization to avoid making a remote call // Optimization to avoid making a remote call
initialized = 1; initialized = 1;
} }
else { else {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isInitialized); ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isInitialized);
Object result = doSynchronousClusterTask(task); Object result = doSynchronousClusterTask(task);
initialized = result != null && (Boolean) result ? 1 : 0; initialized = result != null && (Boolean) result ? 1 : 0;
} }
} }
return initialized == 1; return initialized == 1;
} }
public void setInitialized(boolean isInit) { public void setInitialized(boolean isInit) {
doClusterTask(new SetInitializedTask(address, isInit)); doClusterTask(new SetInitializedTask(address, isInit));
} }
public boolean canFloodOfflineMessages() { public boolean canFloodOfflineMessages() {
// Code copied from LocalClientSession to avoid remote calls // Code copied from LocalClientSession to avoid remote calls
if(isOfflineFloodStopped()) { if(isOfflineFloodStopped()) {
return false; return false;
} }
String username = getAddress().getNode(); String username = getAddress().getNode();
for (ClientSession session : SessionManager.getInstance().getSessions(username)) { for (ClientSession session : SessionManager.getInstance().getSessions(username)) {
if (session.isOfflineFloodStopped()) { if (session.isOfflineFloodStopped()) {
return false; return false;
} }
} }
return true; return true;
} }
public boolean isOfflineFloodStopped() { public boolean isOfflineFloodStopped() {
Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache(); Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
ClientSessionInfo sessionInfo = cache.get(getAddress().toString()); ClientSessionInfo sessionInfo = cache.get(getAddress().toString());
return sessionInfo != null && sessionInfo.isOfflineFloodStopped(); return sessionInfo != null && sessionInfo.isOfflineFloodStopped();
} }
public Presence getPresence() { public Presence getPresence() {
Cache<String,ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache(); Cache<String,ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
ClientSessionInfo sessionInfo = cache.get(getAddress().toString()); ClientSessionInfo sessionInfo = cache.get(getAddress().toString());
if (sessionInfo != null) { if (sessionInfo != null) {
return sessionInfo.getPresence(); return sessionInfo.getPresence();
} }
// this can happen if a cluster node becomes unreachable // this can happen if a cluster node becomes unreachable
return new Presence(Presence.Type.unavailable); return new Presence(Presence.Type.unavailable);
} }
public void setPresence(Presence presence) { public void setPresence(Presence presence) {
try { try {
doClusterTask(new SetPresenceTask(address, presence)); doClusterTask(new SetPresenceTask(address, presence));
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
// Remote node is down // Remote node is down
if (presence.getType() == Presence.Type.unavailable) { if (presence.getType() == Presence.Type.unavailable) {
// Ignore unavailable presence (since session is already unavailable - at least to us) // Ignore unavailable presence (since session is already unavailable - at least to us)
return; return;
} }
throw e; throw e;
} }
} }
public int incrementConflictCount() { public int incrementConflictCount() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.incrementConflictCount); ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.incrementConflictCount);
Object result = doSynchronousClusterTask(task); Object result = doSynchronousClusterTask(task);
return result == null ? 0 : (Integer) result; return result == null ? 0 : (Integer) result;
} }
@Override @Override
public boolean isMessageCarbonsEnabled() { public boolean isMessageCarbonsEnabled() {
return messageCarbonsEnabled; return messageCarbonsEnabled;
} }
@Override @Override
public void setMessageCarbonsEnabled(boolean enabled) { public void setMessageCarbonsEnabled(boolean enabled) {
this.messageCarbonsEnabled = enabled; this.messageCarbonsEnabled = enabled;
} }
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) { RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new ClientSessionTask(address, operation); return new ClientSessionTask(address, operation);
} }
ClusterTask getDeliverRawTextTask(String text) { ClusterTask getDeliverRawTextTask(String text) {
return new DeliverRawTextTask(this, address, text); return new DeliverRawTextTask(this, address, text);
} }
ClusterTask getProcessPacketTask(Packet packet) { ClusterTask getProcessPacketTask(Packet packet) {
return new ProcessPacketTask(this, address, packet); return new ProcessPacketTask(this, address, packet);
} }
private static class SetPresenceTask extends ClientSessionTask { private static class SetPresenceTask extends ClientSessionTask {
private Presence presence; private Presence presence;
public SetPresenceTask() { public SetPresenceTask() {
super(); super();
} }
protected SetPresenceTask(JID address, Presence presence) { protected SetPresenceTask(JID address, Presence presence) {
super(address, null); super(address, null);
this.presence = presence; this.presence = presence;
} }
public void run() { public void run() {
((ClientSession)getSession()).setPresence(presence); ((ClientSession)getSession()).setPresence(presence);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement()); ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in); Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
presence = new Presence(packetElement, true); presence = new Presence(packetElement, true);
} }
} }
private static class SetPrivacyListTask extends ClientSessionTask { private static class SetPrivacyListTask extends ClientSessionTask {
private boolean activeList; private boolean activeList;
private String listName; private String listName;
public SetPrivacyListTask() { public SetPrivacyListTask() {
super(); super();
} }
protected SetPrivacyListTask(JID address, boolean activeList, PrivacyList list) { protected SetPrivacyListTask(JID address, boolean activeList, PrivacyList list) {
super(address, null); super(address, null);
this.activeList = activeList; this.activeList = activeList;
this.listName = list != null ? list.getName() : null; this.listName = list != null ? list.getName() : null;
} }
public void run() { public void run() {
ClientSession session = ((ClientSession) getSession()); ClientSession session = ((ClientSession) getSession());
PrivacyList list = null; PrivacyList list = null;
// Get the privacy list to set // Get the privacy list to set
if (listName != null) { if (listName != null) {
try { try {
String username = session.getUsername(); String username = session.getUsername();
list = PrivacyListManager.getInstance().getPrivacyList(username, listName); list = PrivacyListManager.getInstance().getPrivacyList(username, listName);
} catch (UserNotFoundException e) { } catch (UserNotFoundException e) {
// Should never happen // Should never happen
} }
} }
// Set the privacy list to the session // Set the privacy list to the session
if (activeList) { if (activeList) {
session.setActiveList(list); session.setActiveList(list);
} }
else { else {
session.setDefaultList(list); session.setDefaultList(list);
} }
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeBoolean(out, activeList); ExternalizableUtil.getInstance().writeBoolean(out, activeList);
ExternalizableUtil.getInstance().writeBoolean(out, listName != null); ExternalizableUtil.getInstance().writeBoolean(out, listName != null);
if (listName != null) { if (listName != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, listName); ExternalizableUtil.getInstance().writeSafeUTF(out, listName);
} }
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
activeList = ExternalizableUtil.getInstance().readBoolean(in); activeList = ExternalizableUtil.getInstance().readBoolean(in);
if (ExternalizableUtil.getInstance().readBoolean(in)) { if (ExternalizableUtil.getInstance().readBoolean(in)) {
listName = ExternalizableUtil.getInstance().readSafeUTF(in); listName = ExternalizableUtil.getInstance().readSafeUTF(in);
} }
} }
} }
private static class SetInitializedTask extends ClientSessionTask { private static class SetInitializedTask extends ClientSessionTask {
private boolean initialized; private boolean initialized;
public SetInitializedTask() { public SetInitializedTask() {
super(); super();
} }
protected SetInitializedTask(JID address, boolean initialized) { protected SetInitializedTask(JID address, boolean initialized) {
super(address, null); super(address, null);
this.initialized = initialized; this.initialized = initialized;
} }
public void run() { public void run() {
((ClientSession) getSession()).setInitialized(initialized); ((ClientSession) getSession()).setInitialized(initialized);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeBoolean(out, initialized); ExternalizableUtil.getInstance().writeBoolean(out, initialized);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
initialized = ExternalizableUtil.getInstance().readBoolean(in); initialized = ExternalizableUtil.getInstance().readBoolean(in);
} }
} }
} }
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.tree.DefaultElement; import org.dom4j.tree.DefaultElement;
......
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.session.ConnectionMultiplexerSession; import org.jivesoftware.openfire.session.ConnectionMultiplexerSession;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
/** /**
* Surrogate for connection manager sessions hosted in some remote cluster node. * Surrogate for connection manager sessions hosted in some remote cluster node.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class RemoteConnectionMultiplexerSession extends RemoteSession implements ConnectionMultiplexerSession { public class RemoteConnectionMultiplexerSession extends RemoteSession implements ConnectionMultiplexerSession {
public RemoteConnectionMultiplexerSession(byte[] nodeID, JID address) { public RemoteConnectionMultiplexerSession(byte[] nodeID, JID address) {
super(nodeID, address); super(nodeID, address);
} }
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) { RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new ConnectionMultiplexerSessionTask(address, operation); return new ConnectionMultiplexerSessionTask(address, operation);
} }
ClusterTask getDeliverRawTextTask(String text) { ClusterTask getDeliverRawTextTask(String text) {
return new DeliverRawTextTask(this, address, text); return new DeliverRawTextTask(this, address, text);
} }
ClusterTask getProcessPacketTask(Packet packet) { ClusterTask getProcessPacketTask(Packet packet) {
return new ProcessPacketTask(this, address, packet); return new ProcessPacketTask(this, address, packet);
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.IncomingServerSession; import org.jivesoftware.openfire.session.IncomingServerSession;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import java.util.Collection; import java.util.Collection;
/** /**
* Surrogate for incoming server sessions hosted in some remote cluster node. * Surrogate for incoming server sessions hosted in some remote cluster node.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class RemoteIncomingServerSession extends RemoteSession implements IncomingServerSession { public class RemoteIncomingServerSession extends RemoteSession implements IncomingServerSession {
private String localDomain; private String localDomain;
private long usingServerDialback = -1; private long usingServerDialback = -1;
public RemoteIncomingServerSession(byte[] nodeID, String streamID) { public RemoteIncomingServerSession(byte[] nodeID, String streamID) {
super(nodeID, null); super(nodeID, null);
this.streamID = new BasicStreamID(streamID); this.streamID = new BasicStreamID(streamID);
} }
public boolean isUsingServerDialback() { public boolean isUsingServerDialback() {
if (usingServerDialback == -1) { if (usingServerDialback == -1) {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isUsingServerDialback); ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isUsingServerDialback);
usingServerDialback = (Boolean) doSynchronousClusterTask(task) ? 1 : 0; usingServerDialback = (Boolean) doSynchronousClusterTask(task) ? 1 : 0;
} }
return usingServerDialback == 1; return usingServerDialback == 1;
} }
public JID getAddress() { public JID getAddress() {
if (address == null) { if (address == null) {
RemoteSessionTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getAddress); RemoteSessionTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getAddress);
address = (JID) doSynchronousClusterTask(task); address = (JID) doSynchronousClusterTask(task);
} }
return address; return address;
} }
public Collection<String> getValidatedDomains() { public Collection<String> getValidatedDomains() {
// Content is stored in a clustered cache so that even in the case of the node hosting // Content is stored in a clustered cache so that even in the case of the node hosting
// the sessions is lost we can still have access to this info to be able to perform // the sessions is lost we can still have access to this info to be able to perform
// proper clean up logic {@link ClusterListener#cleanupNode(NodeCacheKey) // proper clean up logic {@link ClusterListener#cleanupNode(NodeCacheKey)
return SessionManager.getInstance().getValidatedDomains(streamID.getID()); return SessionManager.getInstance().getValidatedDomains(streamID.getID());
} }
public String getLocalDomain() { public String getLocalDomain() {
if (localDomain == null) { if (localDomain == null) {
RemoteSessionTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getLocalDomain); RemoteSessionTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getLocalDomain);
localDomain = (String) doSynchronousClusterTask(task); localDomain = (String) doSynchronousClusterTask(task);
} }
return localDomain; return localDomain;
} }
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) { RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new IncomingServerSessionTask(operation, streamID.getID()); return new IncomingServerSessionTask(operation, streamID.getID());
} }
ClusterTask getDeliverRawTextTask(String text) { ClusterTask getDeliverRawTextTask(String text) {
return new DeliverRawTextTask(streamID.getID(), text); return new DeliverRawTextTask(streamID.getID(), text);
} }
ClusterTask getProcessPacketTask(Packet packet) { ClusterTask getProcessPacketTask(Packet packet) {
return new ProcessPacketTask(streamID.getID(), packet); return new ProcessPacketTask(streamID.getID(), packet);
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.session.OutgoingServerSession; import org.jivesoftware.openfire.session.OutgoingServerSession;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.util.Collection; import java.util.Collection;
/** /**
* Surrogate for outgoing server sessions hosted in some remote cluster node. * Surrogate for outgoing server sessions hosted in some remote cluster node.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class RemoteOutgoingServerSession extends RemoteSession implements OutgoingServerSession { public class RemoteOutgoingServerSession extends RemoteSession implements OutgoingServerSession {
private long usingServerDialback = -1; private long usingServerDialback = -1;
public RemoteOutgoingServerSession(byte[] nodeID, JID address) { public RemoteOutgoingServerSession(byte[] nodeID, JID address) {
super(nodeID, address); super(nodeID, address);
} }
public Collection<String> getAuthenticatedDomains() { public Collection<String> getAuthenticatedDomains() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getAuthenticatedDomains); ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getAuthenticatedDomains);
return (Collection<String>) doSynchronousClusterTask(task); return (Collection<String>) doSynchronousClusterTask(task);
} }
public void addAuthenticatedDomain(String domain) { public void addAuthenticatedDomain(String domain) {
doClusterTask(new AddAuthenticatedDomainTask(address, domain)); doClusterTask(new AddAuthenticatedDomainTask(address, domain));
} }
public Collection<String> getHostnames() { public Collection<String> getHostnames() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getHostnames); ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getHostnames);
return (Collection<String>) doSynchronousClusterTask(task); return (Collection<String>) doSynchronousClusterTask(task);
} }
public void addHostname(String hostname) { public void addHostname(String hostname) {
doClusterTask(new AddHostnameTask(address, hostname)); doClusterTask(new AddHostnameTask(address, hostname));
} }
public boolean authenticateSubdomain(String domain, String hostname) { public boolean authenticateSubdomain(String domain, String hostname) {
ClusterTask task = new AuthenticateSubdomainTask(address, domain, hostname); ClusterTask task = new AuthenticateSubdomainTask(address, domain, hostname);
return (Boolean) doSynchronousClusterTask(task); return (Boolean) doSynchronousClusterTask(task);
} }
public boolean isUsingServerDialback() { public boolean isUsingServerDialback() {
if (usingServerDialback == -1) { if (usingServerDialback == -1) {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isUsingServerDialback); ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isUsingServerDialback);
usingServerDialback = (Boolean) doSynchronousClusterTask(task) ? 1 : 0; usingServerDialback = (Boolean) doSynchronousClusterTask(task) ? 1 : 0;
} }
return usingServerDialback == 1; return usingServerDialback == 1;
} }
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) { RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new OutgoingServerSessionTask(address, operation); return new OutgoingServerSessionTask(address, operation);
} }
ClusterTask getDeliverRawTextTask(String text) { ClusterTask getDeliverRawTextTask(String text) {
return new DeliverRawTextTask(this, address, text); return new DeliverRawTextTask(this, address, text);
} }
ClusterTask getProcessPacketTask(Packet packet) { ClusterTask getProcessPacketTask(Packet packet) {
return new ProcessPacketTask(this, address, packet); return new ProcessPacketTask(this, address, packet);
} }
private static class AddAuthenticatedDomainTask extends OutgoingServerSessionTask { private static class AddAuthenticatedDomainTask extends OutgoingServerSessionTask {
private String domain; private String domain;
public AddAuthenticatedDomainTask() { public AddAuthenticatedDomainTask() {
super(); super();
} }
protected AddAuthenticatedDomainTask(JID address, String domain) { protected AddAuthenticatedDomainTask(JID address, String domain) {
super(address, null); super(address, null);
this.domain = domain; this.domain = domain;
} }
public void run() { public void run() {
((OutgoingServerSession) getSession()).addAuthenticatedDomain(domain); ((OutgoingServerSession) getSession()).addAuthenticatedDomain(domain);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF(out, domain); ExternalizableUtil.getInstance().writeSafeUTF(out, domain);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
domain = ExternalizableUtil.getInstance().readSafeUTF(in); domain = ExternalizableUtil.getInstance().readSafeUTF(in);
} }
} }
private static class AddHostnameTask extends OutgoingServerSessionTask { private static class AddHostnameTask extends OutgoingServerSessionTask {
private String hostname; private String hostname;
public AddHostnameTask() { public AddHostnameTask() {
super(); super();
} }
protected AddHostnameTask(JID address, String hostname) { protected AddHostnameTask(JID address, String hostname) {
super(address, null); super(address, null);
this.hostname = hostname; this.hostname = hostname;
} }
public void run() { public void run() {
((OutgoingServerSession) getSession()).addHostname(hostname); ((OutgoingServerSession) getSession()).addHostname(hostname);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF(out, hostname); ExternalizableUtil.getInstance().writeSafeUTF(out, hostname);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
hostname = ExternalizableUtil.getInstance().readSafeUTF(in); hostname = ExternalizableUtil.getInstance().readSafeUTF(in);
} }
} }
private static class AuthenticateSubdomainTask extends OutgoingServerSessionTask { private static class AuthenticateSubdomainTask extends OutgoingServerSessionTask {
private String domain; private String domain;
private String hostname; private String hostname;
public AuthenticateSubdomainTask() { public AuthenticateSubdomainTask() {
super(); super();
} }
protected AuthenticateSubdomainTask(JID address, String domain, String hostname) { protected AuthenticateSubdomainTask(JID address, String domain, String hostname) {
super(address, null); super(address, null);
this.domain = domain; this.domain = domain;
this.hostname = hostname; this.hostname = hostname;
} }
public void run() { public void run() {
result = ((OutgoingServerSession) getSession()).authenticateSubdomain(domain, hostname); result = ((OutgoingServerSession) getSession()).authenticateSubdomain(domain, hostname);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out); super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF(out, domain); ExternalizableUtil.getInstance().writeSafeUTF(out, domain);
ExternalizableUtil.getInstance().writeSafeUTF(out, hostname); ExternalizableUtil.getInstance().writeSafeUTF(out, hostname);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in); super.readExternal(in);
domain = ExternalizableUtil.getInstance().readSafeUTF(in); domain = ExternalizableUtil.getInstance().readSafeUTF(in);
hostname = ExternalizableUtil.getInstance().readSafeUTF(in); hostname = ExternalizableUtil.getInstance().readSafeUTF(in);
} }
} }
} }
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Date; import java.util.Date;
......
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.session.*; import org.jivesoftware.openfire.session.*;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
/** /**
* Locator of sessions that know how to talk to Hazelcast cluster nodes. * Locator of sessions that know how to talk to Hazelcast cluster nodes.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class RemoteSessionLocator implements org.jivesoftware.openfire.session.RemoteSessionLocator { public class RemoteSessionLocator implements org.jivesoftware.openfire.session.RemoteSessionLocator {
// TODO Keep a cache for a brief moment so we can reuse same instances (that use their own cache) // TODO Keep a cache for a brief moment so we can reuse same instances (that use their own cache)
public ClientSession getClientSession(byte[] nodeID, JID address) { public ClientSession getClientSession(byte[] nodeID, JID address) {
return new RemoteClientSession(nodeID, address); return new RemoteClientSession(nodeID, address);
} }
public ComponentSession getComponentSession(byte[] nodeID, JID address) { public ComponentSession getComponentSession(byte[] nodeID, JID address) {
return new RemoteComponentSession(nodeID, address); return new RemoteComponentSession(nodeID, address);
} }
public ConnectionMultiplexerSession getConnectionMultiplexerSession(byte[] nodeID, JID address) { public ConnectionMultiplexerSession getConnectionMultiplexerSession(byte[] nodeID, JID address) {
return new RemoteConnectionMultiplexerSession(nodeID, address); return new RemoteConnectionMultiplexerSession(nodeID, address);
} }
public IncomingServerSession getIncomingServerSession(byte[] nodeID, String streamID) { public IncomingServerSession getIncomingServerSession(byte[] nodeID, String streamID) {
return new RemoteIncomingServerSession(nodeID, streamID); return new RemoteIncomingServerSession(nodeID, streamID);
} }
public OutgoingServerSession getOutgoingServerSession(byte[] nodeID, JID address) { public OutgoingServerSession getOutgoingServerSession(byte[] nodeID, JID address) {
return new RemoteOutgoingServerSession(nodeID, address); return new RemoteOutgoingServerSession(nodeID, address);
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.openfire.session; package org.jivesoftware.openfire.plugin.session;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.TaskEngine; import org.jivesoftware.util.TaskEngine;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* Operations to be executed in a remote session hosted in a remote cluster node. * Operations to be executed in a remote session hosted in a remote cluster node.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public abstract class RemoteSessionTask implements ClusterTask { public abstract class RemoteSessionTask implements ClusterTask {
protected Object result; protected Object result;
protected Operation operation; protected Operation operation;
public RemoteSessionTask() { public RemoteSessionTask() {
} }
protected RemoteSessionTask(Operation operation) { protected RemoteSessionTask(Operation operation) {
this.operation = operation; this.operation = operation;
} }
abstract Session getSession(); abstract Session getSession();
public Object getResult() { public Object getResult() {
return result; return result;
} }
public void run() { public void run() {
if (operation == Operation.getStreamID) { if (operation == Operation.getStreamID) {
result = getSession().getStreamID().getID(); result = getSession().getStreamID().getID();
} }
else if (operation == Operation.getServerName) { else if (operation == Operation.getServerName) {
result = getSession().getServerName(); result = getSession().getServerName();
} }
else if (operation == Operation.getCreationDate) { else if (operation == Operation.getCreationDate) {
result = getSession().getCreationDate(); result = getSession().getCreationDate();
} }
else if (operation == Operation.getLastActiveDate) { else if (operation == Operation.getLastActiveDate) {
result = getSession().getLastActiveDate(); result = getSession().getLastActiveDate();
} }
else if (operation == Operation.getNumClientPackets) { else if (operation == Operation.getNumClientPackets) {
result = getSession().getNumClientPackets(); result = getSession().getNumClientPackets();
} }
else if (operation == Operation.getNumServerPackets) { else if (operation == Operation.getNumServerPackets) {
result = getSession().getNumServerPackets(); result = getSession().getNumServerPackets();
} }
else if (operation == Operation.getCipherSuiteName) { else if (operation == Operation.getCipherSuiteName) {
result = getSession().getCipherSuiteName(); result = getSession().getCipherSuiteName();
} }
else if (operation == Operation.close) { else if (operation == Operation.close) {
// Run in another thread so we avoid blocking calls (in hazelcast) // Run in another thread so we avoid blocking calls (in hazelcast)
final Session session = getSession(); final Session session = getSession();
if (session != null) { if (session != null) {
final Future<?> future = TaskEngine.getInstance().submit(new Runnable() { final Future<?> future = TaskEngine.getInstance().submit(new Runnable() {
public void run() { public void run() {
session.close(); session.close();
} }
}); });
// Wait until the close operation is done or timeout is met // Wait until the close operation is done or timeout is met
try { try {
future.get(15, TimeUnit.SECONDS); future.get(15, TimeUnit.SECONDS);
} }
catch (Exception e) { catch (Exception e) {
// Ignore // Ignore
} }
} }
} }
else if (operation == Operation.isClosed) { else if (operation == Operation.isClosed) {
result = getSession().isClosed(); result = getSession().isClosed();
} }
else if (operation == Operation.isSecure) { else if (operation == Operation.isSecure) {
result = getSession().isSecure(); result = getSession().isSecure();
} }
else if (operation == Operation.getHostAddress) { else if (operation == Operation.getHostAddress) {
try { try {
result = getSession().getHostAddress(); result = getSession().getHostAddress();
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
Log.error("Error getting address of session: " + getSession(), e); Log.error("Error getting address of session: " + getSession(), e);
} }
} }
else if (operation == Operation.getHostName) { else if (operation == Operation.getHostName) {
try { try {
result = getSession().getHostName(); result = getSession().getHostName();
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
Log.error("Error getting address of session: " + getSession(), e); Log.error("Error getting address of session: " + getSession(), e);
} }
} }
else if (operation == Operation.validate) { else if (operation == Operation.validate) {
result = getSession().validate(); result = getSession().validate();
} }
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeBoolean(out, operation != null); ExternalizableUtil.getInstance().writeBoolean(out, operation != null);
if (operation != null) { if (operation != null) {
ExternalizableUtil.getInstance().writeInt(out, operation.ordinal()); ExternalizableUtil.getInstance().writeInt(out, operation.ordinal());
} }
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
if (ExternalizableUtil.getInstance().readBoolean(in)) { if (ExternalizableUtil.getInstance().readBoolean(in)) {
operation = Operation.values()[ExternalizableUtil.getInstance().readInt(in)]; operation = Operation.values()[ExternalizableUtil.getInstance().readInt(in)];
} }
} }
public enum Operation { public enum Operation {
/** /**
* Basic session operations * Basic session operations
*/ */
getStreamID, getStreamID,
getServerName, getServerName,
getCreationDate, getCreationDate,
getLastActiveDate, getLastActiveDate,
getNumClientPackets, getNumClientPackets,
getNumServerPackets, getNumServerPackets,
getCipherSuiteName, getCipherSuiteName,
close, close,
isClosed, isClosed,
isSecure, isSecure,
getHostAddress, getHostAddress,
getHostName, getHostName,
validate, validate,
/** /**
* Operations of c2s sessions * Operations of c2s sessions
*/ */
isInitialized, isInitialized,
incrementConflictCount, incrementConflictCount,
/** /**
* Operations of outgoing server sessions * Operations of outgoing server sessions
*/ */
getAuthenticatedDomains, getAuthenticatedDomains,
getHostnames, getHostnames,
isUsingServerDialback, isUsingServerDialback,
/** /**
* Operations of external component sessions * Operations of external component sessions
*/ */
getType, getType,
getCategory, getCategory,
getInitialSubdomain, getInitialSubdomain,
getSubdomains, getSubdomains,
getName, getName,
getDescription, getDescription,
start, start,
shutdown, shutdown,
/** /**
* Operations of incoming server sessions * Operations of incoming server sessions
*/ */
getLocalDomain, getLocalDomain,
getAddress getAddress
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cache; package org.jivesoftware.openfire.plugin.util.cache;
import java.util.Set; import java.util.Set;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.NodeID; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.util.StringUtils;
import com.hazelcast.core.EntryEvent; import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.EntryListener; import com.hazelcast.core.EntryListener;
import com.hazelcast.core.MapEvent; import com.hazelcast.core.MapEvent;
/** /**
* Base listener for cache events in the cluster. This class helps keep track * Base listener for cache events in the cluster. This class helps keep track
* of nodes and their elements. The actual tracking information is kept in * of nodes and their elements. The actual tracking information is kept in
* {@link ClusterListener}. This information is then used when a node goes * {@link ClusterListener}. This information is then used when a node goes
* down to proper clean up can be done. * down to proper clean up can be done.
* *
* @author Tom Evans * @author Tom Evans
* @author Pete Matern * @author Pete Matern
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
class CacheListener implements EntryListener { class CacheListener implements EntryListener {
protected final String cacheName; protected final String cacheName;
private ClusterListener clusterListener; private ClusterListener clusterListener;
public CacheListener(ClusterListener clusterListener, String cacheName) { public CacheListener(ClusterListener clusterListener, String cacheName) {
this.clusterListener = clusterListener; this.clusterListener = clusterListener;
this.cacheName = cacheName; this.cacheName = cacheName;
} }
public void entryAdded(EntryEvent event) { public void entryAdded(EntryEvent event) {
handleEntryEvent(event, false); handleEntryEvent(event, false);
} }
public void entryUpdated(EntryEvent event) { public void entryUpdated(EntryEvent event) {
handleEntryEvent(event, false); handleEntryEvent(event, false);
} }
public void entryRemoved(EntryEvent event) { public void entryRemoved(EntryEvent event) {
handleEntryEvent(event, true); handleEntryEvent(event, true);
} }
public void entryEvicted(EntryEvent event) { public void entryEvicted(EntryEvent event) {
handleEntryEvent(event, true); handleEntryEvent(event, true);
} }
private void handleEntryEvent(EntryEvent event, boolean removal) { private void handleEntryEvent(EntryEvent event, boolean removal) {
NodeID nodeID = NodeID.getInstance(StringUtils.getBytes(event.getMember().getUuid())); NodeID nodeID = NodeID.getInstance(StringUtils.getBytes(event.getMember().getUuid()));
// ignore events which were triggered by this node // ignore events which were triggered by this node
if (!XMPPServer.getInstance().getNodeID().equals(nodeID)) { if (!XMPPServer.getInstance().getNodeID().equals(nodeID)) {
Set<String> sessionJIDS = clusterListener.lookupJIDList(nodeID, cacheName); Set<String> sessionJIDS = clusterListener.lookupJIDList(nodeID, cacheName);
if (removal) { if (removal) {
sessionJIDS.remove(event.getKey().toString()); sessionJIDS.remove(event.getKey().toString());
} }
else { else {
sessionJIDS.add(event.getKey().toString()); sessionJIDS.add(event.getKey().toString());
} }
} }
} }
private void handleMapEvent(MapEvent event) { private void handleMapEvent(MapEvent event) {
NodeID nodeID = NodeID.getInstance(StringUtils.getBytes(event.getMember().getUuid())); NodeID nodeID = NodeID.getInstance(StringUtils.getBytes(event.getMember().getUuid()));
// ignore events which were triggered by this node // ignore events which were triggered by this node
if (!XMPPServer.getInstance().getNodeID().equals(nodeID)) { if (!XMPPServer.getInstance().getNodeID().equals(nodeID)) {
Set<String> sessionJIDs = clusterListener.lookupJIDList(nodeID, cacheName); Set<String> sessionJIDs = clusterListener.lookupJIDList(nodeID, cacheName);
sessionJIDs.clear(); sessionJIDs.clear();
} }
} }
@Override @Override
public void mapCleared(MapEvent event) { public void mapCleared(MapEvent event) {
handleMapEvent(event); handleMapEvent(event);
} }
@Override @Override
public void mapEvicted(MapEvent event) { public void mapEvicted(MapEvent event) {
handleMapEvent(event); handleMapEvent(event);
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cache; package org.jivesoftware.openfire.plugin.util.cache;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Enumeration; import java.util.Enumeration;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin; import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginClassLoader; import org.jivesoftware.openfire.container.PluginClassLoader;
import org.jivesoftware.openfire.container.PluginManager; import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Class loader to be used by Openfire to load classes that live in the Hazelcast plugin, * Class loader to be used by Openfire to load classes that live in the Hazelcast plugin,
* the Openfire core and also classes defined in other plugins. With this new class loader * the Openfire core and also classes defined in other plugins. With this new class loader
* plugins can now make use of hazelcast.<p> * plugins can now make use of hazelcast.<p>
* *
* However, there is a catch with this class loader. Plugins that define the same class name * However, there is a catch with this class loader. Plugins that define the same class name
* (i.e. package and class name) will have a problem if they try to send that class through * (i.e. package and class name) will have a problem if they try to send that class through
* the cluster. Hazelcast will deserialize the class and will use the first class definition * the cluster. Hazelcast will deserialize the class and will use the first class definition
* found in the list of plugins.<p> * found in the list of plugins.<p>
* *
* The sequence of search for this class loader is first check the hazelcast plugin that * The sequence of search for this class loader is first check the hazelcast plugin that
* includes checking the Openfire core. If not found then try with the other plugins. * includes checking the Openfire core. If not found then try with the other plugins.
* *
* @author Tom Evans * @author Tom Evans
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class ClusterClassLoader extends ClassLoader { public class ClusterClassLoader extends ClassLoader {
private static Logger logger = LoggerFactory.getLogger(ClusterClassLoader.class); private static Logger logger = LoggerFactory.getLogger(ClusterClassLoader.class);
private static final String HAZELCAST_CONFIG_DIR = JiveGlobals.getProperty( private static final String HAZELCAST_CONFIG_DIR = JiveGlobals.getProperty(
"hazelcast.config.xml.directory", JiveGlobals.getHomeDirectory() "hazelcast.config.xml.directory", JiveGlobals.getHomeDirectory()
+ "/conf"); + "/conf");
private PluginClassLoader hazelcastClassloader; private PluginClassLoader hazelcastClassloader;
public ClusterClassLoader() { public ClusterClassLoader() {
Plugin plugin = XMPPServer.getInstance().getPluginManager().getPlugin("hazelcast"); Plugin plugin = XMPPServer.getInstance().getPluginManager().getPlugin("hazelcast");
hazelcastClassloader = XMPPServer.getInstance().getPluginManager().getPluginClassloader(plugin); hazelcastClassloader = XMPPServer.getInstance().getPluginManager().getPluginClassloader(plugin);
// this is meant to allow loading configuration files from outside the plugin JAR file // this is meant to allow loading configuration files from outside the plugin JAR file
File confFolder = new File(HAZELCAST_CONFIG_DIR); File confFolder = new File(HAZELCAST_CONFIG_DIR);
try { try {
logger.debug("Adding conf folder {}", confFolder); logger.debug("Adding conf folder {}", confFolder);
hazelcastClassloader.addURLFile(confFolder.toURI().toURL()); hazelcastClassloader.addURLFile(confFolder.toURI().toURL());
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
logger.error("Error adding folder {} to classpath {}", HAZELCAST_CONFIG_DIR, e.getMessage()); logger.error("Error adding folder {} to classpath {}", HAZELCAST_CONFIG_DIR, e.getMessage());
} }
} }
public Class<?> loadClass(String name) throws ClassNotFoundException { public Class<?> loadClass(String name) throws ClassNotFoundException {
try { try {
return hazelcastClassloader.loadClass(name); return hazelcastClassloader.loadClass(name);
} }
catch (ClassNotFoundException e) { catch (ClassNotFoundException e) {
PluginManager pluginManager = XMPPServer.getInstance().getPluginManager(); PluginManager pluginManager = XMPPServer.getInstance().getPluginManager();
for (Plugin plugin : pluginManager.getPlugins()) { for (Plugin plugin : pluginManager.getPlugins()) {
String pluginName = pluginManager.getPluginDirectory(plugin).getName(); String pluginName = pluginManager.getPluginDirectory(plugin).getName();
if ("hazelcast".equals(pluginName) || "admin".equals(pluginName)) { if ("hazelcast".equals(pluginName) || "admin".equals(pluginName)) {
continue; continue;
} }
PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin); PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin);
try { try {
return pluginClassloader.loadClass(name); return pluginClassloader.loadClass(name);
} }
catch (ClassNotFoundException e1) { catch (ClassNotFoundException e1) {
// Do nothing. Continue to the next plugin // Do nothing. Continue to the next plugin
} }
} }
} }
throw new ClassNotFoundException(name); throw new ClassNotFoundException(name);
} }
public URL getResource(String name) { public URL getResource(String name) {
URL resource = hazelcastClassloader.getResource(name); URL resource = hazelcastClassloader.getResource(name);
if (resource == null) { if (resource == null) {
PluginManager pluginManager = XMPPServer.getInstance().getPluginManager(); PluginManager pluginManager = XMPPServer.getInstance().getPluginManager();
for (Plugin plugin : pluginManager.getPlugins()) { for (Plugin plugin : pluginManager.getPlugins()) {
String pluginName = pluginManager.getPluginDirectory(plugin).getName(); String pluginName = pluginManager.getPluginDirectory(plugin).getName();
if ("hazelcast".equals(pluginName) || "admin".equals(pluginName)) { if ("hazelcast".equals(pluginName) || "admin".equals(pluginName)) {
continue; continue;
} }
PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin); PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin);
resource = pluginClassloader.getResource(name); resource = pluginClassloader.getResource(name);
if (resource != null) { if (resource != null) {
return resource; return resource;
} }
} }
} }
return resource; return resource;
} }
public Enumeration<URL> getResources(String name) throws IOException { public Enumeration<URL> getResources(String name) throws IOException {
Enumeration<URL> answer = null; Enumeration<URL> answer = null;
try { try {
answer = hazelcastClassloader.getResources(name); answer = hazelcastClassloader.getResources(name);
} }
catch (IOException e) { catch (IOException e) {
// Ignore // Ignore
} }
if (answer == null || !answer.hasMoreElements()) { if (answer == null || !answer.hasMoreElements()) {
PluginManager pluginManager = XMPPServer.getInstance().getPluginManager(); PluginManager pluginManager = XMPPServer.getInstance().getPluginManager();
for (Plugin plugin : pluginManager.getPlugins()) { for (Plugin plugin : pluginManager.getPlugins()) {
String pluginName = pluginManager.getPluginDirectory(plugin).getName(); String pluginName = pluginManager.getPluginDirectory(plugin).getName();
if ("hazelcast".equals(pluginName) || "admin".equals(pluginName)) { if ("hazelcast".equals(pluginName) || "admin".equals(pluginName)) {
continue; continue;
} }
PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin); PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin);
try { try {
answer = pluginClassloader.getResources(name); answer = pluginClassloader.getResources(name);
} }
catch (IOException e) { catch (IOException e) {
// Ignore // Ignore
} }
if (answer != null && answer.hasMoreElements()) { if (answer != null && answer.hasMoreElements()) {
return answer; return answer;
} }
} }
} }
return answer; return answer;
} }
} }
/** /**
* $RCSfile$ * $RCSfile$
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2004-2009 Jive Software. All rights reserved. * Copyright (C) 2004-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cache; package org.jivesoftware.openfire.plugin.util.cache;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.Externalizable; import java.io.Externalizable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass; import java.io.ObjectStreamClass;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jivesoftware.util.cache.ExternalizableUtilStrategy; import org.jivesoftware.util.cache.ExternalizableUtilStrategy;
import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.HazelcastInstance;
/** /**
* Serialization strategy that uses Hazelcast as its underlying mechanism. * Serialization strategy that uses Hazelcast as its underlying mechanism.
* *
* @author Tom Evans * @author Tom Evans
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class ClusterExternalizableUtil implements ExternalizableUtilStrategy { public class ClusterExternalizableUtil implements ExternalizableUtilStrategy {
/** /**
* Writes a Map of String key and value pairs. This method handles the * Writes a Map of String key and value pairs. This method handles the
* case when the Map is <tt>null</tt>. * case when the Map is <tt>null</tt>.
* *
* @param out the output stream. * @param out the output stream.
* @param stringMap the Map of String key/value pairs. * @param stringMap the Map of String key/value pairs.
* @throws java.io.IOException if an error occurs. * @throws java.io.IOException if an error occurs.
*/ */
public void writeStringMap(DataOutput out, Map<String, String> stringMap) throws IOException { public void writeStringMap(DataOutput out, Map<String, String> stringMap) throws IOException {
writeObject(out, stringMap); writeObject(out, stringMap);
} }
/** /**
* Reads a Map of String key and value pairs. This method will return * Reads a Map of String key and value pairs. This method will return
* <tt>null</tt> if the Map written to the stream was <tt>null</tt>. * <tt>null</tt> if the Map written to the stream was <tt>null</tt>.
* *
* @param in the input stream. * @param in the input stream.
* @return a Map of String key/value pairs. * @return a Map of String key/value pairs.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public Map<String, String> readStringMap(DataInput in) throws IOException { public Map<String, String> readStringMap(DataInput in) throws IOException {
return (Map<String, String>) readObject(in); return (Map<String, String>) readObject(in);
} }
/** /**
* Writes a Map of String key and Set of Strings value pairs. This method DOES NOT handle the * Writes a Map of String key and Set of Strings value pairs. This method DOES NOT handle the
* case when the Map is <tt>null</tt>. * case when the Map is <tt>null</tt>.
* *
* @param out the output stream. * @param out the output stream.
* @param map the Map of String key and Set of Strings value pairs. * @param map the Map of String key and Set of Strings value pairs.
* @throws java.io.IOException if an error occurs. * @throws java.io.IOException if an error occurs.
*/ */
public void writeStringsMap(DataOutput out, Map<String, Set<String>> map) throws IOException { public void writeStringsMap(DataOutput out, Map<String, Set<String>> map) throws IOException {
writeObject(out, map); writeObject(out, map);
} }
/** /**
* Reads a Map of String key and Set of Strings value pairs. * Reads a Map of String key and Set of Strings value pairs.
* *
* @param in the input stream. * @param in the input stream.
* @param map a Map of String key and Set of Strings value pairs. * @param map a Map of String key and Set of Strings value pairs.
* @return number of elements added to the collection. * @return number of elements added to the collection.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public int readStringsMap(DataInput in, Map<String, Set<String>> map) throws IOException { public int readStringsMap(DataInput in, Map<String, Set<String>> map) throws IOException {
Map<String, Set<String>> result = (Map<String, Set<String>>) readObject(in); Map<String, Set<String>> result = (Map<String, Set<String>>) readObject(in);
if (result == null) return 0; if (result == null) return 0;
map.putAll(result); map.putAll(result);
return result.size(); return result.size();
} }
/** /**
* Writes a Map of Long key and Integer value pairs. This method handles * Writes a Map of Long key and Integer value pairs. This method handles
* the case when the Map is <tt>null</tt>. * the case when the Map is <tt>null</tt>.
* *
* @param out the output stream. * @param out the output stream.
* @param map the Map of Long key/Integer value pairs. * @param map the Map of Long key/Integer value pairs.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public void writeLongIntMap(DataOutput out, Map<Long, Integer> map) throws IOException { public void writeLongIntMap(DataOutput out, Map<Long, Integer> map) throws IOException {
writeObject(out, map); writeObject(out, map);
} }
/** /**
* Reads a Map of Long key and Integer value pairs. This method will return * Reads a Map of Long key and Integer value pairs. This method will return
* <tt>null</tt> if the Map written to the stream was <tt>null</tt>. * <tt>null</tt> if the Map written to the stream was <tt>null</tt>.
* *
* @param in the input stream. * @param in the input stream.
* @return a Map of Long key/Integer value pairs. * @return a Map of Long key/Integer value pairs.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public Map<Long, Integer> readLongIntMap(DataInput in) throws IOException { public Map<Long, Integer> readLongIntMap(DataInput in) throws IOException {
return (Map<Long, Integer>) readObject(in); return (Map<Long, Integer>) readObject(in);
} }
/** /**
* Writes a List of Strings. This method handles the case when the List is * Writes a List of Strings. This method handles the case when the List is
* <tt>null</tt>. * <tt>null</tt>.
* *
* @param out the output stream. * @param out the output stream.
* @param stringList the List of Strings. * @param stringList the List of Strings.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public void writeStringList(DataOutput out, List<String> stringList) throws IOException { public void writeStringList(DataOutput out, List<String> stringList) throws IOException {
writeObject(out, stringList); writeObject(out, stringList);
} }
/** /**
* Reads a List of Strings. This method will return <tt>null</tt> if the List * Reads a List of Strings. This method will return <tt>null</tt> if the List
* written to the stream was <tt>null</tt>. * written to the stream was <tt>null</tt>.
* *
* @param in the input stream. * @param in the input stream.
* @return a List of Strings. * @return a List of Strings.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public List<String> readStringList(DataInput in) throws IOException { public List<String> readStringList(DataInput in) throws IOException {
return (List<String>) readObject(in); return (List<String>) readObject(in);
} }
/** /**
* Writes an array of long values. This method handles the case when the * Writes an array of long values. This method handles the case when the
* array is <tt>null</tt>. * array is <tt>null</tt>.
* *
* @param out the output stream. * @param out the output stream.
* @param array the array of long values. * @param array the array of long values.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public void writeLongArray(DataOutput out, long [] array) throws IOException { public void writeLongArray(DataOutput out, long [] array) throws IOException {
writeObject(out, array); writeObject(out, array);
} }
/** /**
* Reads an array of long values. This method will return <tt>null</tt> if * Reads an array of long values. This method will return <tt>null</tt> if
* the array written to the stream was <tt>null</tt>. * the array written to the stream was <tt>null</tt>.
* *
* @param in the input stream. * @param in the input stream.
* @return an array of long values. * @return an array of long values.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public long [] readLongArray(DataInput in) throws IOException { public long [] readLongArray(DataInput in) throws IOException {
return (long []) readObject(in); return (long []) readObject(in);
} }
public void writeLong(DataOutput out, long value) throws IOException { public void writeLong(DataOutput out, long value) throws IOException {
writeObject(out, value); writeObject(out, value);
} }
public long readLong(DataInput in) throws IOException { public long readLong(DataInput in) throws IOException {
return (Long) readObject(in); return (Long) readObject(in);
} }
public void writeByteArray(DataOutput out, byte[] value) throws IOException { public void writeByteArray(DataOutput out, byte[] value) throws IOException {
writeObject(out, value); writeObject(out, value);
} }
public byte[] readByteArray(DataInput in) throws IOException { public byte[] readByteArray(DataInput in) throws IOException {
return (byte []) readObject(in); return (byte []) readObject(in);
} }
public void writeInt(DataOutput out, int value) throws IOException { public void writeInt(DataOutput out, int value) throws IOException {
writeObject(out, value); writeObject(out, value);
} }
public int readInt(DataInput in) throws IOException { public int readInt(DataInput in) throws IOException {
return (Integer) readObject(in); return (Integer) readObject(in);
} }
public void writeBoolean(DataOutput out, boolean value) throws IOException { public void writeBoolean(DataOutput out, boolean value) throws IOException {
writeObject(out, value); writeObject(out, value);
} }
public boolean readBoolean(DataInput in) throws IOException { public boolean readBoolean(DataInput in) throws IOException {
return (Boolean) readObject(in); return (Boolean) readObject(in);
} }
public void writeSerializable(DataOutput out, Serializable value) throws IOException { public void writeSerializable(DataOutput out, Serializable value) throws IOException {
writeObject(out, value); writeObject(out, value);
} }
public Serializable readSerializable(DataInput in) throws IOException { public Serializable readSerializable(DataInput in) throws IOException {
return (Serializable) readObject(in); return (Serializable) readObject(in);
} }
public void writeSafeUTF(DataOutput out, String value) throws IOException { public void writeSafeUTF(DataOutput out, String value) throws IOException {
writeObject(out, value); writeObject(out, value);
} }
public String readSafeUTF(DataInput in) throws IOException { public String readSafeUTF(DataInput in) throws IOException {
return (String) readObject(in); return (String) readObject(in);
} }
/** /**
* Writes a collection of Externalizable objects. The collection passed as a parameter * Writes a collection of Externalizable objects. The collection passed as a parameter
* must be a collection and not a <tt>null</null> value. * must be a collection and not a <tt>null</null> value.
* *
* @param out the output stream. * @param out the output stream.
* @param value the collection of Externalizable objects. This value must not be null. * @param value the collection of Externalizable objects. This value must not be null.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public void writeExternalizableCollection(DataOutput out, Collection<? extends Externalizable> value) throws IOException { public void writeExternalizableCollection(DataOutput out, Collection<? extends Externalizable> value) throws IOException {
writeObject(out, value); writeObject(out, value);
} }
/** /**
* Writes a collection of Serializable objects. The collection passed as a parameter * Writes a collection of Serializable objects. The collection passed as a parameter
* must be a collection and not a <tt>null</null> value. * must be a collection and not a <tt>null</null> value.
* *
* @param out the output stream. * @param out the output stream.
* @param value the collection of Serializable objects. This value must not be null. * @param value the collection of Serializable objects. This value must not be null.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
*/ */
public void writeSerializableCollection(DataOutput out, Collection<? extends Serializable> value) throws IOException { public void writeSerializableCollection(DataOutput out, Collection<? extends Serializable> value) throws IOException {
writeObject(out, value); writeObject(out, value);
} }
/** /**
* Reads a collection of Externalizable objects and adds them to the collection passed as a parameter. The * Reads a collection of Externalizable objects and adds them to the collection passed as a parameter. The
* collection passed as a parameter must be a collection and not a <tt>null</null> value. * collection passed as a parameter must be a collection and not a <tt>null</null> value.
* *
* @param in the input stream. * @param in the input stream.
* @param value the collection of Externalizable objects. This value must not be null. * @param value the collection of Externalizable objects. This value must not be null.
* @param loader class loader to use to build elements inside of the serialized collection. * @param loader class loader to use to build elements inside of the serialized collection.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
* @return the number of elements added to the collection. * @return the number of elements added to the collection.
*/ */
public int readExternalizableCollection(DataInput in, Collection<? extends Externalizable> value, ClassLoader loader) throws IOException { public int readExternalizableCollection(DataInput in, Collection<? extends Externalizable> value, ClassLoader loader) throws IOException {
Collection<Externalizable> result = (Collection<Externalizable>) readObject(in); Collection<Externalizable> result = (Collection<Externalizable>) readObject(in);
if (result == null) return 0; if (result == null) return 0;
((Collection<Externalizable>)value).addAll(result); ((Collection<Externalizable>)value).addAll(result);
return result.size(); return result.size();
} }
/** /**
* Reads a collection of Serializable objects and adds them to the collection passed as a parameter. The * Reads a collection of Serializable objects and adds them to the collection passed as a parameter. The
* collection passed as a parameter must be a collection and not a <tt>null</null> value. * collection passed as a parameter must be a collection and not a <tt>null</null> value.
* *
* @param in the input stream. * @param in the input stream.
* @param value the collection of Serializable objects. This value must not be null. * @param value the collection of Serializable objects. This value must not be null.
* @param loader class loader to use to build elements inside of the serialized collection. * @param loader class loader to use to build elements inside of the serialized collection.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
* @return the number of elements added to the collection. * @return the number of elements added to the collection.
*/ */
public int readSerializableCollection(DataInput in, Collection<? extends Serializable> value, ClassLoader loader) throws IOException { public int readSerializableCollection(DataInput in, Collection<? extends Serializable> value, ClassLoader loader) throws IOException {
Collection<Serializable> result = (Collection<Serializable>) readObject(in); Collection<Serializable> result = (Collection<Serializable>) readObject(in);
if (result == null) return 0; if (result == null) return 0;
((Collection<Serializable>)value).addAll(result); ((Collection<Serializable>)value).addAll(result);
return result.size(); return result.size();
} }
/** /**
* Writes a Map of String key and value pairs. This method handles the * Writes a Map of String key and value pairs. This method handles the
* case when the Map is <tt>null</tt>. * case when the Map is <tt>null</tt>.
* *
* @param out the output stream. * @param out the output stream.
* @param map the Map of String key and Externalizable value pairs. * @param map the Map of String key and Externalizable value pairs.
* @throws java.io.IOException if an error occurs. * @throws java.io.IOException if an error occurs.
*/ */
public void writeExternalizableMap(DataOutput out, Map<String, ? extends Externalizable> map) throws IOException { public void writeExternalizableMap(DataOutput out, Map<String, ? extends Externalizable> map) throws IOException {
writeObject(out, map); writeObject(out, map);
} }
/** /**
* Writes a Map of Serializable key and value pairs. This method handles the * Writes a Map of Serializable key and value pairs. This method handles the
* case when the Map is <tt>null</tt>. * case when the Map is <tt>null</tt>.
* *
* @param out the output stream. * @param out the output stream.
* @param map the Map of Serializable key and value pairs. * @param map the Map of Serializable key and value pairs.
* @throws java.io.IOException if an error occurs. * @throws java.io.IOException if an error occurs.
*/ */
public void writeSerializableMap(DataOutput out, Map<? extends Serializable, ? extends Serializable> map) throws IOException { public void writeSerializableMap(DataOutput out, Map<? extends Serializable, ? extends Serializable> map) throws IOException {
writeObject(out, map); writeObject(out, map);
} }
/** /**
* Reads a Map of String key and value pairs. This method will return * Reads a Map of String key and value pairs. This method will return
* <tt>null</tt> if the Map written to the stream was <tt>null</tt>. * <tt>null</tt> if the Map written to the stream was <tt>null</tt>.
* *
* @param in the input stream. * @param in the input stream.
* @param map a Map of String key and Externalizable value pairs. * @param map a Map of String key and Externalizable value pairs.
* @param loader class loader to use to build elements inside of the serialized collection. * @param loader class loader to use to build elements inside of the serialized collection.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
* @return the number of elements added to the collection. * @return the number of elements added to the collection.
*/ */
public int readExternalizableMap(DataInput in, Map<String, ? extends Externalizable> map, ClassLoader loader) throws IOException { public int readExternalizableMap(DataInput in, Map<String, ? extends Externalizable> map, ClassLoader loader) throws IOException {
Map<String, Externalizable> result = (Map<String, Externalizable>) readObject(in); Map<String, Externalizable> result = (Map<String, Externalizable>) readObject(in);
if (result == null) return 0; if (result == null) return 0;
((Map<String, Externalizable>)map).putAll(result); ((Map<String, Externalizable>)map).putAll(result);
return result.size(); return result.size();
} }
/** /**
* Reads a Map of Serializable key and value pairs. This method will return * Reads a Map of Serializable key and value pairs. This method will return
* <tt>null</tt> if the Map written to the stream was <tt>null</tt>. * <tt>null</tt> if the Map written to the stream was <tt>null</tt>.
* *
* @param in the input stream. * @param in the input stream.
* @param map a Map of Serializable key and value pairs. * @param map a Map of Serializable key and value pairs.
* @param loader class loader to use to build elements inside of the serialized collection. * @param loader class loader to use to build elements inside of the serialized collection.
* @throws IOException if an error occurs. * @throws IOException if an error occurs.
* @return the number of elements added to the collection. * @return the number of elements added to the collection.
*/ */
public int readSerializableMap(DataInput in, Map<? extends Serializable, ? extends Serializable> map, ClassLoader loader) throws IOException { public int readSerializableMap(DataInput in, Map<? extends Serializable, ? extends Serializable> map, ClassLoader loader) throws IOException {
Map<String, Serializable> result = (Map<String, Serializable>) readObject(in); Map<String, Serializable> result = (Map<String, Serializable>) readObject(in);
if (result == null) return 0; if (result == null) return 0;
((Map<String, Serializable>)map).putAll(result); ((Map<String, Serializable>)map).putAll(result);
return result.size(); return result.size();
} }
public void writeStrings(DataOutput out, Collection<String> collection) throws IOException { public void writeStrings(DataOutput out, Collection<String> collection) throws IOException {
writeObject(out, collection); writeObject(out, collection);
} }
public int readStrings(DataInput in, Collection<String> collection) throws IOException { public int readStrings(DataInput in, Collection<String> collection) throws IOException {
Collection<String> result = (Collection<String>) readObject(in); Collection<String> result = (Collection<String>) readObject(in);
if (result == null) return 0; if (result == null) return 0;
collection.addAll(result); collection.addAll(result);
return result.size(); return result.size();
} }
// serialization helpers // serialization helpers
public static void writeObject(DataOutput out, Object obj) throws IOException { public static void writeObject(DataOutput out, Object obj) throws IOException {
if (obj == null) { if (obj == null) {
out.writeByte(0); out.writeByte(0);
} else if (obj instanceof Long) { } else if (obj instanceof Long) {
out.writeByte(1); out.writeByte(1);
out.writeLong((Long) obj); out.writeLong((Long) obj);
} else if (obj instanceof Integer) { } else if (obj instanceof Integer) {
out.writeByte(2); out.writeByte(2);
out.writeInt((Integer) obj); out.writeInt((Integer) obj);
} else if (obj instanceof String) { } else if (obj instanceof String) {
out.writeByte(3); out.writeByte(3);
out.writeUTF((String) obj); out.writeUTF((String) obj);
} else if (obj instanceof Double) { } else if (obj instanceof Double) {
out.writeByte(4); out.writeByte(4);
out.writeDouble((Double) obj); out.writeDouble((Double) obj);
} else if (obj instanceof Float) { } else if (obj instanceof Float) {
out.writeByte(5); out.writeByte(5);
out.writeFloat((Float) obj); out.writeFloat((Float) obj);
} else if (obj instanceof Boolean) { } else if (obj instanceof Boolean) {
out.writeByte(6); out.writeByte(6);
out.writeBoolean((Boolean) obj); out.writeBoolean((Boolean) obj);
} else if (obj instanceof Date) { } else if (obj instanceof Date) {
out.writeByte(8); out.writeByte(8);
out.writeLong(((Date) obj).getTime()); out.writeLong(((Date) obj).getTime());
} else { } else {
out.writeByte(9); out.writeByte(9);
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos); ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj); oos.writeObject(obj);
oos.close(); oos.close();
byte[] buf = bos.toByteArray(); byte[] buf = bos.toByteArray();
out.writeInt(buf.length); out.writeInt(buf.length);
out.write(buf); out.write(buf);
} }
} }
public static Object readObject(DataInput in) throws IOException { public static Object readObject(DataInput in) throws IOException {
byte type = in.readByte(); byte type = in.readByte();
if (type == 0) { if (type == 0) {
return null; return null;
} else if (type == 1) { } else if (type == 1) {
return in.readLong(); return in.readLong();
} else if (type == 2) { } else if (type == 2) {
return in.readInt(); return in.readInt();
} else if (type == 3) { } else if (type == 3) {
return in.readUTF(); return in.readUTF();
} else if (type == 4) { } else if (type == 4) {
return in.readDouble(); return in.readDouble();
} else if (type == 5) { } else if (type == 5) {
return in.readFloat(); return in.readFloat();
} else if (type == 6) { } else if (type == 6) {
return in.readBoolean(); return in.readBoolean();
} else if (type == 8) { } else if (type == 8) {
return new Date(in.readLong()); return new Date(in.readLong());
} else if (type == 9) { } else if (type == 9) {
int len = in.readInt(); int len = in.readInt();
byte[] buf = new byte[len]; byte[] buf = new byte[len];
in.readFully(buf); in.readFully(buf);
ObjectInputStream oin = newObjectInputStream(new ByteArrayInputStream(buf)); ObjectInputStream oin = newObjectInputStream(new ByteArrayInputStream(buf));
try { try {
return oin.readObject(); return oin.readObject();
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new IOException(e); throw new IOException(e);
} finally { } finally {
oin.close(); oin.close();
} }
} else { } else {
throw new IOException("Unknown object type=" + type); throw new IOException("Unknown object type=" + type);
} }
} }
public static ObjectInputStream newObjectInputStream(final InputStream in) throws IOException { public static ObjectInputStream newObjectInputStream(final InputStream in) throws IOException {
return new ObjectInputStream(in) { return new ObjectInputStream(in) {
@Override @Override
protected Class<?> resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException { protected Class<?> resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException {
return loadClass(desc.getName()); return loadClass(desc.getName());
} }
}; };
} }
public static Class<?> loadClass(final String className) throws ClassNotFoundException { public static Class<?> loadClass(final String className) throws ClassNotFoundException {
return loadClass(null, className); return loadClass(null, className);
} }
public static Class<?> loadClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException { public static Class<?> loadClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException {
if (className == null) { if (className == null) {
throw new IllegalArgumentException("ClassName cannot be null!"); throw new IllegalArgumentException("ClassName cannot be null!");
} }
if (className.length() <= MAX_PRIM_CLASSNAME_LENGTH && Character.isLowerCase(className.charAt(0))) { if (className.length() <= MAX_PRIM_CLASSNAME_LENGTH && Character.isLowerCase(className.charAt(0))) {
for (int i = 0; i < PRIMITIVE_CLASSES_ARRAY.length; i++) { for (int i = 0; i < PRIMITIVE_CLASSES_ARRAY.length; i++) {
if (className.equals(PRIMITIVE_CLASSES_ARRAY[i].getName())) { if (className.equals(PRIMITIVE_CLASSES_ARRAY[i].getName())) {
return PRIMITIVE_CLASSES_ARRAY[i]; return PRIMITIVE_CLASSES_ARRAY[i];
} }
} }
} }
ClassLoader theClassLoader = classLoader; ClassLoader theClassLoader = classLoader;
if (className.startsWith("com.hazelcast.") || className.startsWith("[Lcom.hazelcast.")) { if (className.startsWith("com.hazelcast.") || className.startsWith("[Lcom.hazelcast.")) {
theClassLoader = HazelcastInstance.class.getClassLoader(); theClassLoader = HazelcastInstance.class.getClassLoader();
} }
if (theClassLoader == null) { if (theClassLoader == null) {
theClassLoader = Thread.currentThread().getContextClassLoader(); theClassLoader = Thread.currentThread().getContextClassLoader();
} }
if (theClassLoader != null) { if (theClassLoader != null) {
if (className.startsWith("[")) { if (className.startsWith("[")) {
return Class.forName(className, true, theClassLoader); return Class.forName(className, true, theClassLoader);
} else { } else {
return theClassLoader.loadClass(className); return theClassLoader.loadClass(className);
} }
} }
return Class.forName(className); return Class.forName(className);
} }
private static final Class[] PRIMITIVE_CLASSES_ARRAY = {int.class, long.class, boolean.class, byte.class, private static final Class[] PRIMITIVE_CLASSES_ARRAY = {int.class, long.class, boolean.class, byte.class,
float.class, double.class, byte.class, char.class, short.class, void.class}; float.class, double.class, byte.class, char.class, short.class, void.class};
private static final int MAX_PRIM_CLASSNAME_LENGTH = 7; // boolean.class.getName().length(); private static final int MAX_PRIM_CLASSNAME_LENGTH = 7; // boolean.class.getName().length();
} }
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cache; package org.jivesoftware.openfire.plugin.util.cache;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
...@@ -38,6 +38,7 @@ import org.jivesoftware.openfire.cluster.ClusterNodeInfo; ...@@ -38,6 +38,7 @@ import org.jivesoftware.openfire.cluster.ClusterNodeInfo;
import org.jivesoftware.openfire.cluster.NodeID; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.handler.DirectedPresence; import org.jivesoftware.openfire.handler.DirectedPresence;
import org.jivesoftware.openfire.handler.PresenceUpdateHandler; import org.jivesoftware.openfire.handler.PresenceUpdateHandler;
import org.jivesoftware.openfire.plugin.util.cluster.HazelcastClusterNodeInfo;
import org.jivesoftware.openfire.session.ClientSessionInfo; import org.jivesoftware.openfire.session.ClientSessionInfo;
import org.jivesoftware.openfire.session.IncomingServerSession; import org.jivesoftware.openfire.session.IncomingServerSession;
import org.jivesoftware.openfire.session.RemoteSessionLocator; import org.jivesoftware.openfire.session.RemoteSessionLocator;
...@@ -64,7 +65,6 @@ import com.hazelcast.core.Member; ...@@ -64,7 +65,6 @@ import com.hazelcast.core.Member;
import com.hazelcast.core.MemberAttributeEvent; import com.hazelcast.core.MemberAttributeEvent;
import com.hazelcast.core.MembershipEvent; import com.hazelcast.core.MembershipEvent;
import com.hazelcast.core.MembershipListener; import com.hazelcast.core.MembershipListener;
import com.jivesoftware.util.cluster.HazelcastClusterNodeInfo;
/** /**
* ClusterListener reacts to membership changes in the cluster. It takes care of cleaning up the state * ClusterListener reacts to membership changes in the cluster. It takes care of cleaning up the state
...@@ -473,8 +473,10 @@ public class ClusterListener implements MembershipListener, LifecycleListener { ...@@ -473,8 +473,10 @@ public class ClusterListener implements MembershipListener, LifecycleListener {
Collection<JID> getHandlers(EntryEvent event) { Collection<JID> getHandlers(EntryEvent event) {
Object value = event.getValue(); Object value = event.getValue();
Collection<JID> answer = new ArrayList<JID>(); Collection<JID> answer = new ArrayList<JID>();
for (DirectedPresence directedPresence : (Collection<DirectedPresence>)value) { if (value != null) {
answer.add(directedPresence.getHandler()); for (DirectedPresence directedPresence : (Collection<DirectedPresence>)value) {
answer.add(directedPresence.getHandler());
}
} }
return answer; return answer;
} }
......
/** /**
* $Revision$ * $Revision$
* $Date$ * $Date$
* *
* Copyright (C) 1999-2009 Jive Software. All rights reserved. * Copyright (C) 1999-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cache; package org.jivesoftware.openfire.plugin.util.cache;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jivesoftware.util.cache.Cache; import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheFactory; import org.jivesoftware.util.cache.CacheFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.hazelcast.core.EntryListener; import com.hazelcast.core.EntryListener;
import com.hazelcast.core.IMap; import com.hazelcast.core.IMap;
import com.hazelcast.monitor.LocalMapStats; import com.hazelcast.monitor.LocalMapStats;
/** /**
* Clustered implementation of the Cache interface using Hazelcast. * Clustered implementation of the Cache interface using Hazelcast.
* *
*/ */
public class ClusteredCache implements Cache { public class ClusteredCache implements Cache {
private static Logger logger = LoggerFactory.getLogger(ClusteredCache.class); private static Logger logger = LoggerFactory.getLogger(ClusteredCache.class);
private final Map<EntryListener, String> registrations = new HashMap<EntryListener, String>(); private final Map<EntryListener, String> registrations = new HashMap<EntryListener, String>();
/** /**
* The map is used for distributed operations such as get, put, etc. * The map is used for distributed operations such as get, put, etc.
*/ */
protected IMap map; protected IMap map;
private String name; private String name;
private long numberOfGets = 0; private long numberOfGets = 0;
/** /**
* Create a new cache using the supplied named cache as the actual cache implementation * Create a new cache using the supplied named cache as the actual cache implementation
* *
* @param name a name for the cache, which should be unique per vm. * @param name a name for the cache, which should be unique per vm.
* @param cache the cache implementation * @param cache the cache implementation
*/ */
protected ClusteredCache(String name, IMap cache) { protected ClusteredCache(String name, IMap cache) {
map = cache; map = cache;
setName(name); setName(name);
} }
public void addEntryListener(EntryListener listener, boolean includeValue) { public void addEntryListener(EntryListener listener, boolean includeValue) {
registrations.put(listener, map.addEntryListener(listener, includeValue)); registrations.put(listener, map.addEntryListener(listener, includeValue));
} }
public void removeEntryListener(EntryListener listener) { public void removeEntryListener(EntryListener listener) {
String registrationId = registrations.get(listener); String registrationId = registrations.get(listener);
if (registrationId != null) { if (registrationId != null) {
map.removeEntryListener(registrationId); map.removeEntryListener(registrationId);
} }
} }
// Cache Interface // Cache Interface
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Object put(Object key, Object object) { public Object put(Object key, Object object) {
if (object == null) { return null; } if (object == null) { return null; }
return map.put(key, object); return map.put(key, object);
} }
public Object get(Object key) { public Object get(Object key) {
numberOfGets++; numberOfGets++;
return map.get(key); return map.get(key);
} }
public Object remove(Object key) { public Object remove(Object key) {
return map.remove(key); return map.remove(key);
} }
public void clear() { public void clear() {
map.clear(); map.clear();
} }
public int size() { public int size() {
LocalMapStats stats = map.getLocalMapStats(); LocalMapStats stats = map.getLocalMapStats();
return (int) (stats.getOwnedEntryCount() + stats.getBackupEntryCount()); return (int) (stats.getOwnedEntryCount() + stats.getBackupEntryCount());
} }
public boolean containsKey(Object key) { public boolean containsKey(Object key) {
return map.containsKey(key); return map.containsKey(key);
} }
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
return map.containsValue(value); return map.containsValue(value);
} }
public Set entrySet() { public Set entrySet() {
return map.entrySet(); return map.entrySet();
} }
public boolean isEmpty() { public boolean isEmpty() {
return map.isEmpty(); return map.isEmpty();
} }
public Set keySet() { public Set keySet() {
return map.keySet(); return map.keySet();
} }
public void putAll(Map entries) { public void putAll(Map entries) {
map.putAll(entries); map.putAll(entries);
} }
public Collection values() { public Collection values() {
return map.values(); return map.values();
} }
public long getCacheHits() { public long getCacheHits() {
return map.getLocalMapStats().getHits(); return map.getLocalMapStats().getHits();
} }
public long getCacheMisses() { public long getCacheMisses() {
long hits = map.getLocalMapStats().getHits(); long hits = map.getLocalMapStats().getHits();
return numberOfGets > hits ? numberOfGets - hits : 0; return numberOfGets > hits ? numberOfGets - hits : 0;
} }
public int getCacheSize() { public int getCacheSize() {
LocalMapStats stats = map.getLocalMapStats(); LocalMapStats stats = map.getLocalMapStats();
return (int) (stats.getOwnedEntryMemoryCost() + stats.getBackupEntryMemoryCost()); return (int) (stats.getOwnedEntryMemoryCost() + stats.getBackupEntryMemoryCost());
} }
public long getMaxCacheSize() { public long getMaxCacheSize() {
return CacheFactory.getMaxCacheSize(getName()); return CacheFactory.getMaxCacheSize(getName());
} }
public void setMaxCacheSize(int maxSize) { public void setMaxCacheSize(int maxSize) {
CacheFactory.setMaxSizeProperty(getName(), maxSize); CacheFactory.setMaxSizeProperty(getName(), maxSize);
} }
public long getMaxLifetime() { public long getMaxLifetime() {
return CacheFactory.getMaxCacheLifetime(getName()); return CacheFactory.getMaxCacheLifetime(getName());
} }
public void setMaxLifetime(long maxLifetime) { public void setMaxLifetime(long maxLifetime) {
CacheFactory.setMaxSizeProperty(getName(), maxLifetime); CacheFactory.setMaxSizeProperty(getName(), maxLifetime);
} }
public void destroy() { public void destroy() {
map.destroy(); map.destroy();
} }
public boolean lock(Object key, long timeout) { public boolean lock(Object key, long timeout) {
boolean result = true; boolean result = true;
if (timeout < 0) { if (timeout < 0) {
map.lock(key); map.lock(key);
} else if (timeout == 0) { } else if (timeout == 0) {
result = map.tryLock(key); result = map.tryLock(key);
} else { } else {
try { try {
result = map.tryLock(key, timeout, TimeUnit.MILLISECONDS); result = map.tryLock(key, timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.error("Failed to get cluster lock", e); logger.error("Failed to get cluster lock", e);
result = false; result = false;
} }
} }
return result; return result;
} }
public boolean unlock(Object key) { public boolean unlock(Object key) {
boolean result = true; boolean result = true;
try { map.unlock(key); } try { map.unlock(key); }
catch (IllegalMonitorStateException e) { catch (IllegalMonitorStateException e) {
logger.error("Falied to release cluster lock", e); logger.error("Falied to release cluster lock", e);
result = false; result = false;
} }
return result; return result;
} }
} }
/** /**
* $Revision: $ * $Revision: $
* $Date: $ * $Date: $
* *
* Copyright (C) 2007-2009 Jive Software. All rights reserved. * Copyright (C) 2007-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cache; package org.jivesoftware.openfire.plugin.util.cache;
import java.io.Serializable; import java.io.Serializable;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import org.jivesoftware.openfire.JMXManager; import org.jivesoftware.openfire.JMXManager;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.ClusterNodeInfo; import org.jivesoftware.openfire.cluster.ClusterNodeInfo;
import org.jivesoftware.openfire.cluster.NodeID; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.openfire.plugin.session.RemoteSessionLocator;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.openfire.plugin.util.cluster.ClusterPacketRouter;
import org.jivesoftware.util.cache.Cache; import org.jivesoftware.openfire.plugin.util.cluster.HazelcastClusterNodeInfo;
import org.jivesoftware.util.cache.CacheFactoryStrategy; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.cache.CacheWrapper; import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.CacheFactoryStrategy;
import org.jivesoftware.util.cache.ExternalizableUtilStrategy; import org.jivesoftware.util.cache.CacheWrapper;
import org.slf4j.Logger; import org.jivesoftware.util.cache.ClusterTask;
import org.slf4j.LoggerFactory; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.jivesoftware.util.cache.ExternalizableUtilStrategy;
import com.hazelcast.config.ClasspathXmlConfig; import org.slf4j.Logger;
import com.hazelcast.config.Config; import org.slf4j.LoggerFactory;
import com.hazelcast.core.Cluster;
import com.hazelcast.core.Hazelcast; import com.hazelcast.config.ClasspathXmlConfig;
import com.hazelcast.core.HazelcastInstance; import com.hazelcast.config.Config;
import com.hazelcast.core.Member; import com.hazelcast.core.Cluster;
import com.jivesoftware.openfire.session.RemoteSessionLocator; import com.hazelcast.core.Hazelcast;
import com.jivesoftware.util.cluster.ClusterPacketRouter; import com.hazelcast.core.HazelcastInstance;
import com.jivesoftware.util.cluster.HazelcastClusterNodeInfo; import com.hazelcast.core.Member;
/** /**
* CacheFactory implementation to use when using Hazelcast in cluster mode. * CacheFactory implementation to use when using Hazelcast in cluster mode.
* *
* @author Tom Evans * @author Tom Evans
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class ClusteredCacheFactory implements CacheFactoryStrategy { public class ClusteredCacheFactory implements CacheFactoryStrategy {
public static final String HAZELCAST_EXECUTOR_SERVICE_NAME = public static final String HAZELCAST_EXECUTOR_SERVICE_NAME =
JiveGlobals.getProperty("hazelcast.executor.service.name", "openfire::cluster::executor"); JiveGlobals.getProperty("hazelcast.executor.service.name", "openfire::cluster::executor");
private static final long MAX_CLUSTER_EXECUTION_TIME = private static final long MAX_CLUSTER_EXECUTION_TIME =
JiveGlobals.getLongProperty("hazelcast.max.execution.seconds", 30); JiveGlobals.getLongProperty("hazelcast.max.execution.seconds", 30);
private static final long CLUSTER_STARTUP_RETRY_TIME = private static final long CLUSTER_STARTUP_RETRY_TIME =
JiveGlobals.getLongProperty("hazelcast.startup.retry.seconds", 10); JiveGlobals.getLongProperty("hazelcast.startup.retry.seconds", 10);
private static final long CLUSTER_STARTUP_RETRY_COUNT = private static final long CLUSTER_STARTUP_RETRY_COUNT =
JiveGlobals.getLongProperty("hazelcast.startup.retry.count", 1); JiveGlobals.getLongProperty("hazelcast.startup.retry.count", 1);
private static final String HAZELCAST_CONFIG_FILE = private static final String HAZELCAST_CONFIG_FILE =
JiveGlobals.getProperty("hazelcast.config.xml.filename", "hazelcast-cache-config.xml"); JiveGlobals.getProperty("hazelcast.config.xml.filename", "hazelcast-cache-config.xml");
private static final boolean HAZELCAST_JMX_ENABLED = private static final boolean HAZELCAST_JMX_ENABLED =
JiveGlobals.getBooleanProperty("hazelcast.config.jmx.enabled", false); JiveGlobals.getBooleanProperty("hazelcast.config.jmx.enabled", false);
private static Logger logger = LoggerFactory.getLogger(ClusteredCacheFactory.class); private static Logger logger = LoggerFactory.getLogger(ClusteredCacheFactory.class);
/** /**
* Keep serialization strategy the server was using before we set our strategy. We will * Keep serialization strategy the server was using before we set our strategy. We will
* restore old strategy when plugin is unloaded. * restore old strategy when plugin is unloaded.
*/ */
private ExternalizableUtilStrategy serializationStrategy; private ExternalizableUtilStrategy serializationStrategy;
/** /**
* Storage for cache statistics * Storage for cache statistics
*/ */
private static Map<String, Map<String, long[]>> cacheStats; private static Map<String, Map<String, long[]>> cacheStats;
private static HazelcastInstance hazelcast = null; private static HazelcastInstance hazelcast = null;
private static Cluster cluster = null; private static Cluster cluster = null;
private ClusterListener clusterListener; private ClusterListener clusterListener;
/** /**
* Keeps that running state. Initial state is stopped. * Keeps that running state. Initial state is stopped.
*/ */
private State state = State.stopped; private State state = State.stopped;
public boolean startCluster() { public boolean startCluster() {
state = State.starting; state = State.starting;
// Set the serialization strategy to use for transmitting objects between node clusters // Set the serialization strategy to use for transmitting objects between node clusters
serializationStrategy = ExternalizableUtil.getInstance().getStrategy(); serializationStrategy = ExternalizableUtil.getInstance().getStrategy();
ExternalizableUtil.getInstance().setStrategy(new ClusterExternalizableUtil()); ExternalizableUtil.getInstance().setStrategy(new ClusterExternalizableUtil());
// Set session locator to use when in a cluster // Set session locator to use when in a cluster
XMPPServer.getInstance().setRemoteSessionLocator(new RemoteSessionLocator()); XMPPServer.getInstance().setRemoteSessionLocator(new RemoteSessionLocator());
// Set packet router to use to deliver packets to remote cluster nodes // Set packet router to use to deliver packets to remote cluster nodes
XMPPServer.getInstance().getRoutingTable().setRemotePacketRouter(new ClusterPacketRouter()); XMPPServer.getInstance().getRoutingTable().setRemotePacketRouter(new ClusterPacketRouter());
ClassLoader oldLoader = null; ClassLoader oldLoader = null;
// Store previous class loader (in case we change it) // Store previous class loader (in case we change it)
oldLoader = Thread.currentThread().getContextClassLoader(); oldLoader = Thread.currentThread().getContextClassLoader();
ClassLoader loader = new ClusterClassLoader(); ClassLoader loader = new ClusterClassLoader();
Thread.currentThread().setContextClassLoader(loader); Thread.currentThread().setContextClassLoader(loader);
int retry = 0; int retry = 0;
do { do {
try { try {
Config config = new ClasspathXmlConfig(HAZELCAST_CONFIG_FILE); Config config = new ClasspathXmlConfig(HAZELCAST_CONFIG_FILE);
config.setInstanceName("openfire"); config.setInstanceName("openfire");
config.setClassLoader(loader); config.setClassLoader(loader);
if (JMXManager.isEnabled() && HAZELCAST_JMX_ENABLED) { if (JMXManager.isEnabled() && HAZELCAST_JMX_ENABLED) {
config.setProperty("hazelcast.jmx", "true"); config.setProperty("hazelcast.jmx", "true");
config.setProperty("hazelcast.jmx.detailed", "true"); config.setProperty("hazelcast.jmx.detailed", "true");
} }
hazelcast = Hazelcast.newHazelcastInstance(config); hazelcast = Hazelcast.newHazelcastInstance(config);
cluster = hazelcast.getCluster(); cluster = hazelcast.getCluster();
// Update the running state of the cluster // Update the running state of the cluster
state = cluster != null ? State.started : State.stopped; state = cluster != null ? State.started : State.stopped;
// Set the ID of this cluster node // Set the ID of this cluster node
XMPPServer.getInstance().setNodeID(NodeID.getInstance(getClusterMemberID())); XMPPServer.getInstance().setNodeID(NodeID.getInstance(getClusterMemberID()));
// CacheFactory is now using clustered caches. We can add our listeners. // CacheFactory is now using clustered caches. We can add our listeners.
clusterListener = new ClusterListener(cluster); clusterListener = new ClusterListener(cluster);
hazelcast.getLifecycleService().addLifecycleListener(clusterListener); hazelcast.getLifecycleService().addLifecycleListener(clusterListener);
cluster.addMembershipListener(clusterListener); cluster.addMembershipListener(clusterListener);
break; break;
} catch (Exception e) { } catch (Exception e) {
if (retry < CLUSTER_STARTUP_RETRY_COUNT) { if (retry < CLUSTER_STARTUP_RETRY_COUNT) {
logger.warn("Failed to start clustering (" + e.getMessage() + "); " + logger.warn("Failed to start clustering (" + e.getMessage() + "); " +
"will retry in " + CLUSTER_STARTUP_RETRY_TIME + " seconds"); "will retry in " + CLUSTER_STARTUP_RETRY_TIME + " seconds");
try { Thread.sleep(CLUSTER_STARTUP_RETRY_TIME*1000); } try { Thread.sleep(CLUSTER_STARTUP_RETRY_TIME*1000); }
catch (InterruptedException ie) { /* ignore */ } catch (InterruptedException ie) { /* ignore */ }
} else { } else {
logger.error("Unable to start clustering - continuing in local mode", e); logger.error("Unable to start clustering - continuing in local mode", e);
state = State.stopped; state = State.stopped;
} }
} }
} while (retry++ < CLUSTER_STARTUP_RETRY_COUNT); } while (retry++ < CLUSTER_STARTUP_RETRY_COUNT);
if (oldLoader != null) { if (oldLoader != null) {
// Restore previous class loader // Restore previous class loader
Thread.currentThread().setContextClassLoader(oldLoader); Thread.currentThread().setContextClassLoader(oldLoader);
} }
return cluster != null; return cluster != null;
} }
public void stopCluster() { public void stopCluster() {
// Stop the cache services. // Stop the cache services.
cacheStats = null; cacheStats = null;
// Update the running state of the cluster // Update the running state of the cluster
state = State.stopped; state = State.stopped;
// Stop the cluster // Stop the cluster
Hazelcast.shutdownAll(); Hazelcast.shutdownAll();
cluster = null; cluster = null;
// Wait until the server has updated its internal state // Wait until the server has updated its internal state
while (!clusterListener.isDone()) { while (!clusterListener.isDone()) {
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// Ignore // Ignore
} }
} }
// Reset the node ID // Reset the node ID
XMPPServer.getInstance().setNodeID(null); XMPPServer.getInstance().setNodeID(null);
// Reset packet router to use to deliver packets to remote cluster nodes // Reset packet router to use to deliver packets to remote cluster nodes
XMPPServer.getInstance().getRoutingTable().setRemotePacketRouter(null); XMPPServer.getInstance().getRoutingTable().setRemotePacketRouter(null);
// Reset the session locator to use // Reset the session locator to use
XMPPServer.getInstance().setRemoteSessionLocator(null); XMPPServer.getInstance().setRemoteSessionLocator(null);
// Set the old serialization strategy was using before clustering was loaded // Set the old serialization strategy was using before clustering was loaded
ExternalizableUtil.getInstance().setStrategy(serializationStrategy); ExternalizableUtil.getInstance().setStrategy(serializationStrategy);
} }
public Cache createCache(String name) { public Cache createCache(String name) {
// Check if cluster is being started up // Check if cluster is being started up
while (state == State.starting) { while (state == State.starting) {
// Wait until cluster is fully started (or failed) // Wait until cluster is fully started (or failed)
try { try {
Thread.sleep(250); Thread.sleep(250);
} }
catch (InterruptedException e) { catch (InterruptedException e) {
// Ignore // Ignore
} }
} }
if (state == State.stopped) { if (state == State.stopped) {
throw new IllegalStateException("Cannot create clustered cache when not in a cluster"); throw new IllegalStateException("Cannot create clustered cache when not in a cluster");
} }
return new ClusteredCache(name, hazelcast.getMap(name)); return new ClusteredCache(name, hazelcast.getMap(name));
} }
public void destroyCache(Cache cache) { public void destroyCache(Cache cache) {
if (cache instanceof CacheWrapper) { if (cache instanceof CacheWrapper) {
cache = ((CacheWrapper)cache).getWrappedCache(); cache = ((CacheWrapper)cache).getWrappedCache();
} }
ClusteredCache clustered = (ClusteredCache)cache; ClusteredCache clustered = (ClusteredCache)cache;
clustered.destroy(); clustered.destroy();
} }
public boolean isSeniorClusterMember() { public boolean isSeniorClusterMember() {
if (cluster == null) { return false; } if (cluster == null) { return false; }
// first cluster member is the oldest // first cluster member is the oldest
Iterator<Member> members = cluster.getMembers().iterator(); Iterator<Member> members = cluster.getMembers().iterator();
return members.next().getUuid().equals(cluster.getLocalMember().getUuid()); return members.next().getUuid().equals(cluster.getLocalMember().getUuid());
} }
public Collection<ClusterNodeInfo> getClusterNodesInfo() { public Collection<ClusterNodeInfo> getClusterNodesInfo() {
return clusterListener.getClusterNodesInfo(); return clusterListener.getClusterNodesInfo();
} }
public int getMaxClusterNodes() { public int getMaxClusterNodes() {
// No longer depends on license code so just return a big number // No longer depends on license code so just return a big number
return 10000; return 10000;
} }
public byte[] getSeniorClusterMemberID() { public byte[] getSeniorClusterMemberID() {
if (cluster != null && !cluster.getMembers().isEmpty()) { if (cluster != null && !cluster.getMembers().isEmpty()) {
Member oldest = cluster.getMembers().iterator().next(); Member oldest = cluster.getMembers().iterator().next();
return StringUtils.getBytes(oldest.getUuid()); return StringUtils.getBytes(oldest.getUuid());
} }
else { else {
return null; return null;
} }
} }
public byte[] getClusterMemberID() { public byte[] getClusterMemberID() {
if (cluster != null) { if (cluster != null) {
return StringUtils.getBytes(cluster.getLocalMember().getUuid()); return StringUtils.getBytes(cluster.getLocalMember().getUuid());
} }
else { else {
return null; return null;
} }
} }
/** /**
* Gets the pseudo-synchronized time from the cluster. While the cluster members may * Gets the pseudo-synchronized time from the cluster. While the cluster members may
* have varying system times, this method is expected to return a timestamp that is * have varying system times, this method is expected to return a timestamp that is
* synchronized (or nearly so; best effort) across the cluster. * synchronized (or nearly so; best effort) across the cluster.
* *
* @return Synchronized time for all cluster members * @return Synchronized time for all cluster members
*/ */
public long getClusterTime() { public long getClusterTime() {
return cluster == null ? System.currentTimeMillis() : cluster.getClusterTime(); return cluster == null ? System.currentTimeMillis() : cluster.getClusterTime();
} }
/* /*
* Execute the given task on the other (non-local) cluster members. * Execute the given task on the other (non-local) cluster members.
* Note that this method does not provide the result set for the given * Note that this method does not provide the result set for the given
* task, as the task is run asynchronously across the cluster. * task, as the task is run asynchronously across the cluster.
*/ */
public void doClusterTask(final ClusterTask task) { public void doClusterTask(final ClusterTask task) {
if (cluster == null) { return; } if (cluster == null) { return; }
Set<Member> members = new HashSet<Member>(); Set<Member> members = new HashSet<Member>();
Member current = cluster.getLocalMember(); Member current = cluster.getLocalMember();
for(Member member : cluster.getMembers()) { for(Member member : cluster.getMembers()) {
if (!member.getUuid().equals(current.getUuid())) { if (!member.getUuid().equals(current.getUuid())) {
members.add(member); members.add(member);
} }
} }
if (members.size() > 0) { if (members.size() > 0) {
// Asynchronously execute the task on the other cluster members // Asynchronously execute the task on the other cluster members
logger.debug("Executing asynchronous MultiTask: " + task.getClass().getName()); logger.debug("Executing asynchronous MultiTask: " + task.getClass().getName());
hazelcast.getExecutorService(HAZELCAST_EXECUTOR_SERVICE_NAME).submitToMembers( hazelcast.getExecutorService(HAZELCAST_EXECUTOR_SERVICE_NAME).submitToMembers(
new CallableTask<Object>(task), members); new CallableTask<Object>(task), members);
} else { } else {
logger.warn("No cluster members selected for cluster task " + task.getClass().getName()); logger.warn("No cluster members selected for cluster task " + task.getClass().getName());
} }
} }
/* /*
* Execute the given task on the given cluster member. * Execute the given task on the given cluster member.
* Note that this method does not provide the result set for the given * Note that this method does not provide the result set for the given
* task, as the task is run asynchronously across the cluster. * task, as the task is run asynchronously across the cluster.
*/ */
public void doClusterTask(final ClusterTask task, byte[] nodeID) { public void doClusterTask(final ClusterTask task, byte[] nodeID) {
if (cluster == null) { return; } if (cluster == null) { return; }
Member member = getMember(nodeID); Member member = getMember(nodeID);
// Check that the requested member was found // Check that the requested member was found
if (member != null) { if (member != null) {
// Asynchronously execute the task on the target member // Asynchronously execute the task on the target member
logger.debug("Executing asynchronous DistributedTask: " + task.getClass().getName()); logger.debug("Executing asynchronous DistributedTask: " + task.getClass().getName());
hazelcast.getExecutorService(HAZELCAST_EXECUTOR_SERVICE_NAME).submitToMember( hazelcast.getExecutorService(HAZELCAST_EXECUTOR_SERVICE_NAME).submitToMember(
new CallableTask<Object>(task), member); new CallableTask<Object>(task), member);
} else { } else {
String msg = MessageFormat.format("Requested node {0} not found in cluster", StringUtils.getString(nodeID)); String msg = MessageFormat.format("Requested node {0} not found in cluster", StringUtils.getString(nodeID));
logger.warn(msg); logger.warn(msg);
throw new IllegalArgumentException(msg); throw new IllegalArgumentException(msg);
} }
} }
/* /*
* Execute the given task on the designated cluster members. * Execute the given task on the designated cluster members.
* Note that this method blocks for up to MAX_CLUSTER_EXECUTION_TIME * Note that this method blocks for up to MAX_CLUSTER_EXECUTION_TIME
* (seconds) until the task is run on all members. * (seconds) per member until the task is run on all members.
*/ */
public Collection<Object> doSynchronousClusterTask(ClusterTask task, boolean includeLocalMember) { public Collection<Object> doSynchronousClusterTask(ClusterTask task, boolean includeLocalMember) {
if (cluster == null) { return Collections.emptyList(); } if (cluster == null) { return Collections.emptyList(); }
Set<Member> members = new HashSet<Member>(); Set<Member> members = new HashSet<Member>();
Member current = cluster.getLocalMember(); Member current = cluster.getLocalMember();
for(Member member : cluster.getMembers()) { for(Member member : cluster.getMembers()) {
if (includeLocalMember || (!member.getUuid().equals(current.getUuid()))) { if (includeLocalMember || (!member.getUuid().equals(current.getUuid()))) {
members.add(member); members.add(member);
} }
} }
Collection<Object> result = new ArrayList<Object>(); Collection<Object> result = new ArrayList<Object>();
if (members.size() > 0) { if (members.size() > 0) {
// Asynchronously execute the task on the other cluster members // Asynchronously execute the task on the other cluster members
try { try {
logger.debug("Executing MultiTask: " + task.getClass().getName()); logger.debug("Executing MultiTask: " + task.getClass().getName());
Map<Member, Future<Object>> futures = hazelcast.getExecutorService(HAZELCAST_EXECUTOR_SERVICE_NAME) Map<Member, Future<Object>> futures = hazelcast.getExecutorService(HAZELCAST_EXECUTOR_SERVICE_NAME)
.submitToMembers(new CallableTask<Object>(task), members); .submitToMembers(new CallableTask<Object>(task), members);
long nanosLeft = TimeUnit.SECONDS.toNanos(MAX_CLUSTER_EXECUTION_TIME); long nanosLeft = TimeUnit.SECONDS.toNanos(MAX_CLUSTER_EXECUTION_TIME*members.size());
for (Future<Object> future : futures.values()) { for (Future<Object> future : futures.values()) {
long start = System.nanoTime(); long start = System.nanoTime();
result.add(future.get(nanosLeft, TimeUnit.NANOSECONDS)); result.add(future.get(nanosLeft, TimeUnit.NANOSECONDS));
nanosLeft = (System.nanoTime() - start); nanosLeft = (System.nanoTime() - start);
} }
} catch (TimeoutException te) { } catch (TimeoutException te) {
logger.error("Failed to execute cluster task within " + MAX_CLUSTER_EXECUTION_TIME + " seconds", te); logger.error("Failed to execute cluster task within " + MAX_CLUSTER_EXECUTION_TIME + " seconds", te);
} catch (Exception e) { } catch (Exception e) {
logger.error("Failed to execute cluster task", e); logger.error("Failed to execute cluster task", e);
} }
} else { } else {
logger.warn("No cluster members selected for cluster task " + task.getClass().getName()); logger.warn("No cluster members selected for cluster task " + task.getClass().getName());
} }
return result; return result;
} }
/* /*
* Execute the given task on the designated cluster member. * Execute the given task on the designated cluster member.
* Note that this method blocks for up to MAX_CLUSTER_EXECUTION_TIME * Note that this method blocks for up to MAX_CLUSTER_EXECUTION_TIME
* (seconds) until the task is run on the given member. * (seconds) until the task is run on the given member.
*/ */
public Object doSynchronousClusterTask(ClusterTask task, byte[] nodeID) { public Object doSynchronousClusterTask(ClusterTask task, byte[] nodeID) {
if (cluster == null) { return null; } if (cluster == null) { return null; }
Member member = getMember(nodeID); Member member = getMember(nodeID);
Object result = null; Object result = null;
// Check that the requested member was found // Check that the requested member was found
if (member != null) { if (member != null) {
// Asynchronously execute the task on the target member // Asynchronously execute the task on the target member
logger.debug("Executing DistributedTask: " + task.getClass().getName()); logger.debug("Executing DistributedTask: " + task.getClass().getName());
try { try {
Future<Object> future = hazelcast.getExecutorService(HAZELCAST_EXECUTOR_SERVICE_NAME) Future<Object> future = hazelcast.getExecutorService(HAZELCAST_EXECUTOR_SERVICE_NAME)
.submitToMember(new CallableTask<Object>(task), member); .submitToMember(new CallableTask<Object>(task), member);
result = future.get(MAX_CLUSTER_EXECUTION_TIME, TimeUnit.SECONDS); result = future.get(MAX_CLUSTER_EXECUTION_TIME, TimeUnit.SECONDS);
logger.debug("DistributedTask result: " + (result == null ? "null" : result)); logger.debug("DistributedTask result: " + (result == null ? "null" : result));
} catch (TimeoutException te) { } catch (TimeoutException te) {
logger.error("Failed to execute cluster task within " + MAX_CLUSTER_EXECUTION_TIME + " seconds", te); logger.error("Failed to execute cluster task within " + MAX_CLUSTER_EXECUTION_TIME + " seconds", te);
} catch (Exception e) { } catch (Exception e) {
logger.error("Failed to execute cluster task", e); logger.error("Failed to execute cluster task", e);
} }
} else { } else {
String msg = MessageFormat.format("Requested node {0} not found in cluster", StringUtils.getString(nodeID)); String msg = MessageFormat.format("Requested node {0} not found in cluster", StringUtils.getString(nodeID));
logger.warn(msg); logger.warn(msg);
throw new IllegalArgumentException(msg); throw new IllegalArgumentException(msg);
} }
return result; return result;
} }
public ClusterNodeInfo getClusterNodeInfo(byte[] nodeID) { public ClusterNodeInfo getClusterNodeInfo(byte[] nodeID) {
if (cluster == null) { return null; } if (cluster == null) { return null; }
ClusterNodeInfo result = null; ClusterNodeInfo result = null;
Member member = getMember(nodeID); Member member = getMember(nodeID);
if (member != null) { if (member != null) {
result = new HazelcastClusterNodeInfo(member, cluster.getClusterTime()); result = new HazelcastClusterNodeInfo(member, cluster.getClusterTime());
} }
return result; return result;
} }
private Member getMember(byte[] nodeID) { private Member getMember(byte[] nodeID) {
Member result = null; Member result = null;
for(Member member: cluster.getMembers()) { for(Member member: cluster.getMembers()) {
if (Arrays.equals(StringUtils.getBytes(member.getUuid()), nodeID)) { if (Arrays.equals(StringUtils.getBytes(member.getUuid()), nodeID)) {
result = member; result = member;
break; break;
} }
} }
return result; return result;
} }
public void updateCacheStats(Map<String, Cache> caches) { public void updateCacheStats(Map<String, Cache> caches) {
if (caches.size() > 0 && cluster != null) { if (caches.size() > 0 && cluster != null) {
// Create the cacheStats map if necessary. // Create the cacheStats map if necessary.
if (cacheStats == null) { if (cacheStats == null) {
cacheStats = hazelcast.getMap("opt-$cacheStats"); cacheStats = hazelcast.getMap("opt-$cacheStats");
} }
String uid = cluster.getLocalMember().getUuid(); String uid = cluster.getLocalMember().getUuid();
Map<String, long[]> stats = new HashMap<String, long[]>(); Map<String, long[]> stats = new HashMap<String, long[]>();
for (String cacheName : caches.keySet()) { for (String cacheName : caches.keySet()) {
Cache cache = caches.get(cacheName); Cache cache = caches.get(cacheName);
// The following information is published: // The following information is published:
// current size, max size, num elements, cache // current size, max size, num elements, cache
// hits, cache misses. // hits, cache misses.
long [] info = new long[5]; long [] info = new long[5];
info[0] = cache.getCacheSize(); info[0] = cache.getCacheSize();
info[1] = cache.getMaxCacheSize(); info[1] = cache.getMaxCacheSize();
info[2] = cache.size(); info[2] = cache.size();
info[3] = cache.getCacheHits(); info[3] = cache.getCacheHits();
info[4] = cache.getCacheMisses(); info[4] = cache.getCacheMisses();
stats.put(cacheName, info); stats.put(cacheName, info);
} }
// Publish message // Publish message
cacheStats.put(uid, stats); cacheStats.put(uid, stats);
} }
} }
public String getPluginName() { public String getPluginName() {
return "hazelcast"; return "hazelcast";
} }
public Lock getLock(Object key, Cache cache) { public Lock getLock(Object key, Cache cache) {
if (cache instanceof CacheWrapper) { if (cache instanceof CacheWrapper) {
cache = ((CacheWrapper)cache).getWrappedCache(); cache = ((CacheWrapper)cache).getWrappedCache();
} }
return new ClusterLock(key, (ClusteredCache) cache); return new ClusterLock(key, (ClusteredCache) cache);
} }
private static class ClusterLock implements Lock { private static class ClusterLock implements Lock {
private Object key; private Object key;
private ClusteredCache cache; private ClusteredCache cache;
public ClusterLock(Object key, ClusteredCache cache) { public ClusterLock(Object key, ClusteredCache cache) {
this.key = key; this.key = key;
this.cache = cache; this.cache = cache;
} }
public void lock() { public void lock() {
cache.lock(key, -1); cache.lock(key, -1);
} }
public void lockInterruptibly() throws InterruptedException { public void lockInterruptibly() throws InterruptedException {
cache.lock(key, -1); cache.lock(key, -1);
} }
public boolean tryLock() { public boolean tryLock() {
return cache.lock(key, 0); return cache.lock(key, 0);
} }
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return cache.lock(key, unit.toMillis(time)); return cache.lock(key, unit.toMillis(time));
} }
public void unlock() { public void unlock() {
cache.unlock(key); cache.unlock(key);
} }
public Condition newCondition() { public Condition newCondition() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }
private static class CallableTask<Object> implements Callable<Object>, Serializable { private static class CallableTask<Object> implements Callable<Object>, Serializable {
private ClusterTask task; private ClusterTask task;
public CallableTask(ClusterTask task) { public CallableTask(ClusterTask task) {
this.task = task; this.task = task;
} }
public Object call() { public Object call() {
task.run(); task.run();
logger.debug("CallableTask[" + task.getClass().getName() + "] result: " + task.getResult()); logger.debug("CallableTask[" + task.getClass().getName() + "] result: " + task.getResult());
return (Object) task.getResult(); return (Object) task.getResult();
} }
} }
private static enum State { private static enum State {
stopped, stopped,
starting, starting,
started started
} }
} }
/** /**
* $Revision$ * $Revision$
* $Date$ * $Date$
* *
* Copyright (C) 1999-2009 Jive Software. All rights reserved. * Copyright (C) 1999-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cluster; package org.jivesoftware.openfire.plugin.util.cluster;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.tree.DefaultElement; import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.Message; import org.xmpp.packet.Message;
/** /**
* Task that will broadcast a message to local connected client sessions. * Task that will broadcast a message to local connected client sessions.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class BroadcastMessage implements ClusterTask { public class BroadcastMessage implements ClusterTask {
private Message packet; private Message packet;
public BroadcastMessage() { public BroadcastMessage() {
} }
public BroadcastMessage(Message packet) { public BroadcastMessage(Message packet) {
this.packet = packet; this.packet = packet;
} }
public Object getResult() { public Object getResult() {
// Not used since we are using #execute and not #query when using InvocationService // Not used since we are using #execute and not #query when using InvocationService
return null; return null;
} }
public void run() { public void run() {
// Broadcast message to client sessions connected to this node // Broadcast message to client sessions connected to this node
XMPPServer.getInstance().getRoutingTable().broadcastPacket(packet, true); XMPPServer.getInstance().getRoutingTable().broadcastPacket(packet, true);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) packet.getElement()); ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) packet.getElement());
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in); Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
packet = new Message(packetElement, true); packet = new Message(packetElement, true);
} }
} }
/** /**
* $Revision$ * $Revision$
* $Date$ * $Date$
* *
* Copyright (C) 1999-2009 Jive Software. All rights reserved. * Copyright (C) 1999-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cluster; package org.jivesoftware.openfire.plugin.util.cluster;
import org.jivesoftware.openfire.RemotePacketRouter; import org.jivesoftware.openfire.RemotePacketRouter;
import org.jivesoftware.util.cache.CacheFactory; import org.jivesoftware.util.cache.CacheFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Message; import org.xmpp.packet.Message;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
/** /**
* Route packets to other nodes of the cluster. If the remote node was not found or failed * Route packets to other nodes of the cluster. If the remote node was not found or failed
* to be reached then depending on the type of packet an error packet will be returned. In case * to be reached then depending on the type of packet an error packet will be returned. In case
* the remote node is reached but the remote node fails to route the packet to the recipient (e.g. * the remote node is reached but the remote node fails to route the packet to the recipient (e.g.
* the recipient just left) then an error packet may be created from the remote node and send it * the recipient just left) then an error packet may be created from the remote node and send it
* back to this node.<p> * back to this node.<p>
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class ClusterPacketRouter implements RemotePacketRouter { public class ClusterPacketRouter implements RemotePacketRouter {
private static Logger logger = LoggerFactory.getLogger(ClusterPacketRouter.class); private static Logger logger = LoggerFactory.getLogger(ClusterPacketRouter.class);
public boolean routePacket(byte[] nodeID, JID receipient, Packet packet) { public boolean routePacket(byte[] nodeID, JID receipient, Packet packet) {
// Send the packet to the specified node and let the remote node deliver the packet to the recipient // Send the packet to the specified node and let the remote node deliver the packet to the recipient
try { try {
CacheFactory.doClusterTask(new RemotePacketExecution(receipient, packet), nodeID); CacheFactory.doClusterTask(new RemotePacketExecution(receipient, packet), nodeID);
return true; return true;
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
logger.warn("Error while routing packet to remote node: " + e); logger.warn("Error while routing packet to remote node: " + e);
return false; return false;
} }
} }
public void broadcastPacket(Message packet) { public void broadcastPacket(Message packet) {
// Execute the broadcast task across the cluster // Execute the broadcast task across the cluster
CacheFactory.doClusterTask(new BroadcastMessage(packet)); CacheFactory.doClusterTask(new BroadcastMessage(packet));
} }
} }
/** /**
* $Revision$ * $Revision$
* $Date$ * $Date$
* *
* Copyright (C) 1999-2009 Jive Software. All rights reserved. * Copyright (C) 1999-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cluster; package org.jivesoftware.openfire.plugin.util.cluster;
import org.jivesoftware.openfire.cluster.ClusterManager; import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.cluster.ClusterNodeInfo; import org.jivesoftware.openfire.cluster.ClusterNodeInfo;
import org.jivesoftware.openfire.cluster.NodeID; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.util.StringUtils;
import com.hazelcast.core.Member; import com.hazelcast.core.Member;
/** /**
* Cluster Node information as provided by Hazelcast. * Cluster Node information as provided by Hazelcast.
* *
* @author Tom Evans * @author Tom Evans
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class HazelcastClusterNodeInfo implements ClusterNodeInfo { public class HazelcastClusterNodeInfo implements ClusterNodeInfo {
private String hostname; private String hostname;
private NodeID nodeID; private NodeID nodeID;
private long joinedTime; private long joinedTime;
private boolean seniorMember; private boolean seniorMember;
public HazelcastClusterNodeInfo(Member member) { public HazelcastClusterNodeInfo(Member member) {
this(member, System.currentTimeMillis()); this(member, System.currentTimeMillis());
} }
public HazelcastClusterNodeInfo(Member member, Long joinedTime) { public HazelcastClusterNodeInfo(Member member, Long joinedTime) {
hostname = member.getSocketAddress().getHostName(); hostname = member.getSocketAddress().getHostName();
nodeID = NodeID.getInstance(StringUtils.getBytes(member.getUuid())); nodeID = NodeID.getInstance(StringUtils.getBytes(member.getUuid()));
this.joinedTime = joinedTime; this.joinedTime = joinedTime;
seniorMember = ClusterManager.getSeniorClusterMember().equals(StringUtils.getBytes(member.getUuid())); seniorMember = ClusterManager.getSeniorClusterMember().equals(StringUtils.getBytes(member.getUuid()));
} }
public String getHostName() { public String getHostName() {
return hostname; return hostname;
} }
public NodeID getNodeID() { public NodeID getNodeID() {
return nodeID; return nodeID;
} }
public long getJoinedTime() { public long getJoinedTime() {
return joinedTime; return joinedTime;
} }
public boolean isSeniorMember() { public boolean isSeniorMember() {
return seniorMember; return seniorMember;
} }
} }
/** /**
* $Revision$ * $Revision$
* $Date$ * $Date$
* *
* Copyright (C) 1999-2009 Jive Software. All rights reserved. * Copyright (C) 1999-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cluster; package org.jivesoftware.openfire.plugin.util.cluster;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import org.jivesoftware.openfire.cluster.NodeID; import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.util.cache.CacheFactory; import org.jivesoftware.util.cache.CacheFactory;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
/** /**
* A utility class which helps to gather Hazelcast stats and information. * A utility class which helps to gather Hazelcast stats and information.
*/ */
public class NodeRuntimeStats { public class NodeRuntimeStats {
// This properties file is located in the Hazelcast JAR // This properties file is located in the Hazelcast JAR
private static final ResourceBundle config = ResourceBundle.getBundle("hazelcast-runtime"); private static final ResourceBundle config = ResourceBundle.getBundle("hazelcast-runtime");
public static String getProviderConfig(String key) { public static String getProviderConfig(String key) {
return config.getString(key); return config.getString(key);
} }
/** /**
* Returns a Map of HazelcastRuntimeStats.NodeInfo objects keyed by cluster Member objects. * Returns a Map of HazelcastRuntimeStats.NodeInfo objects keyed by cluster Member objects.
* A NodeInfo object is a collection of various Node stats. * A NodeInfo object is a collection of various Node stats.
* *
* @return a Map of NodeInfo objects. * @return a Map of NodeInfo objects.
*/ */
public static Map<NodeID, NodeInfo> getNodeInfo() { public static Map<NodeID, NodeInfo> getNodeInfo() {
// Run cluster-wide stats query // Run cluster-wide stats query
Collection<Object> taskResult = CacheFactory.doSynchronousClusterTask(new NodeInfoTask(), true); Collection<Object> taskResult = CacheFactory.doSynchronousClusterTask(new NodeInfoTask(), true);
Map<NodeID, NodeInfo> result = new HashMap<NodeID, NodeInfo>(); Map<NodeID, NodeInfo> result = new HashMap<NodeID, NodeInfo>();
for (Object tr : taskResult) { for (Object tr : taskResult) {
NodeInfo nodeInfo = (NodeInfo) tr; NodeInfo nodeInfo = (NodeInfo) tr;
NodeID nodeId = NodeID.getInstance(nodeInfo.getNodeId()); NodeID nodeId = NodeID.getInstance(nodeInfo.getNodeId());
result.put(nodeId, nodeInfo); result.put(nodeId, nodeInfo);
} }
return result; return result;
} }
/** /**
* Clears the cache stats. * Clears the cache stats.
*/ */
public static void clearCacheStats() { public static void clearCacheStats() {
// not supported // not supported
} }
/** /**
* Encapsulates statistics and information about a cluster node. * Encapsulates statistics and information about a cluster node.
*/ */
public static class NodeInfoTask implements ClusterTask { public static class NodeInfoTask implements ClusterTask {
private Object result = null; private Object result = null;
public void run() { public void run() {
// Get runtime stats - mem and time: // Get runtime stats - mem and time:
Runtime runtime = Runtime.getRuntime(); Runtime runtime = Runtime.getRuntime();
long free = runtime.freeMemory(); long free = runtime.freeMemory();
long total = runtime.totalMemory(); long total = runtime.totalMemory();
long max = runtime.maxMemory(); long max = runtime.maxMemory();
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
result = new NodeInfo(CacheFactory.getClusterMemberID(), free, total, max, time); result = new NodeInfo(CacheFactory.getClusterMemberID(), free, total, max, time);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSerializable(out, (NodeInfo) result); ExternalizableUtil.getInstance().writeSerializable(out, (NodeInfo) result);
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
result = ExternalizableUtil.getInstance().readSerializable(in); result = ExternalizableUtil.getInstance().readSerializable(in);
} }
public Object getResult() { return result; } public Object getResult() { return result; }
} }
/** /**
* Encapsulates statistics and information about a cluster node. * Encapsulates statistics and information about a cluster node.
*/ */
public static class NodeInfo implements Serializable { public static class NodeInfo implements Serializable {
private byte[] nodeId; private byte[] nodeId;
private long freeMem; private long freeMem;
private long totalMem; private long totalMem;
private long maxMem; private long maxMem;
private long time; private long time;
NodeInfo(byte[] nodeId, long freeMem, long totalMem, long maxMem, long time) NodeInfo(byte[] nodeId, long freeMem, long totalMem, long maxMem, long time)
{ {
this.nodeId = nodeId; this.nodeId = nodeId;
this.freeMem = freeMem; this.freeMem = freeMem;
this.totalMem = totalMem; this.totalMem = totalMem;
this.maxMem = maxMem; this.maxMem = maxMem;
this.time = time; this.time = time;
} }
/** /**
* Returns the amount of free memory in the cluster node's VM (in bytes). * Returns the amount of free memory in the cluster node's VM (in bytes).
* *
* @return the amount of free memory on the cluster node. * @return the amount of free memory on the cluster node.
*/ */
public byte[] getNodeId() { public byte[] getNodeId() {
return nodeId; return nodeId;
} }
/** /**
* Returns the amount of free memory in the cluster node's VM (in bytes). * Returns the amount of free memory in the cluster node's VM (in bytes).
* *
* @return the amount of free memory on the cluster node. * @return the amount of free memory on the cluster node.
*/ */
public long getFreeMem() { public long getFreeMem() {
return freeMem; return freeMem;
} }
/** /**
* Returns the total amount of memory in the cluster node's VM (in bytes). * Returns the total amount of memory in the cluster node's VM (in bytes).
* *
* @return the total amount of memory on the cluster node. * @return the total amount of memory on the cluster node.
*/ */
public long getTotalMem() { public long getTotalMem() {
return totalMem; return totalMem;
} }
/** /**
* Returns the max amount of memory in the cluster node's VM (in bytes). * Returns the max amount of memory in the cluster node's VM (in bytes).
* *
* @return the max amount of memory on the cluster node. * @return the max amount of memory on the cluster node.
*/ */
public long getMaxMem() { public long getMaxMem() {
return maxMem; return maxMem;
} }
/** /**
* Returns the current time on the cluster node in long format. This is useful * Returns the current time on the cluster node in long format. This is useful
* monitoring information for applications that require the local times of each * monitoring information for applications that require the local times of each
* cluster member be to roughly in-synch (on top of the standard Hazelcast * cluster member be to roughly in-synch (on top of the standard Hazelcast
* cluster time).<p> * cluster time).<p>
* *
* This value will always be somewhat inaccurate due to network delays, etc, so * This value will always be somewhat inaccurate due to network delays, etc, so
* should only be taken as an approximate value. * should only be taken as an approximate value.
* *
* @return the local time of the cluster node. * @return the local time of the cluster node.
*/ */
public long getTime() { public long getTime() {
return time; return time;
} }
} }
} }
/** /**
* $Revision$ * $Revision$
* $Date$ * $Date$
* *
* Copyright (C) 1999-2009 Jive Software. All rights reserved. * Copyright (C) 1999-2009 Jive Software. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.jivesoftware.util.cluster; package org.jivesoftware.openfire.plugin.util.cluster;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.tree.DefaultElement; import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.util.cache.ClusterTask; import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil; import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.IQ; import org.xmpp.packet.IQ;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Message; import org.xmpp.packet.Message;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
/** /**
* Task to be executed by remote nodes to deliver the requested packet to the requested * Task to be executed by remote nodes to deliver the requested packet to the requested
* receiver. * receiver.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class RemotePacketExecution implements ClusterTask { public class RemotePacketExecution implements ClusterTask {
private JID recipient; private JID recipient;
private Packet packet; private Packet packet;
public RemotePacketExecution() { public RemotePacketExecution() {
} }
public RemotePacketExecution(JID recipient, Packet packet) { public RemotePacketExecution(JID recipient, Packet packet) {
this.recipient = recipient; this.recipient = recipient;
this.packet = packet; this.packet = packet;
} }
public Object getResult() { public Object getResult() {
return null; return null;
} }
public void run() { public void run() {
// Route packet to entity hosted by this node. If delivery fails then the routing table // Route packet to entity hosted by this node. If delivery fails then the routing table
// will inform the proper router of the failure and the router will handle the error reply logic // will inform the proper router of the failure and the router will handle the error reply logic
XMPPServer.getInstance().getRoutingTable().routePacket(recipient, packet, false); XMPPServer.getInstance().getRoutingTable().routePacket(recipient, packet, false);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSerializable(out, recipient); ExternalizableUtil.getInstance().writeSerializable(out, recipient);
if (packet instanceof IQ) { if (packet instanceof IQ) {
ExternalizableUtil.getInstance().writeInt(out, 1); ExternalizableUtil.getInstance().writeInt(out, 1);
} }
else if (packet instanceof Message) { else if (packet instanceof Message) {
ExternalizableUtil.getInstance().writeInt(out, 2); ExternalizableUtil.getInstance().writeInt(out, 2);
} }
else if (packet instanceof Presence) { else if (packet instanceof Presence) {
ExternalizableUtil.getInstance().writeInt(out, 3); ExternalizableUtil.getInstance().writeInt(out, 3);
} }
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) packet.getElement()); ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) packet.getElement());
} }
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
recipient = (JID) ExternalizableUtil.getInstance().readSerializable(in); recipient = (JID) ExternalizableUtil.getInstance().readSerializable(in);
int packetType = ExternalizableUtil.getInstance().readInt(in); int packetType = ExternalizableUtil.getInstance().readInt(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in); Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
switch (packetType) { switch (packetType) {
case 1: case 1:
packet = new IQ(packetElement, true); packet = new IQ(packetElement, true);
break; break;
case 2: case 2:
packet = new Message(packetElement, true); packet = new Message(packetElement, true);
break; break;
case 3: case 3:
packet = new Presence(packetElement, true); packet = new Presence(packetElement, true);
break; break;
} }
} }
public String toString() { public String toString() {
return super.toString() + " recipient: " + recipient + "packet: " + packet; return super.toString() + " recipient: " + recipient + "packet: " + packet;
} }
} }
\ No newline at end of file
<%@ page import="com.jivesoftware.util.cluster.NodeRuntimeStats, <%@ page import="org.jivesoftware.openfire.plugin.util.cluster.NodeRuntimeStats,
org.jivesoftware.util.cache.CacheFactory, org.jivesoftware.util.cache.CacheFactory,
com.hazelcast.core.Hazelcast, com.hazelcast.core.Hazelcast,
com.hazelcast.core.Cluster, com.hazelcast.core.Cluster,
......
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