/*
* 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.util;
import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ManagedObject;
import com.sun.sgs.app.ManagedReference;
import com.sun.sgs.impl.sharedutil.Objects;
import java.io.Serializable;
/**
* A wrapper for an object that is serializable, but may or may not be
* a {@link ManagedObject}. An instance of this serializable wrapper
* contains a managed reference to the {@code object} specified during
* construction as follows:
* <p> <ul>
*
* <li>If the {@code object} implements {@code ManagedObject}, the
* {@code WrappedSerializable} instance contains a {@link
* ManagedReference} directly to that object. </li>
* <li> Otherwise, if the {@code object} implements {@link
* Serializable} but does not implement {@code ManagedObject}, the
* {@code WrappedSerializable} instance wraps the {@code object} in a
* {@code ManagedObject} and contains a reference to the
* wrapper. </li>
* </ul>
* <p>
* When an instance of {@code WrappedSerializable} is no longer in
* use, the {@link #remove remove} method should be invoked on the
* instance so that if a wrapper was created for the {@code object},
* the wrapper can be removed.
*
* @param <T> type of object wrapped
*/
public final class WrappedSerializable<T> implements Serializable {
/** The serialVersionUID for this class. */
private static final long serialVersionUID = 1L;
/** The managed reference for the object or wrapper.
*/
private ManagedReference<?> ref = null;
/**
* Constructs an instance of this class with the specified object.
* The specified object must implement {@link Serializable} and may
* or may not be a {@link ManagedObject}.
*
* @param object an object
*
* @throws IllegalArgumentException if the specified object does not
* implement <code>Serializable</code>
*/
public WrappedSerializable(T object) {
if (object == null) {
throw new NullPointerException("obj is null");
} else if (!(object instanceof Serializable)) {
throw new IllegalArgumentException("obj not serializable");
}
ManagedObject managedObj =
(object instanceof ManagedObject) ?
(ManagedObject) object :
new Wrapper<T>(object);
ref = AppContext.getDataManager().createReference(managedObj);
}
/**
* Returns the object in this wrapper.
*
* @return T the object in this wrapper
*
* @throws IllegalStateException if {@link #remove remove} has
* been invoked on this instance
*/
public T get() {
checkRemoved();
ManagedObject obj = (ManagedObject) ref.get();
if (obj instanceof Wrapper) {
Wrapper<T> wrapper = Objects.uncheckedCast(obj);
return wrapper.get();
} else {
@SuppressWarnings("unchecked")
T result = (T) obj;
return result;
}
}
/**
* Marks this instance as removed, and if this instance contains a
* {@link ManagedObject} wrapper to the {@code object} specified
* during construction, then removes the wrapper as well.
*
* @throws IllegalStateException if {@link #remove remove} has
* been invoked on this instance
*/
public void remove() {
checkRemoved();
Object obj = ref.get();
if (obj instanceof Wrapper) {
AppContext.getDataManager().removeObject(obj);
}
ref = null;
}
/**
* Throws {@code IllegalStateException} if {@code remove} has
* already been invoked.
*/
private void checkRemoved() {
if (ref == null) {
throw new IllegalStateException("remove already invoked");
}
}
/**
* Managed object wrapper for a serializable object.
*/
private static class Wrapper<T> implements ManagedObject, Serializable {
private static final long serialVersionUID = 1L;
private final T obj;
Wrapper(T obj) {
this.obj = obj;
}
T get() {
return obj;
}
}
}