/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*/
package com.sun.sgs.impl.service.channel;
import com.sun.sgs.app.Channel;
import com.sun.sgs.app.ClientSession;
import com.sun.sgs.app.Delivery;
import com.sun.sgs.app.ManagedObjectRemoval;
import com.sun.sgs.app.ManagedReference;
import com.sun.sgs.app.ObjectNotFoundException;
import java.io.Serializable;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Set;
/**
* A wrapper for a {@code ChannelImpl} object that is returned to the
* application when a channel is created. A {@code ChannelWrapper} is
* handed back to the application instead of a direct reference to a
* {@code ChannelImpl} instance to avoid the possibility of the application
* removing the {@code ChannelImpl} instance from the data service and
* interfering with the channel service's persistent data.
*
* <p>When a {@code ChannelWrapper} instance is removed from the data
* service, the underlying channel is closed.
*/
class ChannelWrapper
implements Channel, Serializable, ManagedObjectRemoval
{
/** The serialVersionUID for this class. */
private static final long serialVersionUID = 1L;
/** The reference to the channel that this instance wraps. */
private ManagedReference<ChannelImpl> channelRef;
/**
* Constructs an instance with the specified {@code channelRef}.
*
* @param channelRef a reference to a channel to wrap
*/
ChannelWrapper(ManagedReference<ChannelImpl> channelRef) {
this.channelRef = channelRef;
}
/* -- Implement Channel -- */
/** {@inheritDoc} */
public String getName() {
return getChannel().getName();
}
/** {@inheritDoc} */
public Delivery getDelivery() {
return getChannel().getDelivery();
}
/** {@inheritDoc} */
public boolean hasSessions() {
return getChannel().hasSessions();
}
/** {@inheritDoc} */
public Iterator<ClientSession> getSessions() {
return getChannel().getSessions();
}
/** {@inheritDoc} */
public Channel join(final ClientSession session) {
getChannel().join(session);
return this;
}
/** {@inheritDoc} */
public Channel join(final Set<? extends ClientSession> sessions) {
getChannel().join(sessions);
return this;
}
/** {@inheritDoc} */
public Channel leave(final ClientSession session) {
getChannel().leave(session);
return this;
}
/** {@inheritDoc} */
public Channel leave(final Set<? extends ClientSession> sessions) {
getChannel().leave(sessions);
return this;
}
/** {@inheritDoc} */
public Channel leaveAll() {
getChannel().leaveAll();
return this;
}
/** {@inheritDoc} */
public Channel send(ByteBuffer message) {
getChannel().send(null, message);
return this;
}
/** {@inheritDoc} */
public Channel send(ClientSession sender, ByteBuffer message) {
getChannel().send(sender, message);
return this;
}
/* -- Implement ManagedObjectRemoval -- */
/** {@inheritDoc}
*
* The application removed the wrapper, so close the channel,
* indicating that the the channel name mapping should be removed as
* well.
*/
public void removingObject() {
if (channelRef != null) {
try {
channelRef.get().close(true);
} catch (ObjectNotFoundException e) {
// already closed.
}
channelRef = null;
}
}
/* -- Public methods -- */
/**
* Returns this channel's ID as a {@code BigInteger}.
*
* @return this channel's ID as a {@code BigInteger}
*/
public BigInteger getChannelId() {
return channelRef.getId();
}
/* -- Implement Object -- */
/** {@inheritDoc} */
@Override
public boolean equals(Object object) {
if (object == this) {
return true;
} else if (object instanceof ChannelWrapper) {
return channelRef.equals(((ChannelWrapper) object).channelRef);
} else {
return false;
}
}
/** {@inheritDoc} */
@Override
public int hashCode() {
return channelRef.hashCode();
}
/** {@inheritDoc} */
@Override
public String toString() {
ChannelImpl channelImpl = null;
try {
channelImpl = channelRef.get();
} catch (Exception e) {
}
return getClass().getName() + "[" +
(channelImpl == null ?
channelRef.toString() :
channelImpl.toString()) +
"]";
}
/* -- Other methods -- */
/**
* Set the channel reference for this wrapper to the specified {@code
* channelRef}. The underlying channel reference changes when the
* application invokes {@code leaveAll} on the channel, which closes
* and removes the old channel (except for the channel's name binding)
* and reuses the existing wrapper, replacing the previous channel
* reference with a reference to the "next generation" channel of the
* same name.
*
* @param channelRef the new channel reference
*/
void setChannelRef(ManagedReference<ChannelImpl> channelRef) {
ChannelServiceImpl.getInstance().getDataService().markForUpdate(this);
this.channelRef = channelRef;
}
/**
* Returns the underlying {@code ChannelImpl} instance for this
* wrapper. If the underlying channel has been removed, then the
* channel has been closed, so {@code IllegalStateException} is thrown.
*/
private ChannelImpl getChannel() {
if (channelRef != null) {
try {
return channelRef.get();
} catch (ObjectNotFoundException e) {
}
}
throw new IllegalStateException("channel is closed");
}
}