/*
* 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 org.jivesoftware.openfire.plugin.session;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.privacy.PrivacyList;
import org.jivesoftware.openfire.privacy.PrivacyListManager;
import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.ClientSessionInfo;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.ClusterTask;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Surrogate for client sessions hosted in some remote cluster node.
*
* @author Gaston Dombiak
*/
public class RemoteClientSession extends RemoteSession implements ClientSession {
private long initialized = -1;
private boolean messageCarbonsEnabled;
public RemoteClientSession(byte[] nodeID, JID address) {
super(nodeID, address);
}
public PrivacyList getActiveList() {
Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
ClientSessionInfo sessionInfo = cache.get(getAddress().toString());
if (sessionInfo != null && sessionInfo.getActiveList() != null) {
return PrivacyListManager.getInstance().getPrivacyList(address.getNode(), sessionInfo.getActiveList());
}
return null;
}
public void setActiveList(PrivacyList activeList) {
// Highly unlikely that a list is change to a remote session but still possible
doClusterTask(new SetPrivacyListTask(address, true, activeList));
}
public PrivacyList getDefaultList() {
Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
ClientSessionInfo sessionInfo = cache.get(getAddress().toString());
if (sessionInfo != null && sessionInfo.getDefaultList() != null) {
return PrivacyListManager.getInstance().getPrivacyList(address.getNode(), sessionInfo.getDefaultList());
}
return null;
}
public void setDefaultList(PrivacyList defaultList) {
// Highly unlikely that a list is change to a remote session but still possible
doClusterTask(new SetPrivacyListTask(address, false, defaultList));
}
public String getUsername() throws UserNotFoundException {
return address.getNode();
}
public boolean isAnonymousUser() {
return SessionManager.getInstance().isAnonymousRoute(getAddress());
}
public boolean isInitialized() {
if (initialized == -1) {
Presence presence = getPresence();
if (presence != null && presence.isAvailable()) {
// Optimization to avoid making a remote call
initialized = 1;
}
else {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.isInitialized);
Object result = doSynchronousClusterTask(task);
initialized = result != null && (Boolean) result ? 1 : 0;
}
}
return initialized == 1;
}
public void setInitialized(boolean isInit) {
doClusterTask(new SetInitializedTask(address, isInit));
}
public boolean canFloodOfflineMessages() {
// Code copied from LocalClientSession to avoid remote calls
if(isOfflineFloodStopped()) {
return false;
}
String username = getAddress().getNode();
for (ClientSession session : SessionManager.getInstance().getSessions(username)) {
if (session.isOfflineFloodStopped()) {
return false;
}
}
return true;
}
public boolean isOfflineFloodStopped() {
Cache<String, ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
ClientSessionInfo sessionInfo = cache.get(getAddress().toString());
return sessionInfo != null && sessionInfo.isOfflineFloodStopped();
}
public Presence getPresence() {
Cache<String,ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
ClientSessionInfo sessionInfo = cache.get(getAddress().toString());
if (sessionInfo != null) {
return sessionInfo.getPresence();
}
// this can happen if a cluster node becomes unreachable
return new Presence(Presence.Type.unavailable);
}
public void setPresence(Presence presence) {
try {
doClusterTask(new SetPresenceTask(address, presence));
} catch (IllegalStateException e) {
// Remote node is down
if (presence.getType() == Presence.Type.unavailable) {
// Ignore unavailable presence (since session is already unavailable - at least to us)
return;
}
throw e;
}
}
public int incrementConflictCount() {
ClusterTask task = getRemoteSessionTask(RemoteSessionTask.Operation.incrementConflictCount);
Object result = doSynchronousClusterTask(task);
return result == null ? 0 : (Integer) result;
}
@Override
public boolean isMessageCarbonsEnabled() {
return messageCarbonsEnabled;
}
@Override
public void setMessageCarbonsEnabled(boolean enabled) {
this.messageCarbonsEnabled = enabled;
}
RemoteSessionTask getRemoteSessionTask(RemoteSessionTask.Operation operation) {
return new ClientSessionTask(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 SetPresenceTask extends ClientSessionTask {
private Presence presence;
public SetPresenceTask() {
super();
}
protected SetPresenceTask(JID address, Presence presence) {
super(address, null);
this.presence = presence;
}
public void run() {
((ClientSession)getSession()).setPresence(presence);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
presence = new Presence(packetElement, true);
}
}
private static class SetPrivacyListTask extends ClientSessionTask {
private boolean activeList;
private String listName;
public SetPrivacyListTask() {
super();
}
protected SetPrivacyListTask(JID address, boolean activeList, PrivacyList list) {
super(address, null);
this.activeList = activeList;
this.listName = list != null ? list.getName() : null;
}
public void run() {
ClientSession session = ((ClientSession) getSession());
PrivacyList list = null;
// Get the privacy list to set
if (listName != null) {
try {
String username = session.getUsername();
list = PrivacyListManager.getInstance().getPrivacyList(username, listName);
} catch (UserNotFoundException e) {
// Should never happen
}
}
// Set the privacy list to the session
if (activeList) {
session.setActiveList(list);
}
else {
session.setDefaultList(list);
}
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeBoolean(out, activeList);
ExternalizableUtil.getInstance().writeBoolean(out, listName != null);
if (listName != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, listName);
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
activeList = ExternalizableUtil.getInstance().readBoolean(in);
if (ExternalizableUtil.getInstance().readBoolean(in)) {
listName = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
}
private static class SetInitializedTask extends ClientSessionTask {
private boolean initialized;
public SetInitializedTask() {
super();
}
protected SetInitializedTask(JID address, boolean initialized) {
super(address, null);
this.initialized = initialized;
}
public void run() {
((ClientSession) getSession()).setInitialized(initialized);
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
ExternalizableUtil.getInstance().writeBoolean(out, initialized);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
super.readExternal(in);
initialized = ExternalizableUtil.getInstance().readBoolean(in);
}
}
}