package com.voxeo.moho.sip;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import javax.media.mscontrol.MediaObject;
import javax.media.mscontrol.MediaSession;
import javax.media.mscontrol.join.Joinable.Direction;
import javax.media.mscontrol.networkconnection.NetworkConnection;
import org.apache.log4j.Logger;
import com.voxeo.moho.ApplicationContext;
import com.voxeo.moho.ApplicationContextImpl;
import com.voxeo.moho.Endpoint;
import com.voxeo.moho.Joint;
import com.voxeo.moho.Participant;
import com.voxeo.moho.ParticipantContainer;
import com.voxeo.moho.SettableJointImpl;
import com.voxeo.moho.Unjoint;
import com.voxeo.moho.UnjointImpl;
import com.voxeo.moho.common.event.MohoUnjoinCompleteEvent;
import com.voxeo.moho.event.Event;
import com.voxeo.moho.event.EventSource;
import com.voxeo.moho.event.JoinCompleteEvent;
import com.voxeo.moho.event.Observer;
import com.voxeo.moho.event.UnjoinCompleteEvent;
import com.voxeo.moho.remote.RemoteEndpointImpl;
import com.voxeo.moho.remote.sipbased.RemoteJoinIncomingCall;
import com.voxeo.moho.remote.sipbased.RemoteJoinOutgoingCall;
import com.voxeo.moho.remotejoin.RemoteParticipant;
public class RemoteParticipantImpl implements RemoteParticipant, ParticipantContainer {
private static final Logger LOG = Logger.getLogger(RemoteParticipantImpl.class);
protected String _id;
protected ApplicationContextImpl _appContext;
protected MediaSession _mediaSession;
protected NetworkConnection _network;
protected JoinDelegate _joinDelegate;
protected boolean _operationInProcess;
protected boolean _remoteInitiateJoin;
protected boolean _remoteInitiateUnjoin;
protected Participant _joiningParticipant;
public RemoteParticipantImpl(final ApplicationContextImpl appContext, final String id) {
super();
_id = id;
_appContext = appContext;
}
@Override
public String getApplicationState() {
throw new UnsupportedOperationException();
}
@Override
public String getApplicationState(String FSM) {
throw new UnsupportedOperationException();
}
@Override
public void setApplicationState(String state) {
throw new UnsupportedOperationException();
}
@Override
public void setApplicationState(String FSM, String state) {
throw new UnsupportedOperationException();
}
@Override
public ApplicationContext getApplicationContext() {
return _appContext;
}
@Override
public void addObserver(Observer... observers) {
throw new UnsupportedOperationException();
}
@Override
public void removeObserver(Observer listener) {
throw new UnsupportedOperationException();
}
@Override
public <S extends EventSource, T extends Event<S>> Future<T> dispatch(T event) {
throw new UnsupportedOperationException();
}
@Override
public <S extends EventSource, T extends Event<S>> Future<T> dispatch(T event, Runnable afterExec) {
throw new UnsupportedOperationException();
}
@Override
public String getId() {
return _id;
}
@Override
public <T> T getAttribute(String name) {
throw new UnsupportedOperationException();
}
@Override
public void setAttribute(String name, Object value) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, Object> getAttributeMap() {
throw new UnsupportedOperationException();
}
@Override
public Endpoint getAddress() {
return new RemoteEndpointImpl(_appContext, _id);
}
@Override
public Joint join(Participant other, JoinType type, Direction direction) {
return this.join(other, type, false, direction);
}
@Override
public Joint join(Participant other, JoinType type, boolean force, Direction direction) {
return this.join(other, type, force, direction, true);
}
@Override
public Joint join(Participant other, JoinType type, boolean force, Direction direction, boolean dtmfPassThough) {
JoinDelegate joinDelegate = null;
if (type != JoinType.DIRECT) {
joinDelegate = new LocalRemoteJoinDelegate(other, this, direction);
}
else {
joinDelegate = new DirectLocalRemoteJoinDelegate((SIPCallImpl) other, this, direction);
}
SettableJointImpl joint = new SettableJointImpl();
joinDelegate.setSettableJoint(joint);
try {
joinDelegate.doJoin();
}
catch (Exception e) {
// TODO
throw new RuntimeException(e);
}
return joint;
}
@Override
public Participant[] getParticipants() {
throw new UnsupportedOperationException();
}
@Override
public Participant[] getParticipants(Direction direction) {
throw new UnsupportedOperationException();
}
@Override
public void disconnect() {
if (_network != null) {
try {
_network.release();
}
catch (final Throwable t) {
LOG.warn("Exception when releasing networkconnection", t);
}
_network = null;
}
if (_mediaSession != null) {
try {
_mediaSession.release();
}
catch (final Throwable t) {
LOG.warn("Exception when releasing media object", t);
}
_mediaSession = null;
}
}
@Override
public MediaObject getMediaObject() {
return _network;
}
@Override
public String getRemoteAddress() {
return _id;
}
public MediaSession getMediaSession() {
return _mediaSession;
}
public void setMediaSession(MediaSession mediaSession) {
this._mediaSession = mediaSession;
}
public NetworkConnection getNetworkConnection() {
return _network;
}
public void setNetworkConnection(NetworkConnection network) {
this._network = network;
}
public synchronized void startJoin(final Participant participant, final JoinDelegate delegate) {
if (_joinDelegate != null) {
throw new IllegalStateException("other join operation in process.");
}
_operationInProcess = true;
_joinDelegate = delegate;
_joiningParticipant = participant;
}
@Override
public void joinDone(Participant participant, JoinDelegate delegate) {
_operationInProcess = false;
_joinDelegate = null;
_joiningParticipant = null;
}
@Override
public JoinDelegate getJoinDelegate(String participantID) {
return _joinDelegate;
}
public synchronized void joinDone(boolean notifyRemote) {
try {
JoinCompleteEvent.Cause cause = _joinDelegate.getCause();
Exception exception = _joinDelegate.getException();
if (notifyRemote) {
_appContext.getRemoteCommunication().joinDone(_joiningParticipant.getRemoteAddress(), this.getId(), cause,
exception);
}
}
finally {
_joinDelegate = null;
_operationInProcess = false;
_remoteInitiateJoin = false;
}
}
public Unjoint unjoin(final Participant other) {
Unjoint task = new UnjointImpl(_appContext.getExecutor(), new Callable<UnjoinCompleteEvent>() {
@Override
public UnjoinCompleteEvent call() throws Exception {
return doUnjoin(other, true);
}
});
return task;
}
public MohoUnjoinCompleteEvent doUnjoin(final Participant other, final boolean callPeerUnjoin) throws Exception {
MohoUnjoinCompleteEvent event = null;
try {
disconnect();
if (!_remoteInitiateUnjoin) {
_appContext.getRemoteCommunication().unjoin(other.getRemoteAddress(), this.getId());
}
if (callPeerUnjoin) {
((ParticipantContainer) other).doUnjoin(this, false);
}
}
catch (final Exception e) {
LOG.error("", e);
event = new MohoUnjoinCompleteEvent(this, other, UnjoinCompleteEvent.Cause.FAIL_UNJOIN, e, callPeerUnjoin);
throw e;
}
finally {
if (event == null) {
event = new MohoUnjoinCompleteEvent(this, other, UnjoinCompleteEvent.Cause.FAIL_UNJOIN, callPeerUnjoin);
}
_remoteInitiateUnjoin = false;
}
return event;
}
@Override
public void addParticipant(Participant p, JoinType type, Direction direction, Participant realJoined) {
// TODO Auto-generated method stub
}
public void setRemoteInitiateUnjoin(boolean remoteInitiateUnjoin) {
this._remoteInitiateUnjoin = remoteInitiateUnjoin;
}
public void setRemoteInitiateJoin(boolean remoteInitiateJoin) {
this._remoteInitiateJoin = remoteInitiateJoin;
}
@Override
public Direction getDirection(Participant participant) {
// TODO Auto-generated method stub
return null;
}
@Override
public byte[] getJoinSDP() {
throw new UnsupportedOperationException();
}
@Override
public void processSDPAnswer(byte[] sdp) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public byte[] processSDPOffer(byte[] sdp) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public JoinType getJoinType(Participant participant) {
throw new UnsupportedOperationException();
}
@Override
public Unjoint unjoin(final Participant other, final boolean callPeerUnjoin) throws Exception {
Unjoint task = new UnjointImpl(_appContext.getExecutor(), new Callable<UnjoinCompleteEvent>() {
@Override
public UnjoinCompleteEvent call() throws Exception {
return doUnjoin(other, callPeerUnjoin);
}
});
return task;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_id == null) ? 0 : _id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass() && !(obj instanceof RemoteParticipant))
return false;
if (obj instanceof RemoteJoinOutgoingCall) {
RemoteJoinOutgoingCall other = (RemoteJoinOutgoingCall) obj;
if (other.getJoinee().getUser().equalsIgnoreCase(_id)) {
return true;
}
else {
return false;
}
}
else if (obj instanceof RemoteJoinIncomingCall) {
RemoteJoinIncomingCall other = (RemoteJoinIncomingCall) obj;
if (other.getJoiner().getUser().equalsIgnoreCase(_id)) {
return true;
}
else {
return false;
}
}
else {
RemoteParticipantImpl other = (RemoteParticipantImpl) obj;
if (_id == null) {
if (other._id != null)
return false;
}
else if (!_id.equals(other._id))
return false;
return true;
}
}
@Override
public String getRemoteParticipantID() {
return _id;
}
@Override
public String toString() {
return "RemoteParticipantImpl [_id=" + _id + "]";
}
}