/*
* Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved.
*
* The Sun Project JXTA(TM) Software License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by Sun Microsystems, Inc. for JXTA(TM) technology."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
* not be used to endorse or promote products derived from this software
* without prior written permission. For written permission, please contact
* Project JXTA at http://www.jxta.org.
*
* 5. Products derived from this software may not be called "JXTA", nor may
* "JXTA" appear in their name, without prior written permission of Sun.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
* MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JXTA is a registered trademark of Sun Microsystems, Inc. in the United
* States and other countries.
*
* Please see the license information page at :
* <http://www.jxta.org/project/www/license.html> for instructions on use of
* the license in source files.
*
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of Project JXTA. For more information on Project JXTA, please see
* http://www.jxta.org.
*
* This license is based on the BSD license adopted by the Apache Foundation.
*/
package net.jxta.impl.peergroup;
import net.jxta.access.AccessService;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.Advertisement;
import net.jxta.document.Element;
import net.jxta.endpoint.EndpointService;
import net.jxta.exception.PeerGroupException;
import net.jxta.exception.ProtocolNotSupportedException;
import net.jxta.exception.ServiceNotFoundException;
import net.jxta.id.ID;
import net.jxta.logging.Logging;
import net.jxta.membership.MembershipService;
import net.jxta.peer.PeerID;
import net.jxta.peer.PeerInfoService;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.pipe.PipeService;
import net.jxta.platform.JxtaLoader;
import net.jxta.platform.Module;
import net.jxta.platform.ModuleSpecID;
import net.jxta.protocol.ConfigParams;
import net.jxta.protocol.ModuleImplAdvertisement;
import net.jxta.protocol.PeerAdvertisement;
import net.jxta.protocol.PeerGroupAdvertisement;
import net.jxta.rendezvous.RendezVousService;
import net.jxta.resolver.ResolverService;
import net.jxta.service.Service;
import java.io.IOException;
import java.net.URI;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.jxta.content.ContentService;
/**
* Provides a pure interface object that permits interaction with the actual
* PeerGroup implementation without giving access to the real object.
* <p/>
* This class defines immutable objects. It has no control over the wrapped peer
* group object's life cycle. It provides a weak PeerGroup interface object.
*/
class PeerGroupInterface implements PeerGroup {
/**
* Logger
*/
private final static transient Logger LOG = Logger.getLogger(PeerGroupInterface.class.getName());
/**
* Ever increasing count of peer group interfaces to assist tracking.
*/
private final static AtomicInteger interfaceInstanceCount = new AtomicInteger(0);
/**
* Tracks the requestor of this interface object.
*/
protected final Throwable requestor;
/**
* The instance count of this interface object for tracking purposes.
*/
protected final int instance;
/**
* If {@code true} then {@link #unref()} has been called.
*/
protected final AtomicBoolean unrefed = new AtomicBoolean(false);
/**
* The peer group instance which backs this interface object.
*/
protected PeerGroup groupImpl;
/**
* Constructs an interface object that front-ends the provided Peer Group.
*
* @param theRealThing the real PeerGroup
*/
PeerGroupInterface(PeerGroup theRealThing) {
groupImpl = theRealThing;
requestor = new Throwable("Requestor Stack Trace : " + theRealThing.getPeerGroupID());
instance = interfaceInstanceCount.incrementAndGet();
if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) {
LOG.log(Level.INFO, "Peer Group Interface Constructed {" + instance + "}", requestor);
} else if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
LOG.log(Level.INFO, "Peer Group Interface Constructed {" + instance + "}");
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object target) {
PeerGroup temp = groupImpl;
if (null != temp) {
return temp.equals(target);
} else {
return super.equals(target);
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
PeerGroup temp = groupImpl;
if (null != temp) {
return temp.hashCode();
} else {
return super.hashCode();
}
}
/**
* {@inheritDoc}
* <p/>
* An implementation suitable for debugging. <b>Do not parse this
* string!</b> All of the information is available from other sources.
*/
@Override
public String toString() {
PeerGroup temp = groupImpl;
if (null != temp) {
return temp.toString();
} else {
return super.toString() + "{" + instance + "}";
}
}
/**
* {@inheritDoc}
* <p/>
* This is here for class hierarchy reasons. It is normally ignored. By
* definition, the interface object protects the real object's start/stop
* methods from being called.
*/
public void init(PeerGroup pg, ID assignedID, Advertisement impl) {
}
/**
* {@inheritDoc}
* <p/>
* This is here for class hierarchy reasons. It is normally ignored. By
* definition, the interface object protects the real object's start/stop
* methods from being called.
*/
public int startApp(String[] args) {
return Module.START_OK;
}
/**
* {@inheritDoc}
* <p/>
* Applications assume that they have exclusive access to the peer group
* object. They call {@code stopApp()} to signify that they are finished
* with the peer group. Since peer groups are shared, we use
* {@code stopApp()} to {@link #unref()}.
* <p/>
* We could also just do nothing and let this interface be GCed but calling
* {@link #unref()} makes the group go away immediately if it is not shared,
* which is what applications calling stopApp() expect.
*/
public void stopApp() {
unref();
}
/**
* {@inheritDoc}
*/
public PeerGroup getInterface() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return this;
}
/**
* {@inheritDoc}
* <p/>
* This is already a weak reference (non-counted) to the peer group so we
* can just return ourself.
*/
public PeerGroup getWeakInterface() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return this;
}
/**
* {@inheritDoc}
*/
public boolean unref() {
boolean unref = unrefed.compareAndSet(false, true);
if (unref) {
if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) {
Throwable unrefer = new Throwable("Unrefer Stack Trace", requestor);
LOG.log(Level.FINER, "Peer Group Interface Unreference {" + instance + "}", unrefer);
} else if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
LOG.log(Level.INFO, "Peer Group Interface Unreference {" + instance + "}");
}
groupImpl = null;
} else {
if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
Throwable unrefer = new Throwable("Unrefer Stack Trace", requestor);
LOG.log(Level.WARNING, "Duplicate dereference of Peer Group Interface {" + instance + "}", unrefer);
}
}
return unref;
}
/**
* {@inheritDoc}
*/
public Advertisement getImplAdvertisement() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getImplAdvertisement();
}
/**
* {@inheritDoc}
*/
public ThreadGroup getHomeThreadGroup() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getHomeThreadGroup();
}
/**
* {@inheritDoc}
*/
public URI getStoreHome() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getStoreHome();
}
/**
* {@inheritDoc}
*/
public JxtaLoader getLoader() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getLoader();
}
/**
* {@inheritDoc}
*/
public boolean isRendezvous() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.isRendezvous();
}
/**
* {@inheritDoc}
*/
public PeerGroupAdvertisement getPeerGroupAdvertisement() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getPeerGroupAdvertisement();
}
/**
* {@inheritDoc}
*/
public PeerAdvertisement getPeerAdvertisement() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getPeerAdvertisement();
}
/**
* {@inheritDoc}
*/
public Service lookupService(ID name) throws ServiceNotFoundException {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.lookupService(name);
}
/**
* {@inheritDoc}
*/
public Service lookupService(ID name, int roleIndex) throws ServiceNotFoundException {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.lookupService(name, roleIndex);
}
/**
* {@inheritDoc}
*/
public Iterator<ID> getRoleMap(ID name) {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getRoleMap(name);
}
/**
* {@inheritDoc}
*/
public boolean compatible(Element compat) {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.compatible(compat);
}
/**
* {@inheritDoc}
* <p/>
* FIXME 20031103 jice Ideally, we'd need the groupAPI to offer a means to
* loadModule() without making a counted reference, so that group services
* can loadModule() things without preventing group termination. This could
* be achieved elegantly by making this the only behaviour available through
* a weak GroupInterface. So it would be enough to obtain a weak interface
* from one's group and then use its loadmodule method rather than that of
* the strong group reference. However, that's a bit too big a change to be
* decided without more careful consideration.
*/
public Module loadModule(ID assignedID, Advertisement impl) throws ProtocolNotSupportedException, PeerGroupException {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.loadModule(assignedID, impl);
}
/**
* {@inheritDoc}
*/
public Module loadModule(ID assignedID, ModuleSpecID specID, int where) {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.loadModule(assignedID, specID, where);
}
/**
* {@inheritDoc}
*/
public void publishGroup(String name, String description) throws IOException {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
temp.publishGroup(name, description);
}
/*
* Valuable application helpers: Various methods to instantiate groups.
*/
/**
* {@inheritDoc}
*/
public PeerGroup newGroup(Advertisement pgAdv) throws PeerGroupException {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.newGroup(pgAdv);
}
/**
* {@inheritDoc}
*/
public PeerGroup newGroup(PeerGroupID gid, Advertisement impl, String name, String description) throws PeerGroupException {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.newGroup(gid, impl, name, description);
}
/**
* {@inheritDoc}
*/
public PeerGroup newGroup(PeerGroupID gid) throws PeerGroupException {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.newGroup(gid);
}
/*
* shortcuts to the well-known services, in order to avoid calls to lookup.
*/
/**
* {@inheritDoc}
*/
public RendezVousService getRendezVousService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getRendezVousService();
}
/**
* {@inheritDoc}
*/
public EndpointService getEndpointService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getEndpointService();
}
/**
* {@inheritDoc}
*/
public ResolverService getResolverService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getResolverService();
}
/**
* {@inheritDoc}
*/
public DiscoveryService getDiscoveryService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getDiscoveryService();
}
/**
* {@inheritDoc}
*/
public PeerInfoService getPeerInfoService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getPeerInfoService();
}
/**
* {@inheritDoc}
*/
public MembershipService getMembershipService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getMembershipService();
}
/**
* {@inheritDoc}
*/
public PipeService getPipeService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getPipeService();
}
/**
* {@inheritDoc}
*/
public AccessService getAccessService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getAccessService();
}
/**
* {@inheritDoc}
*/
public ContentService getContentService() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getContentService();
}
/*
* A few convenience methods. This information is available from
* the peer and peergroup advertisement.
*/
/**
* {@inheritDoc}
*/
public PeerGroupID getPeerGroupID() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getPeerGroupID();
}
/**
* {@inheritDoc}
*/
public PeerID getPeerID() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getPeerID();
}
/**
* {@inheritDoc}
*/
public String getPeerGroupName() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getPeerGroupName();
}
/**
* {@inheritDoc}
*/
public String getPeerName() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getPeerName();
}
/**
* {@inheritDoc}
*/
public ConfigParams getConfigAdvertisement() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
ConfigParams configAdvertisement = temp.getConfigAdvertisement();
if (configAdvertisement == null) {
return null;
}
return configAdvertisement.clone();
}
/**
* {@inheritDoc}
*/
public ModuleImplAdvertisement getAllPurposePeerGroupImplAdvertisement() throws Exception {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getAllPurposePeerGroupImplAdvertisement();
}
/**
* {@inheritDoc}
*/
public PeerGroup getParentGroup() {
PeerGroup temp = groupImpl;
if (unrefed.get() || (null == temp)) {
throw new IllegalStateException("This Peer Group interface object has been unreferenced and can no longer be used. {" + instance + "}");
}
return temp.getParentGroup();
}
}