/*
* 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);
}
}
}