Commit dc8b97ec authored by GregDThomas's avatar GregDThomas Committed by daryl herzmann

Delete the long-deprecated Coherence based clustering plugin (#921)

parent 5815efc8
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Clustering Plugin Changelog</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
H2 {
font-size : 10pt;
font-weight : bold;
padding-left : 1em;
}
A:hover {
text-decoration : none;
}
H1 {
font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE {
font-family : courier new;
font-size : 100%;
}
</style>
</head>
<body>
<h1>
Clustering Plugin Changelog
</h1>
<p><b>1.4.0</b> -- October 12, 2015</p>
<ul>
<li>[<a href='http://www.igniterealtime.org/issues/browse/OF-953'>OF-953</a>] - Updated JSP libraries.</li>
<li>Requires Openfire 3.11.0.</li>
</ul>
<p><b>1.3.0</b> -- Sep 13, 2013</p>
<ul>
<li>Requires Openfire 3.9.0.</li>
</ul>
<p><b>1.2.4</b> -- May 1, 2013</p>
<p><b>NOTE</b>: This plugin has been deprecated and is not actively maintained. See the
<a href="readme.html">README</a> document for more information.</p>
<ul>
<li>Updated plugin sources to be compatible with Openfire 3.8.2 (<a href="http://issues.igniterealtime.org/browse/OF-666">cluster time</a>).</li>
</ul>
<p><b>1.2.3</b> -- January 8, 2013</p>
<ul>
<li>Updated plugin sources to be compatible with Openfire 3.7.2.</li>
</ul>
<p><b>1.2.2</b> -- Aug 31, 2012</p>
<ul>
<li>Updated plugin sources to be compatible with Coherence 3.7.1.</li>
<li>Updated README docs with Coherence requirements (EE) and clustering setup.</li>
</ul>
<p><b>1.2.1</b> -- Dec 16, 2011</p>
<ul>
<li>CoherenceCache is now compatible with a changed API of Openfire caches.</li>
</ul>
<p><b>1.2.0</b> -- Nov 10, 2009</p>
<ul>
<li>Changed license to Apache 2.0. Oracle Coherence should now be obtained separately.</li>
<li>ClusterListener is now compatible with distributed caches.</li>
</ul>
<p><b>1.1.1</b> -- June 4, 2008</p>
<ul>
<li>Fixed license validation problem.</li>
</ul>
<p><b>1.1.0</b> -- May 29, 2008</p>
<ul>
<li>Compatible version with Openfire 3.5.2. </li>
</ul>
<p><b>1.0.0</b> -- May 6, 2008</p>
<ul>
<li>Initial release. </li>
</ul>
</body>
</html>
After you have licensed and downloaded Coherence EE from Oracle, place
the following jar files in this folder:
coherence.jar
coherence-work.jar
To build the clustering plugin, issue the following command from
the Openfire (source) /build/ folder:
$OPENFIRE_SRC/build> ant -Dplugin=clustering plugin
Also note that due to classpath loading order, it may be necessary to
either remove the coherence-cache-config.xml file from the Coherence
runtime JAR, or rename the plugin-clustering.jar file to force it to
load before coherence.jar (e.g. "clustering-plugin.jar" or similar).
In order to run Oracle Coherence in production mode, you will need to
secure licensing for the Enterprise Edition (EE) of Coherence. While
clustered caching for Openfire is available in the Standard Edition (SE),
per the Oracle Fusion licensing docs the InvocationService (which is
used by Openfire to distribute tasks among the cluster members) is only
available in EE or Grid Edition (GE).
Note that Coherence is configured to run GE in development mode by default.
You can change this setting by overriding the following Java system properties
via /etc/sysconfig/openfire (RPM) or openfired.vmoptions (Windows):
-Dtangosol.coherence.edition=EE
-Dtangosol.coherence.mode=prod
The current Coherence release is version 3.7.1.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<class>com.jivesoftware.openfire.ClusteringPlugin</class>
<name>Clustering Plugin</name>
<description>(deprecated) Adds clustering support.</description>
<author>Jive Software</author>
<version>1.4.0</version>
<date>10/12/2015</date>
<minServerVersion>4.0.0</minServerVersion>
</plugin>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>plugins</artifactId>
<groupId>org.igniterealtime.openfire</groupId>
<version>4.2.0-SNAPSHOT</version>
</parent>
<groupId>org.igniterealtime.openfire.plugins</groupId>
<artifactId>clustering</artifactId>
<version>1.4.0</version>
<name>Clustering Plugin</name>
<description>(deprecated) Adds clustering support.</description>
<build>
<sourceDirectory>src/java</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Clustering Plugin Readme</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
H2 {
font-size : 10pt;
font-weight : bold;
}
A:hover {
text-decoration : none;
}
H1 {
font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE {
font-family : courier new;
font-size : 100%;
}
#datatable TH {
color : #fff;
background-color : #2A448C;
text-align : left;
}
#datatable TD {
background-color : #FAF6EF;
}
#datatable .name {
background-color : #DCE2F5;
}
</style>
</head>
<body>
<h1>
Clustering Plugin Readme
</h1>
<div id="datatable">
<p class="name">&nbsp;<br />
<b>PLEASE NOTE</b> -- Clustering Plugin Users:<br /><br />
Starting with Openfire 3.8.0, this Coherence-based clustering plugin
has been deprecated in favor of the new Hazelcast-based plugin (/plugins/hazelcast).
Refer to the Hazelcast plugin documentation or
<a href="http://community.igniterealtime.org/message/224947#224947">this community post</a>
for additional information.<br /><br />
This plugin has been updated and is expected to be compatible with Openfire 3.8.x. However,
please be advised that <b>no functional testing</b> has been performed on the latest version.
<i>This plugin is no longer actively maintained.</i><br />&nbsp;
</p>
</div>
<h2>Overview</h2>
<p>
The clustering plugin adds support for running multiple redundant Openfire
servers together in a cluster. By running Openfire in a cluster, you can
distribute the connection load among several servers, as well as having some
form of failover in the event that one of your servers dies. <font color="red">This
plugin requires a valid <a href="http://www.oracle.com/technology/products/coherence/index.html">Oracle Coherence</a> license.</font>
</p><p>
In order to run Oracle Coherence in production mode, you will need to secure
licensing for (at least) the Enterprise Edition (EE) of Coherence. Refer to the
<a href="http://docs.oracle.com/cd/E14571_01/doc.1111/e14860/products.htm#BABIEAJF">
Oracle Fusion licensing docs</a> for more information. Openfire uses the Compute Grid
InvocationService to distribute tasks among the cluster members, but this feature is
currently available only in EE or Grid Edition (GE).
</p><p>
Note that Coherence is configured to run as GE in development mode by default.
You can change this setting by overriding the following Java system properties
via /etc/sysconfig/openfire (RPM) or openfired.vmoptions (Windows):
</p><pre>
-Dtangosol.coherence.edition=EE
-Dtangosol.coherence.mode=prod
</pre><p>
The current Coherence release is version 3.7.1.</p>
<h2>Installation</h2>
<p>After installing the clustering plugin (by copying clustering.jar into the Openfire plugins directory),
follow steps 1 through 4 for adding Oracle Coherence libraries to Openfire. Step 5
explains how to add this plugin to your Openfire setup.
<ol>
<li>Get <a href="http://www.oracle.com/technology/products/coherence/index.html">Oracle Coherence for Java Version</a>.</li>
<li>Unzip the coherence file and locate <b>coherence.jar</b> and <b>coherence-work.jar</b> in folder coherence/lib.</li>
<li>Copy <b>coherence.jar</b> and <b>coherence-work.jar</b> to [openfire_home]/plugins/clustering/lib.</li>
<li>Restart Openfire server.</li>
</ol>
This version of the plugin has been updated to be compatible with Oracle Coherence Version 3.7.1. Earlier
versions of the clustering plugin are incompatible with Coherence 3.7.1 due to certain changes in the
Coherence API.
</p>
<h2>Upgrading from Openfire Enterprise</h2>
<p>
To upgrade from Enterprise, you will need to shut down your server,
remove the <b>enterprise.jar</b> file and <b>enterprise</b> directory from
the plugins directory in your Openfire install root, and then follow the steps
outlined in the <i>Installation</i> section above.
</p>
<h2>Configuration</h2>
<p>
To enable clustering or monitor the cluster go to: Server --&gt; Server Manager --&gt; Clustering
</p>
<p>
You can change a number of Coherence properties by overriding Java system properties
via /etc/sysconfig/openfire (RPM) or openfired.vmoptions (Windows). For example,
to change the default cluster multicast port number, use the following:
</p><pre>
-Dtangosol.coherence.clusterport=32380
</pre><p>
Other such settings may be found in the tangosol-coherence.xml file located in the
coherence.jar file, identified via the "system-property" attribute.</p>
<h2>Compiling from source code</h2>
<p>
If you want to modify or maintain this plugin you will need to get its source code and compile it.
Source code of this plugin is now available in the list of plugins that you get when you download
the <a href="http://www.igniterealtime.org/downloads/source.jsp">Openfire's source code</a>. Follow
these steps to have a working environment:
<ol>
<li>Get <a href="http://www.igniterealtime.org/downloads/source.jsp">Openfire's source code</a>.</li>
<li>Get <a href="http://www.oracle.com/technology/products/coherence/index.html">Oracle Coherence for Java Version</a>.</li>
<li>Unzip the coherence file and locate <b>coherence.jar</b> and <b>coherence-work.jar</b> in folder coherence/lib.</li>
<li>Copy <b>coherence.jar</b> and <b>coherence-work.jar</b> to [openfire]/plugins/clustering/lib.</li>
<li>Add <b>coherence.jar</b> and <b>coherence-work.jar</b> to your IDE build path, or use the Ant build script provided
with the Openfire source distribution (e.g. "ant -Dplugin=clustering plugin").</li>
</ol>
</p>
</body>
</html>
##
## Clustering Resource Bundle
##
## Additional locales can be specified by creating a new resource file in this
## directory using the following conventions:
##
## clustering_i18n "_" language "_" country ".properties"
## clustering_i18n "_" language ".properties"
##
## e.g.
## clustering_i18n_en.propertis <- English resources
## clustering_i18n_en_US.properties <- American US resources
## clustering_i18n_de.properties <- German resources
## clustering_i18n_ja.properties <- Japanese resources
##
## Please note that the two digit language code should be lower case, and the
## two digit country code should be in uppercase. Often, it is not necessary to
## specify the country code.
##
## A full list of language codes can be found at
## http://www-old.ics.uci.edu/pub/ietf/http/related/iso639.txt
## and a full list of country codes can be found at
## http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
##
## In property strings that are parameterized, single quotes can be used to
## quote the "{" (curly brace) if necessary. A real single quote is represented by ''.
##
## REVISION HISTORY (by Enterprise version):
##
## 1.0.0
## Initial Release
plugin.name=Clustering Plugin
plugin.description=Clustering support for Openfire.
##
## Clustering Resource Bundle - Czech locale (cs_CZ)
##
## For a full changelog, refer to the English bundle, clustering_i18n.properties.
##
plugin.name=Clustering Plugin
plugin.description=Clustering support for Openfire.
##
## Clustering Resource Bundle - Spanish locale (es)
##
## For a full changelog, refer to the English bundle, clustering_i18n.properties.
##
plugin.name=Clustering Plugin
plugin.description=Clustering support for Openfire.
# Java Resource Bundle
# Modified by Zaval JRC Editor (C) Zaval CE Group
# http://www.zaval.org/products/jrc-editor/
#
plugin.name=Clustering Plugin
plugin.description=Clustering support for Openfire.
##
## Clustering Resource Bundle - Chinese locale (zh_CN)
##
## For a full changelog, refer to the English bundle, clustering_i18n.properties
.
##
plugin.name=Clustering Plugin
plugin.description=Clustering support for Openfire.
<?xml version='1.0'?>
<!--
Copyright 2001-2005 by Tangosol, Inc. All rights reserved.
This software is the confidential and proprietary information of
Tangosol, Inc. You shall not disclose such confidential and pro-
prietary information and shall use it only in accordance with the
terms of the license agreement you entered into with Tangosol, Inc.
Tangosol, Inc. makes no representations or warranties about the suit-
ability of the software, either express or implied, including but not
limited to the implied warranties of merchantability, fitness for a
particular purpose, or non-infringement. Tangosol, Inc. shall not be
liable for any damages suffered by licensee as a result of using,
modifying or distributing this software or its derivatives.
Tangosol, Inc. is located at http://www.tangosol.com and can be
contacted by e-mail at info@tangosol.com.
This notice may not be removed or altered.
-->
<!--
To override default values defined in this file you will need to add the required
system property as a Java system property.
For instance, if you want to change the default port used for clustering then the
system property to override is tangosol.coherence.clusterport.
Adding -Dtangosol.coherence.clusterport=32390 to your command line when starting
up the server will change the port to use for clustering to be 32390. Depending on
the way you deployed the server you might need to add the property to the
openfired.vmoptions file or /etc/sysconfig/openfire if you are using the RPM install.
-->
<!DOCTYPE coherence PUBLIC
"-//Tangosol, Inc.//DTD Tangosol Coherence 3.0//EN"
"http://www.tangosol.com/dtd/coherence_3_0.dtd">
<coherence>
<cluster-config>
<multicast-listener>
<port system-property="tangosol.coherence.clusterport">32386</port>
<join-timeout-milliseconds>20000</join-timeout-milliseconds>
</multicast-listener>
<shutdown-listener>
<enabled system-property="tangosol.coherence.shutdownhook">false</enabled>
</shutdown-listener>
<services>
<service id="3">
<init-params>
<init-param id="6">
<param-name>backup-count</param-name>
<param-value system-property="tangosol.coherence.distributed.backupcount">1</param-value>
</init-param>
</init-params>
</service>
</services>
</cluster-config>
<configurable-cache-factory-config>
<class-name>com.jivesoftware.util.cache.JiveConfigurableCacheFactory</class-name>
<init-params>
<init-param>
<param-type>java.lang.String</param-type>
<param-value system-property="tangosol.coherence.cacheconfig">coherence-cache-config.xml</param-value>
</init-param>
</init-params>
</configurable-cache-factory-config>
</coherence>
/*
* Copyright (C) 2004-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire;
import java.io.File;
import java.io.FileFilter;
import java.net.MalformedURLException;
import java.net.URL;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import com.tangosol.net.CacheFactory;
/**
* Clustering Enterprise plugin.
*
* @author Matt Tucker
*/
public class ClusteringPlugin implements Plugin {
private static final String COHERENCE_CONFIG = "tangosol-coherence-override";
private static final String COHERENCE_CACHE_CONFIG = "coherence-cache-config";
public void initializePlugin(PluginManager manager, File pluginDirectory) {
// Check if we Enterprise is installed and stop loading this plugin if found
File pluginDir = new File(JiveGlobals.getHomeDirectory(), "plugins");
File[] jars = pluginDir.listFiles(new FileFilter() {
public boolean accept(File pathname) {
String fileName = pathname.getName().toLowerCase();
return (fileName.equalsIgnoreCase("enterprise.jar") || fileName.equalsIgnoreCase("hazelcast.jar"));
}
});
if (jars.length > 0) {
// Do not load this plugin since Enterprise is still installed
System.out.println("Conflicting plugin found. Stopping Clustering Plugin");
throw new IllegalStateException("This plugin cannot run with the Enterprise or Hazelcast plugin");
}
// Make sure that the enteprise folder exists under the home directory
File enterpriseDir = new File(JiveGlobals.getHomeDirectory() +
File.separator + "enterprise");
if (!enterpriseDir.exists()) {
enterpriseDir.mkdirs();
}
// Check if Coherence libs are installed and stop loading this plugin if NOT found
// File libDir = new File(JiveGlobals.getHomeDirectory(), "lib");
// jars = libDir.listFiles(new FileFilter() {
// public boolean accept(File pathname) {
// String fileName = pathname.getName().toLowerCase();
// return (fileName.equalsIgnoreCase("coherence.jar"));
// }
// });
// if (jars.length == 0) {
// // Do not load this plugin since Coherence libs are not installed
// System.out.println("Coherence libs not found. Stopping Clustering Plugin. Copy tangosol.jar, " +
// "coherence.jar and coherence-work.jar files to [OPENFIRE_HOME]/lib and restart the server.");
// throw new IllegalStateException("Coherence libs not found. Stopping Clustering Plugin. Copy " +
// "tangosol.jar, coherence.jar and coherence-work.jar files to [OPENFIRE_HOME]/lib and restart the server.");
// }
// Delete no longer used COHERENCE_CONFIG file. Java system properties should be used
// to customize coherence
File configFile = new File(enterpriseDir, COHERENCE_CONFIG + ".xml");
if (configFile.exists()) {
configFile.delete();
}
// Delete no longer used COHERENCE_CACHE_CONFIG file. Admins should use system properties
// to override default values. Same system properties will be used when not using enterprise or not
// using clustering
configFile = new File(enterpriseDir, COHERENCE_CACHE_CONFIG + ".xml");
if (configFile.exists()) {
configFile.delete();
}
try {
// Add openfireHome/enterprise dir to pluginclassloader
// Add enterprise plugin dir to pluginclassloader
URL url = new File(pluginDirectory + File.separator).toURL();
manager.getPluginClassloader(manager.getPlugin(pluginDirectory.getName())).addURLFile(url);
}
catch (MalformedURLException e) {
Log.error("Error adding openfireHome/enterprise to the classpath of the enterprise plugin", e);
}
CacheFactory.getClusterConfig();
ClusterManager.startup();
}
public void destroyPlugin() {
// Shutdown is initiated by XMPPServer before unloading plugins
if (!XMPPServer.getInstance().isShuttingDown()) {
ClusterManager.shutdown();
}
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.NodeID;
import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.spi.ClientRoute;
import org.jivesoftware.openfire.spi.RoutingTableImpl;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheFactory;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Class that defines possible remote operations that could be performed
* on remote client sessions.
*
* @author Gaston Dombiak
*/
public class ClientSessionTask extends RemoteSessionTask {
private JID address;
public ClientSessionTask() {
super();
}
protected ClientSessionTask(JID address, Operation operation) {
super(operation);
this.address = address;
}
Session getSession() {
return XMPPServer.getInstance().getRoutingTable().getClientRoute(address);
}
public void run() {
super.run();
ClientSession session = (ClientSession) getSession();
if (session instanceof RemoteClientSession) {
// The session is being hosted by other cluster node so log this unexpected case
Cache<String, ClientRoute> usersCache = CacheFactory.createCache(RoutingTableImpl.C2S_CACHE_NAME);
ClientRoute route = usersCache.get(address.toString());
NodeID nodeID = route.getNodeID();
Log.warn("Found remote session instead of local session. JID: " + address + " found in Node: " +
nodeID.toByteArray() + " and local node is: " + XMPPServer.getInstance().getNodeID().toByteArray());
}
if (operation == Operation.isInitialized) {
if (session instanceof RemoteClientSession) {
// Something is wrong since the session shoud be local instead of remote
// Assume some default value
result = true;
}
else {
result = session.isInitialized();
}
}
else if (operation == Operation.incrementConflictCount) {
if (session instanceof RemoteClientSession) {
// Something is wrong since the session shoud be local instead of remote
// Assume some default value
result = 2;
}
else {
result = session.incrementConflictCount();
}
}
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, address);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
public String toString() {
return super.toString() + " operation: " + operation + " address: " + address;
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.ComponentSession;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Class that defines possible remote operations that could be performed
* on remote component sessions (for external components only).
*
* @author Gaston Dombiak
*/
public class ComponentSessionTask extends RemoteSessionTask {
private JID address;
public ComponentSessionTask() {
}
protected ComponentSessionTask(JID address, Operation operation) {
super(operation);
this.address = address;
}
Session getSession() {
return SessionManager.getInstance().getComponentSession(address.getDomain());
}
public void run() {
super.run();
if (operation == Operation.getType) {
result = ((ComponentSession) getSession()).getExternalComponent().getType();
}
else if (operation == Operation.getCategory) {
result = ((ComponentSession) getSession()).getExternalComponent().getCategory();
}
else if (operation == Operation.getInitialSubdomain) {
result = ((ComponentSession) getSession()).getExternalComponent().getInitialSubdomain();
}
else if (operation == Operation.getSubdomains) {
result = ((ComponentSession) getSession()).getExternalComponent().getSubdomains();
}
else if (operation == Operation.getName) {
result = ((ComponentSession) getSession()).getExternalComponent().getName();
}
else if (operation == Operation.getDescription) {
result = ((ComponentSession) getSession()).getExternalComponent().getDescription();
}
else if (operation == Operation.start) {
((ComponentSession) getSession()).getExternalComponent().start();
}
else if (operation == Operation.shutdown) {
((ComponentSession) getSession()).getExternalComponent().shutdown();
}
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, address);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
public String toString() {
return super.toString() + " operation: " + operation + " address: " + address;
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.JID;
/**
* Class that defines possible remote operations that could be performed
* on remote connection manager sessions.
*
* @author Gaston Dombiak
*/
public class ConnectionMultiplexerSessionTask extends RemoteSessionTask {
private JID address;
public ConnectionMultiplexerSessionTask() {
}
protected ConnectionMultiplexerSessionTask(JID address, Operation operation) {
super(operation);
this.address = address;
}
Session getSession() {
return SessionManager.getInstance().getConnectionMultiplexerSession(address);
}
public String toString() {
return super.toString() + " operation: " + operation + " address: " + address;
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.spi.BasicStreamIDFactory;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Cluster task that will ask a remote cluster node to deliver some raw text to a local session.
*
* @author Gaston Dombiak
*/
public class DeliverRawTextTask implements ClusterTask<Void> {
private SessionType sessionType;
private JID address;
private StreamID streamID;
private String text;
public DeliverRawTextTask() {
super();
}
protected DeliverRawTextTask(RemoteSession remoteSession, JID address, String text) {
if (remoteSession instanceof RemoteClientSession) {
this.sessionType = SessionType.client;
}
else if (remoteSession instanceof RemoteOutgoingServerSession) {
this.sessionType = SessionType.outgoingServer;
}
else if (remoteSession instanceof RemoteComponentSession) {
this.sessionType = SessionType.component;
}
else if (remoteSession instanceof RemoteConnectionMultiplexerSession) {
this.sessionType = SessionType.connectionManager;
}
else {
Log.error("Invalid RemoteSession was used for task: " + remoteSession);
}
this.address = address;
this.text = text;
}
public DeliverRawTextTask(StreamID streamID, String text) {
this.sessionType = SessionType.incomingServer;
this.streamID = streamID;
this.text = text;
}
public Void getResult() {
return null;
}
public void run() {
getSession().deliverRawText(text);
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSafeUTF(out, text);
ExternalizableUtil.getInstance().writeInt(out, sessionType.ordinal());
ExternalizableUtil.getInstance().writeBoolean(out, address != null);
if (address != null) {
ExternalizableUtil.getInstance().writeSerializable(out, address);
}
ExternalizableUtil.getInstance().writeBoolean(out, streamID != null);
if (streamID != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, streamID.getID());
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
text = ExternalizableUtil.getInstance().readSafeUTF(in);
sessionType = SessionType.values()[ExternalizableUtil.getInstance().readInt(in)];
if (ExternalizableUtil.getInstance().readBoolean(in)) {
address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
streamID = BasicStreamIDFactory.createStreamID( ExternalizableUtil.getInstance().readSafeUTF(in) );
}
}
Session getSession() {
if (sessionType == SessionType.client) {
return XMPPServer.getInstance().getRoutingTable().getClientRoute(address);
}
else if (sessionType == SessionType.component) {
return SessionManager.getInstance().getComponentSession(address.getDomain());
}
else if (sessionType == SessionType.connectionManager) {
return SessionManager.getInstance().getConnectionMultiplexerSession(address);
}
else if (sessionType == SessionType.outgoingServer) {
return SessionManager.getInstance().getOutgoingServerSession(address.getDomain());
}
else if (sessionType == SessionType.incomingServer) {
return SessionManager.getInstance().getIncomingServerSession(streamID);
}
Log.error("Found unknown session type: " + sessionType);
return null;
}
public String toString() {
return super.toString() + " sessionType: " + sessionType + " address: " + address;
}
private enum SessionType {
client,
outgoingServer,
incomingServer,
component,
connectionManager
}
}
\ No newline at end of file
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.session.IncomingServerSession;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.spi.BasicStreamIDFactory;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Class that defines possible remote operations that could be performed
* on remote incoming server sessions.
*
* @author Gaston Dombiak
*/
public class IncomingServerSessionTask extends RemoteSessionTask {
private StreamID streamID;
public IncomingServerSessionTask() {
super();
}
protected IncomingServerSessionTask(Operation operation, StreamID streamID) {
super(operation);
this.streamID = streamID;
}
Session getSession() {
return SessionManager.getInstance().getIncomingServerSession(streamID);
}
public void run() {
super.run();
if (operation == Operation.getLocalDomain) {
result = ((IncomingServerSession) getSession()).getLocalDomain();
}
else if (operation == Operation.getAddress) {
result = getSession().getAddress();
}
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF( out, streamID.getID() );
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
streamID = BasicStreamIDFactory.createStreamID( ExternalizableUtil.getInstance().readSafeUTF(in) );
}
public String toString() {
return super.toString() + " operation: " + operation + " streamID: " + streamID;
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.OutgoingServerSession;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Class that defines possible remote operations that could be performed
* on remote outgoing server sessions.
*
* @author Gaston Dombiak
*/
public class OutgoingServerSessionTask extends RemoteSessionTask {
private JID address;
public OutgoingServerSessionTask() {
}
protected OutgoingServerSessionTask(JID address, Operation operation) {
super(operation);
this.address = address;
}
Session getSession() {
return SessionManager.getInstance().getOutgoingServerSession(address.getDomain());
}
public void run() {
super.run();
if (operation == Operation.getAuthenticatedDomains) {
result = ((OutgoingServerSession) getSession()).getAuthenticatedDomains();
}
else if (operation == Operation.getHostnames) {
result = ((OutgoingServerSession) getSession()).getHostnames();
}
else if (operation == Operation.isUsingServerDialback) {
result = ((OutgoingServerSession) getSession()).isUsingServerDialback();
}
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, address);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
public String toString() {
return super.toString() + " operation: " + operation + " address: " + address;
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.spi.BasicStreamIDFactory;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.*;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Cluster task that will ask a remote cluster node to deliver some packet to a local session.
*
* @author Gaston Dombiak
*/
public class ProcessPacketTask implements ClusterTask<Void> {
private SessionType sessionType;
private JID address;
private StreamID streamID;
private Packet packet;
public ProcessPacketTask() {
super();
}
protected ProcessPacketTask(RemoteSession remoteSession, JID address, Packet packet) {
if (remoteSession instanceof RemoteClientSession) {
this.sessionType = SessionType.client;
}
else if (remoteSession instanceof RemoteOutgoingServerSession) {
this.sessionType = SessionType.outgoingServer;
}
else if (remoteSession instanceof RemoteComponentSession) {
this.sessionType = SessionType.component;
}
else if (remoteSession instanceof RemoteConnectionMultiplexerSession) {
this.sessionType = SessionType.connectionManager;
}
else {
Log.error("Invalid RemoteSession was used for task: " + remoteSession);
}
this.address = address;
this.packet = packet;
}
protected ProcessPacketTask(StreamID streamID, Packet packet) {
this.sessionType = SessionType.incomingServer;
this.streamID = streamID;
this.packet = packet;
}
public Void getResult() {
return null;
}
public void run() {
getSession().process(packet);
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeBoolean(out, address != null);
if (address != null) {
ExternalizableUtil.getInstance().writeSerializable(out, address);
}
ExternalizableUtil.getInstance().writeBoolean(out, streamID != null);
if (streamID != null) {
ExternalizableUtil.getInstance().writeSafeUTF( out, streamID.getID() );
}
ExternalizableUtil.getInstance().writeInt(out, sessionType.ordinal());
if (packet instanceof IQ) {
ExternalizableUtil.getInstance().writeInt(out, 1);
} else if (packet instanceof Message) {
ExternalizableUtil.getInstance().writeInt(out, 2);
} else if (packet instanceof Presence) {
ExternalizableUtil.getInstance().writeInt(out, 3);
}
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) packet.getElement());
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
if (ExternalizableUtil.getInstance().readBoolean(in)) {
address = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
streamID = BasicStreamIDFactory.createStreamID( ExternalizableUtil.getInstance().readSafeUTF(in) );
}
sessionType = SessionType.values()[ExternalizableUtil.getInstance().readInt(in)];
int packetType = ExternalizableUtil.getInstance().readInt(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
switch (packetType) {
case 1:
packet = new IQ(packetElement, true);
break;
case 2:
packet = new Message(packetElement, true);
break;
case 3:
packet = new Presence(packetElement, true);
break;
}
}
Session getSession() {
if (sessionType == SessionType.client) {
return XMPPServer.getInstance().getRoutingTable().getClientRoute(address);
}
else if (sessionType == SessionType.component) {
return SessionManager.getInstance().getComponentSession(address.getDomain());
}
else if (sessionType == SessionType.connectionManager) {
return SessionManager.getInstance().getConnectionMultiplexerSession(address);
}
else if (sessionType == SessionType.outgoingServer) {
return SessionManager.getInstance().getOutgoingServerSession(address.getDomain());
}
else if (sessionType == SessionType.incomingServer) {
return SessionManager.getInstance().getIncomingServerSession(streamID);
}
Log.error("Found unknown session type: " + sessionType);
return null;
}
public String toString() {
return super.toString() + " sessionType: " + sessionType + " address: " + address;
}
private enum SessionType {
client,
outgoingServer,
incomingServer,
component,
connectionManager
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.session.ComponentSession;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.component.ComponentException;
import org.xmpp.component.ComponentManager;
import org.xmpp.packet.*;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collection;
/**
* Surrogate for sessions of external components hosted in some remote cluster node.
*
* @author Gaston Dombiak
*/
public class RemoteComponentSession extends RemoteSession implements ComponentSession {
private ExternalComponent component;
public RemoteComponentSession(byte[] nodeID, JID address) {
super(nodeID, address);
component = new RemoteExternalComponent(address);
}
public ExternalComponent getExternalComponent() {
return component;
}
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new ComponentSessionTask(address, operation);
}
ClusterTask getDeliverRawTextTask(String text) {
return new DeliverRawTextTask(this, address, text);
}
ClusterTask getProcessPacketTask(Packet packet) {
return new ProcessPacketTask(this, address, packet);
}
private class RemoteExternalComponent implements ExternalComponent {
private JID address;
public RemoteExternalComponent(JID address) {
this.address = address;
}
public void setName(String name) {
RemoteSessionTask task = new SetterTask(address, SetterTask.Type.name, name);
doClusterTask(task);
}
public String getType() {
ClusterTask task = new ComponentSessionTask(address, RemoteSessionTask.Operation.getType);
return (String) doSynchronousClusterTask(task);
}
public void setType(String type) {
RemoteSessionTask task = new SetterTask(address, SetterTask.Type.type, type);
doClusterTask(task);
}
public String getCategory() {
ClusterTask task = new ComponentSessionTask(address, RemoteSessionTask.Operation.getCategory);
return (String) doSynchronousClusterTask(task);
}
public void setCategory(String category) {
RemoteSessionTask task = new SetterTask(address, SetterTask.Type.catergory, category);
doClusterTask(task);
}
public String getInitialSubdomain() {
ClusterTask task =
new ComponentSessionTask(address, RemoteSessionTask.Operation.getInitialSubdomain);
return (String) doSynchronousClusterTask(task);
}
public Collection<String> getSubdomains() {
ClusterTask task = new ComponentSessionTask(address, RemoteSessionTask.Operation.getSubdomains);
return (Collection<String>) doSynchronousClusterTask(task);
}
public String getName() {
ClusterTask task = new ComponentSessionTask(address, RemoteSessionTask.Operation.getName);
return (String) doSynchronousClusterTask(task);
}
public String getDescription() {
ClusterTask task = new ComponentSessionTask(address, RemoteSessionTask.Operation.getDescription);
return (String) doSynchronousClusterTask(task);
}
public void processPacket(Packet packet) {
RemoteSessionTask task = new ProcessComponentPacketTask(address, packet);
doClusterTask(task);
}
public void initialize(JID jid, ComponentManager componentManager) throws ComponentException {
RemoteSessionTask task = new InitializeTask(address, jid);
doClusterTask(task);
}
public void start() {
RemoteSessionTask task = new ComponentSessionTask(address, RemoteSessionTask.Operation.start);
doClusterTask(task);
}
public void shutdown() {
RemoteSessionTask task = new ComponentSessionTask(address, RemoteSessionTask.Operation.shutdown);
doClusterTask(task);
}
}
private static class SetterTask extends ComponentSessionTask {
private Type type;
private String value;
public SetterTask() {
super();
}
protected SetterTask(JID address, Type type, String value) {
super(address, null);
this.type = type;
this.value = value;
}
public void run() {
if (type == Type.name) {
((ComponentSession) getSession()).getExternalComponent().setName(value);
} else if (type == Type.type) {
((ComponentSession) getSession()).getExternalComponent().setType(value);
} else if (type == Type.catergory) {
((ComponentSession) getSession()).getExternalComponent().setCategory(value);
}
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeInt(out, type.ordinal());
ExternalizableUtil.getInstance().writeBoolean(out, value != null);
if (value != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, value);
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
type = Type.values()[ExternalizableUtil.getInstance().readInt(in)];
if (ExternalizableUtil.getInstance().readBoolean(in)) {
value = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
private static enum Type {
name,
type,
catergory
}
}
private static class ProcessComponentPacketTask extends ComponentSessionTask {
private Packet packet;
public ProcessComponentPacketTask() {
super();
}
protected ProcessComponentPacketTask(JID address, Packet packet) {
super(address, null);
this.packet = packet;
}
public void run() {
((ComponentSession) getSession()).getExternalComponent().processPacket(packet);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
if (packet instanceof IQ) {
ExternalizableUtil.getInstance().writeInt(out, 1);
} else if (packet instanceof Message) {
ExternalizableUtil.getInstance().writeInt(out, 2);
} else if (packet instanceof Presence) {
ExternalizableUtil.getInstance().writeInt(out, 3);
}
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) packet.getElement());
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
int packetType = ExternalizableUtil.getInstance().readInt(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
switch (packetType) {
case 1:
packet = new IQ(packetElement, true);
break;
case 2:
packet = new Message(packetElement, true);
break;
case 3:
packet = new Presence(packetElement, true);
break;
}
}
}
private static class InitializeTask extends ComponentSessionTask {
private JID componentJID;
public InitializeTask() {
super();
}
protected InitializeTask(JID address, JID componentJID) {
super(address, null);
this.componentJID = componentJID;
}
public void run() {
try {
((ComponentSession) getSession()).getExternalComponent()
.initialize(componentJID, InternalComponentManager.getInstance());
} catch (ComponentException e) {
Log.error("Error initializing component", e);
}
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, componentJID);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
componentJID = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.session.ConnectionMultiplexerSession;
import org.jivesoftware.util.cache.ClusterTask;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
/**
* Surrogate for connection manager sessions hosted in some remote cluster node.
*
* @author Gaston Dombiak
*/
public class RemoteConnectionMultiplexerSession extends RemoteSession implements ConnectionMultiplexerSession {
public RemoteConnectionMultiplexerSession(byte[] nodeID, JID address) {
super(nodeID, address);
}
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new ConnectionMultiplexerSessionTask(address, operation);
}
ClusterTask getDeliverRawTextTask(String text) {
return new DeliverRawTextTask(this, address, text);
}
ClusterTask getProcessPacketTask(Packet packet) {
return new ProcessPacketTask(this, address, packet);
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.session.IncomingServerSession;
import org.jivesoftware.util.cache.ClusterTask;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import java.util.Collection;
/**
* Surrogate for incoming server sessions hosted in some remote cluster node.
*
* @author Gaston Dombiak
*/
public class RemoteIncomingServerSession extends RemoteSession implements IncomingServerSession {
private String localDomain;
public RemoteIncomingServerSession(byte[] nodeID, StreamID streamID) {
super(nodeID, null);
this.streamID = streamID;
}
public JID getAddress() {
if (address == null) {
RemoteSessionTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getAddress);
address = (JID) doSynchronousClusterTask(task);
}
return address;
}
public Collection<String> getValidatedDomains() {
// 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
// proper clean up logic {@link ClusterListener#cleanupNode(NodeCacheKey)
return SessionManager.getInstance().getValidatedDomains(streamID);
}
public String getLocalDomain() {
if (localDomain == null) {
RemoteSessionTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getLocalDomain);
localDomain = (String) doSynchronousClusterTask(task);
}
return localDomain;
}
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new IncomingServerSessionTask(operation, streamID.getID());
}
ClusterTask getDeliverRawTextTask(String text) {
return new DeliverRawTextTask(streamID.getID(), text);
}
ClusterTask getProcessPacketTask(Packet packet) {
return new ProcessPacketTask(streamID.getID(), packet);
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.session.OutgoingServerSession;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collection;
/**
* Surrogate for outgoing server sessions hosted in some remote cluster node.
*
* @author Gaston Dombiak
*/
public class RemoteOutgoingServerSession extends RemoteSession implements OutgoingServerSession {
private long usingServerDialback = -1;
public RemoteOutgoingServerSession(byte[] nodeID, JID address) {
super(nodeID, address);
}
public Collection<String> getAuthenticatedDomains() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getAuthenticatedDomains);
return (Collection<String>) doSynchronousClusterTask(task);
}
public void addAuthenticatedDomain(String domain) {
doClusterTask(new AddAuthenticatedDomainTask(address, domain));
}
public Collection<String> getHostnames() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getHostnames);
return (Collection<String>) doSynchronousClusterTask(task);
}
public void addHostname(String hostname) {
doClusterTask(new AddHostnameTask(address, hostname));
}
public boolean authenticateSubdomain(String domain, String hostname) {
ClusterTask task = new AuthenticateSubdomainTask(address, domain, hostname);
return (Boolean) doSynchronousClusterTask(task);
}
public boolean isUsingServerDialback() {
if (usingServerDialback == -1) {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isUsingServerDialback);
usingServerDialback = (Boolean) doSynchronousClusterTask(task) ? 1 : 0;
}
return usingServerDialback == 1;
}
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new OutgoingServerSessionTask(address, operation);
}
ClusterTask getDeliverRawTextTask(String text) {
return new DeliverRawTextTask(this, address, text);
}
ClusterTask getProcessPacketTask(Packet packet) {
return new ProcessPacketTask(this, address, packet);
}
private static class AddAuthenticatedDomainTask extends OutgoingServerSessionTask {
private String domain;
public AddAuthenticatedDomainTask() {
super();
}
protected AddAuthenticatedDomainTask(JID address, String domain) {
super(address, null);
this.domain = domain;
}
public void run() {
((OutgoingServerSession) getSession()).addAuthenticatedDomain(domain);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF(out, domain);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
domain = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
private static class AddHostnameTask extends OutgoingServerSessionTask {
private String hostname;
public AddHostnameTask() {
super();
}
protected AddHostnameTask(JID address, String hostname) {
super(address, null);
this.hostname = hostname;
}
public void run() {
((OutgoingServerSession) getSession()).addHostname(hostname);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF(out, hostname);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
hostname = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
private static class AuthenticateSubdomainTask extends OutgoingServerSessionTask {
private String domain;
private String hostname;
public AuthenticateSubdomainTask() {
super();
}
protected AuthenticateSubdomainTask(JID address, String domain, String hostname) {
super(address, null);
this.domain = domain;
this.hostname = hostname;
}
public void run() {
result = ((OutgoingServerSession) getSession()).authenticateSubdomain(domain, hostname);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSafeUTF(out, domain);
ExternalizableUtil.getInstance().writeSafeUTF(out, hostname);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
domain = ExternalizableUtil.getInstance().readSafeUTF(in);
hostname = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.cache.CacheFactory;
import org.jivesoftware.util.cache.ClusterTask;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import java.net.UnknownHostException;
import java.util.Date;
/**
* Base class for sessions being hosted in other cluster nodes. Almost all
* messages will be forwarded to the actual session in some remote cluster node.
* Only some few messages will be local operations like getting the session's address
* or the session status. And only some operations will be cached locally for a brief
* period for content that is highly used and not frequently modified.
*
* @author Gaston Dombiak
*/
public abstract class RemoteSession implements Session {
protected byte[] nodeID;
protected JID address;
// Cache content that never changes
protected StreamID streamID;
private Date creationDate;
private String serverName;
private String hostAddress;
private String hostName;
public RemoteSession(byte[] nodeID, JID address) {
this.nodeID = nodeID;
this.address = address;
}
public JID getAddress() {
return address;
}
/**
* Remote sessions are always authenticated. Otherwise, they won't be visibile to other
* cluster nodes. When the session is closed it will no longer be visible to other nodes
* so {@link #STATUS_CLOSED} is never returned.
*
* @return the authenticated status.
*/
public int getStatus() {
return STATUS_AUTHENTICATED;
}
public StreamID getStreamID() {
// Get it once and cache it since it never changes
if (streamID == null) {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getStreamID);
streamID = (StreamID) doSynchronousClusterTask(task);
}
return streamID;
}
public String getServerName() {
if (serverName == null) {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getServerName);
serverName = (String) doSynchronousClusterTask(task);
}
return serverName;
}
public Date getCreationDate() {
// Get it once and cache it since it never changes
if (creationDate == null) {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getCreationDate);
creationDate = (Date) doSynchronousClusterTask(task);
}
return creationDate;
}
public Date getLastActiveDate() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getLastActiveDate);
return (Date) doSynchronousClusterTask(task);
}
public long getNumClientPackets() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getNumClientPackets);
return (Long) doSynchronousClusterTask(task);
}
public long getNumServerPackets() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getNumServerPackets);
return (Long) doSynchronousClusterTask(task);
}
public void process(Packet packet) {
doClusterTask(getProcessPacketTask(packet));
}
public void close() {
doSynchronousClusterTask(getRemoteSessionTask(RemoteSessionTask.Operation.close));
}
public boolean isClosed() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isClosed);
return (Boolean) doSynchronousClusterTask(task);
}
public boolean isSecure() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isSecure);
return (Boolean) doSynchronousClusterTask(task);
}
public String getHostAddress() throws UnknownHostException {
if (hostAddress == null) {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getHostAddress);
hostAddress = (String) doSynchronousClusterTask(task);
}
return hostAddress;
}
public String getHostName() throws UnknownHostException {
if (hostName == null) {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.getHostName);
hostName = (String) doSynchronousClusterTask(task);
}
return hostName;
}
public void deliverRawText(String text) {
doClusterTask(getDeliverRawTextTask(text));
}
public boolean validate() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.validate);
return (Boolean) doSynchronousClusterTask(task);
}
abstract RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation);
abstract ClusterTask getDeliverRawTextTask(String text);
abstract ClusterTask getProcessPacketTask(Packet packet);
/**
* Invokes a task on the remote cluster member synchronously and returns the result of
* the remote operation.
*
* @param task the ClusterTask object to be invoked on a given cluster member.
* @return result of remote operation.
* @throws IllegalStateException if requested node was not found or not running in a cluster.
*/
protected Object doSynchronousClusterTask(ClusterTask task) {
return CacheFactory.doSynchronousClusterTask(task, nodeID);
}
/**
* Invokes a task on the remote cluster member in an asynchronous fashion.
*
* @param task the task to be invoked on the specified cluster member.
* @throws IllegalStateException if requested node was not found or not running in a cluster.
*/
protected void doClusterTask(ClusterTask task) {
CacheFactory.doClusterTask(task, nodeID);
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.session.*;
import org.xmpp.packet.JID;
/**
* Locator of sessions that know how to talk to Coherence cluster nodes.
*
* @author Gaston Dombiak
*/
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)
public ClientSession getClientSession(byte[] nodeID, JID address) {
return new RemoteClientSession(nodeID, address);
}
public ComponentSession getComponentSession(byte[] nodeID, JID address) {
return new RemoteComponentSession(nodeID, address);
}
public ConnectionMultiplexerSession getConnectionMultiplexerSession(byte[] nodeID, JID address) {
return new RemoteConnectionMultiplexerSession(nodeID, address);
}
public IncomingServerSession getIncomingServerSession(byte[] nodeID, StreamID streamID) {
return new RemoteIncomingServerSession(nodeID, streamID);
}
public OutgoingServerSession getOutgoingServerSession(byte[] nodeID, JID address) {
return new RemoteOutgoingServerSession(nodeID, address);
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.openfire.session;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.TaskEngine;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.net.UnknownHostException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* Operations to be executed in a remote session hosted in a remote cluster node.
*
* @author Gaston Dombiak
*/
public abstract class RemoteSessionTask implements ClusterTask<Object> {
protected Object result;
protected Operation operation;
public RemoteSessionTask() {
}
protected RemoteSessionTask(Operation operation) {
this.operation = operation;
}
abstract Session getSession();
public Object getResult() {
return result;
}
public void run() {
if (operation == Operation.getStreamID) {
result = getSession().getStreamID();
}
else if (operation == Operation.getServerName) {
result = getSession().getServerName();
}
else if (operation == Operation.getCreationDate) {
result = getSession().getCreationDate();
}
else if (operation == Operation.getLastActiveDate) {
result = getSession().getLastActiveDate();
}
else if (operation == Operation.getNumClientPackets) {
result = getSession().getNumClientPackets();
}
else if (operation == Operation.getNumServerPackets) {
result = getSession().getNumServerPackets();
}
else if (operation == Operation.close) {
// Run in another thread so we avoid blocking calls (in coherence)
final Session session = getSession();
if (session != null) {
final Future<?> future = TaskEngine.getInstance().submit(new Runnable() {
public void run() {
session.close();
}
});
// Wait until the close operation is done or timeout is met
try {
future.get(15, TimeUnit.SECONDS);
}
catch (Exception e) {
// Ignore
}
}
}
else if (operation == Operation.isClosed) {
result = getSession().isClosed();
}
else if (operation == Operation.isSecure) {
result = getSession().isSecure();
}
else if (operation == Operation.getHostAddress) {
try {
result = getSession().getHostAddress();
} catch (UnknownHostException e) {
Log.error("Error getting address of session: " + getSession(), e);
}
}
else if (operation == Operation.getHostName) {
try {
result = getSession().getHostName();
} catch (UnknownHostException e) {
Log.error("Error getting address of session: " + getSession(), e);
}
}
else if (operation == Operation.validate) {
result = getSession().validate();
}
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeBoolean(out, operation != null);
if (operation != null) {
ExternalizableUtil.getInstance().writeInt(out, operation.ordinal());
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
if (ExternalizableUtil.getInstance().readBoolean(in)) {
operation = Operation.values()[ExternalizableUtil.getInstance().readInt(in)];
}
}
public enum Operation {
/**
* Basic session operations
*/
getStreamID,
getServerName,
getCreationDate,
getLastActiveDate,
getNumClientPackets,
getNumServerPackets,
close,
isClosed,
isSecure,
getHostAddress,
getHostName,
validate,
/**
* Operations of c2s sessions
*/
isInitialized,
incrementConflictCount,
/**
* Operations of outgoing server sessions
*/
getAuthenticatedDomains,
getHostnames,
isUsingServerDialback,
/**
* Operations of external component sessions
*/
getType,
getCategory,
getInitialSubdomain,
getSubdomains,
getName,
getDescription,
start,
shutdown,
/**
* Operations of incoming server sessions
*/
getLocalDomain,
getAddress
}
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.util.cache;
import com.tangosol.util.MapEvent;
import com.tangosol.util.MapListener;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.NodeID;
import java.util.Set;
/**
* 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
* {@link ClusterListener}. This information is then used when a node goes
* down to proper clean up can be done
*
* @author Pete Matern
* @author Gaston Dombiak
*/
abstract class CacheListener implements MapListener {
protected final String cacheName;
private ClusterListener clusterListener;
public CacheListener(ClusterListener clusterListener, String cacheName) {
this.clusterListener = clusterListener;
this.cacheName = cacheName;
}
public void entryInserted(MapEvent mapEvent) {
handleMapEvent(mapEvent, false);
}
public void entryUpdated(MapEvent mapEvent) {
handleMapEvent(mapEvent, false);
}
public void entryDeleted(MapEvent mapEvent) {
handleMapEvent(mapEvent, true);
}
void handleMapEvent(MapEvent mapEvent, boolean removal) {
NodeID nodeID = getNodeID(mapEvent, removal);
//ignore items which this node has added
if (!XMPPServer.getInstance().getNodeID().equals(nodeID)) {
Set<String> sessionJIDS = clusterListener.lookupJIDList(nodeID, cacheName);
if (removal) {
sessionJIDS.remove(mapEvent.getKey().toString());
}
else {
sessionJIDS.add(mapEvent.getKey().toString());
}
}
}
abstract NodeID getNodeID(MapEvent mapEvent, boolean removal);
}
/*
* Copyright (C) 2007-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.util.cache;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginClassLoader;
import org.jivesoftware.openfire.container.PluginManager;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
/**
* Class loader to be used by coherence to load classes that live in the enterprise plugin,
* the Openfire core and also classes defined in other plugins. With this new class loader
* plugins can now make use of coherence.<p>
*
* 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
* the cluster. Coherence will deserialize the class and will use the first class definition
* found in the list of plugins.<p>
*
* The sequence of search for this class loader is first check the enterprise plugin that
* includes checking the Openfire core. If not found then try with the other plugins.
*
* @author Gaston Dombiak
*/
public class ClusterClassLoader extends ClassLoader {
private PluginClassLoader enterpriseClassloader;
public ClusterClassLoader() {
super();
Plugin plugin = XMPPServer.getInstance().getPluginManager().getPlugin("clustering");
enterpriseClassloader = XMPPServer.getInstance().getPluginManager().getPluginClassloader(plugin);
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
return enterpriseClassloader.loadClass(name);
}
catch (ClassNotFoundException e) {
PluginManager pluginManager = XMPPServer.getInstance().getPluginManager();
for (Plugin plugin : pluginManager.getPlugins()) {
String pluginName = pluginManager.getPluginDirectory(plugin).getName();
if ("clustering".equals(pluginName) || "admin".equals(pluginName)) {
continue;
}
PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin);
try {
return pluginClassloader.loadClass(name);
}
catch (ClassNotFoundException e1) {
// Do nothing. Continue to the next plugin
}
}
}
throw new ClassNotFoundException(name);
}
public URL getResource(String name) {
URL resource = enterpriseClassloader.getResource(name);
if (resource == null) {
PluginManager pluginManager = XMPPServer.getInstance().getPluginManager();
for (Plugin plugin : pluginManager.getPlugins()) {
String pluginName = pluginManager.getPluginDirectory(plugin).getName();
if ("clustering".equals(pluginName) || "admin".equals(pluginName)) {
continue;
}
PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin);
resource = pluginClassloader.getResource(name);
if (resource != null) {
return resource;
}
}
}
return resource;
}
public Enumeration<URL> getResources(String name) throws IOException {
Enumeration<URL> answer = null;
try {
answer = enterpriseClassloader.getResources(name);
}
catch (IOException e) {
// Ignore
}
if (answer == null || !answer.hasMoreElements()) {
PluginManager pluginManager = XMPPServer.getInstance().getPluginManager();
for (Plugin plugin : pluginManager.getPlugins()) {
String pluginName = pluginManager.getPluginDirectory(plugin).getName();
if ("clustering".equals(pluginName) || "admin".equals(pluginName)) {
continue;
}
PluginClassLoader pluginClassloader = pluginManager.getPluginClassloader(plugin);
try {
answer = pluginClassloader.getResources(name);
}
catch (IOException e) {
// Ignore
}
if (answer != null && answer.hasMoreElements()) {
return answer;
}
}
}
return answer;
}
}
/*
* Copyright (C) 1999-2009 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.util.cache;
import com.tangosol.net.BackingMapManager;
import com.tangosol.net.DefaultConfigurableCacheFactory;
import com.tangosol.net.MemberListener;
import com.tangosol.net.NamedCache;
import com.tangosol.net.cache.NearCache;
import com.tangosol.net.cache.ReadWriteBackingMap;
import com.tangosol.util.*;
import org.jivesoftware.util.cache.Cache;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
/**
* Clustered implementation of the Cache interface using Tangosol's Coherence product.
*
*/
public class ClusteredCache implements Cache, QueryMap, InvocableMap {
/**
* The map is used for distributed operations such as get, put, etc.
*/
protected NamedCache map;
/**
* The cache is used as the backing store of the main distributed map and
* makes decisions about when to cull or expire cache entries.
*/
private Cache backingCache;
/**
* Create a new cache.
*
* @param name a name for the cache, which should be unique per vm.
*/
protected ClusteredCache(String name) {
NamedCache cache = com.tangosol.net.CacheFactory.getCache(name);
init(name, cache);
}
/**
* 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 cache the cache implementation
*/
protected ClusteredCache(String name, NamedCache cache) {
init(name, cache);
}
private void init(String name, NamedCache cache) {
map = cache;
BackingMapManager backingManager = cache.getCacheService().getBackingMapManager();
Map mapBacking = null;
if (backingManager instanceof DefaultConfigurableCacheFactory.Manager) {
DefaultConfigurableCacheFactory.Manager actualManager =
(DefaultConfigurableCacheFactory.Manager) backingManager;
int count = 0;
mapBacking = actualManager.getBackingMap(name);
//this ugly logic is necessary because the backing map instance seems to be made available asynchronously
//by the coherence api
while (mapBacking == null && count < 5) {
// Wait a full second
try {
Thread.sleep(1000);
}
catch (Exception e) { /*ignore*/ }
count++;
mapBacking = actualManager.getBackingMap(name);
}
if (mapBacking instanceof ReadWriteBackingMap) {
ReadWriteBackingMap readWriteMap = (ReadWriteBackingMap)mapBacking;
Map realBackingMap = readWriteMap.getInternalCache();
if (realBackingMap instanceof Cache) {
backingCache = (Cache)realBackingMap;
}
}
else if (mapBacking instanceof Cache) {
backingCache = (Cache)mapBacking;
}
}
if (backingCache == null) {
throw new IllegalStateException("Unable to access backing cache for " + name + ". BackingMapManager is a " +
backingManager.getClass().getName() + " and backing map is " +
((mapBacking != null) ? mapBacking.getClass().getName() : "null")
);
}
backingCache.setName(name);
}
public void addMemberListener(MemberListener listener) {
map.getCacheService().addMemberListener(listener);
}
public void removeMemberListener(MemberListener listener) {
map.getCacheService().removeMemberListener(listener);
}
public void addMapListener(MapListener mapListener, Filter filter, boolean fLite) {
map.addMapListener(mapListener, filter, fLite);
}
public void removeMapListener(MapListener mapListener, Filter filter) {
map.removeMapListener(mapListener, filter);
}
// Cache Interface
public String getName() {
return backingCache.getName();
}
public void setName(String name) {
backingCache.setName(name);
}
public Object put(Object key, Object object) {
return map.put(key, object);
}
public Object get(Object key) {
return map.get(key);
}
public Object remove(Object key) {
return map.remove(key);
}
public void clear() {
map.clear();
}
public int size() {
return backingCache.size();
}
public boolean containsKey(Object key) {
return map.containsKey(key);
}
public boolean containsValue(Object value) {
return map.containsValue(value);
}
public Set entrySet() {
return map.entrySet();
}
public boolean isEmpty() {
return map.isEmpty();
}
public Set keySet() {
return map.keySet();
}
public void putAll(Map entries) {
map.putAll(entries);
}
public Collection values() {
return map.values();
}
public long getCacheHits() {
if (map instanceof NearCache) {
return ((NearCache)map).getCacheStatistics().getCacheHits();
}
else if (backingCache != null) {
return backingCache.getCacheHits();
}
else {
return -1;
}
}
public long getCacheMisses() {
if (map instanceof NearCache) {
return ((NearCache)map).getCacheStatistics().getCacheMisses();
}
else if (backingCache != null) {
return backingCache.getCacheMisses();
}
else {
return -1;
}
}
public int getCacheSize() {
return backingCache.getCacheSize();
}
public long getMaxCacheSize() {
return backingCache.getMaxCacheSize();
}
public void setMaxCacheSize(int maxSize) {
backingCache.setMaxCacheSize(maxSize);
}
public long getMaxLifetime() {
return backingCache.getMaxLifetime();
}
public void setMaxLifetime(long maxLifetime) {
backingCache.setMaxLifetime(maxLifetime);
}
public void destroy() {
map.destroy();
}
public boolean lock(Object key, long timeout) {
return map.lock(key, timeout);
}
public boolean unlock(Object key) {
return map.unlock(key);
}
///////// InvocableMap methods //////////////////////////////////
public Object invoke(Object object, EntryProcessor entryProcessor) {
return map.invoke(object, entryProcessor);
}
public Map invokeAll(Collection collection, EntryProcessor entryProcessor) {
return map.invokeAll(collection, entryProcessor);
}
public Map invokeAll(Filter filter, EntryProcessor entryProcessor) {
return map.invokeAll(filter, entryProcessor);
}
public Object aggregate(Collection collection, EntryAggregator entryAggregator) {
return map.aggregate(collection, entryAggregator);
}
public Object aggregate(Filter filter, EntryAggregator entryAggregator) {
return map.aggregate(filter, entryAggregator);
}
////////////// QueryMap methods /////////////////////////
public Set keySet(Filter filter) {
return map.keySet(filter);
}
public Set entrySet(Filter filter) {
return map.entrySet(filter);
}
public Set entrySet(Filter filter, Comparator comparator) {
return map.entrySet(filter, comparator);
}
public void addIndex(ValueExtractor valueExtractor, boolean sorted, Comparator comparator) {
map.addIndex(valueExtractor, sorted, comparator);
}
public void removeIndex(ValueExtractor valueExtractor) {
map.removeIndex(valueExtractor);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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