/*
* Copyright (c) 2001-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 java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.jxta.credential.AuthenticationCredential;
import net.jxta.credential.Credential;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.Advertisement;
import net.jxta.document.Element;
import net.jxta.document.MimeMediaType;
import net.jxta.document.XMLElement;
import net.jxta.endpoint.MessageTransport;
import net.jxta.exception.PeerGroupAuthenticationException;
import net.jxta.exception.PeerGroupException;
import net.jxta.exception.ProtocolNotSupportedException;
import net.jxta.exception.ServiceNotFoundException;
import net.jxta.id.ID;
import net.jxta.impl.access.pse.PSEAccessService;
import net.jxta.impl.cm.CacheManager;
import net.jxta.impl.cm.Srdi;
import net.jxta.impl.content.ContentServiceImpl;
import net.jxta.impl.membership.pse.DialogAuthenticator;
import net.jxta.impl.membership.pse.EngineAuthenticator;
import net.jxta.impl.membership.pse.PSEMembershipService;
import net.jxta.impl.membership.pse.StringAuthenticator;
import net.jxta.logging.Logger;
import net.jxta.logging.Logging;
import net.jxta.membership.MembershipService;
import net.jxta.peergroup.IModuleDefinitions;
import net.jxta.peergroup.PeerGroup;
import net.jxta.platform.IJxtaLoader;
import net.jxta.platform.JxtaApplication;
import net.jxta.platform.Module;
import net.jxta.platform.ModuleClassID;
import net.jxta.platform.ModuleSpecID;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.ConfigParams;
import net.jxta.protocol.ModuleImplAdvertisement;
import net.jxta.service.Service;
/**
* A subclass of GenericPeerGroup that makes a peer group out of independent
* plugin services listed in its impl advertisement.
*/
public class StdPeerGroup extends GenericPeerGroup {
private final static transient Logger LOG = Logging.getLogger(StdPeerGroup.class.getName());
// /**
// * This field is for backwards compatibility with broken code and will
// * be removed in the near future. The correct way to obtain a compatibility
// * statement is to obtain it from a peer group's implementation
// * advertisement.
// *
// * @deprecated will be removed in 2.8
// */
// @Deprecated
// public static final XMLDocument STD_COMPAT =
// CompatibilityUtils.createDefaultCompatStatement();
// /**
// * This field is for backwards compatibility with broken code and will
// * be removed in the near future. The correct way to obtain this
// * information is to obtain it from a peer group's implementation
// * advertisement.
// *
// * @deprecated will be removed in 2.8
// */
// @Deprecated
// public static final String MODULE_IMPL_STD_URI =
// CompatibilityUtils.getDefaultPackageURI();
// /**
// * This field is for backwards compatibility with broken code and will
// * be removed in the near future. The correct way to obtain this
// * information is to obtain it from a peer group's implementation
// * advertisement.
// *
// * @deprecated will be removed in 2.8
// */
// @Deprecated
// public static final String MODULE_IMPL_STD_PROVIDER =
// CompatibilityUtils.getDefaultProvider();
/**
* Static initializer.
*/
static {
// XXX Force redefinition of StdPeerGroup implAdvertisement.
getJxtaLoader().defineClass(getDefaultModuleImplAdvertisement());
}
/**
* If {@code true} then the PeerGroup has been started.
*/
private volatile boolean started = false;
/**
* The order in which we started the services.
*/
private final List<ModuleClassID> moduleStartOrder = new ArrayList<ModuleClassID>();
/**
* A map of the Message Transports for this group.
* <p/>
* <ul>
* <li>keys are {@link net.jxta.platform.ModuleClassID}</li>
* <li>values are {@link net.jxta.platform.Module}, but should also be
* {@link net.jxta.endpoint.MessageTransport}</li>
* </ul>
*/
private final Map<ModuleClassID, Object> messageTransports = new HashMap<ModuleClassID, Object>();
/**
* A map of the applications for this group.
* <p/>
* <ul>
* <li>keys are {@link net.jxta.platform.ModuleClassID}</li>
* <li>values are {@link net.jxta.platform.Module} or
* {@link net.jxta.protocol.ModuleImplAdvertisement} or
* {@link net.jxta.platform.ModuleSpecID}</li>
* </ul>
*/
private final Map<ModuleClassID, Object> applications = new HashMap<ModuleClassID, Object>();
/**
* Cache for this group.
*/
private CacheManager cm = null;
/**
* Create and populate the default module impl Advertisement for this class.
*
* @return The default module impl advertisement for this class.
*/
public static ModuleImplAdvertisement getDefaultModuleImplAdvertisement() {
ModuleImplAdvertisement implAdv = CompatibilityUtils.createModuleImplAdvertisement(
IModuleDefinitions.allPurposePeerGroupSpecID, StdPeerGroup.class.getName(),
"General Purpose Peer Group Implementation");
// Create the service list for the group.
StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv();
// set the services
// core services
IJxtaLoader loader = getJxtaLoader();
paramAdv.addService(IModuleDefinitions.endpointClassID, IModuleDefinitions.refEndpointSpecID);
paramAdv.addService(IModuleDefinitions.resolverClassID, IModuleDefinitions.refResolverSpecID);
paramAdv.addService(IModuleDefinitions.membershipClassID, PSEMembershipService.pseMembershipSpecID);
paramAdv.addService(IModuleDefinitions.accessClassID, PSEAccessService.PSE_ACCESS_SPEC_ID);
// standard services
paramAdv.addService(IModuleDefinitions.discoveryClassID, IModuleDefinitions.refDiscoverySpecID);
paramAdv.addService(IModuleDefinitions.rendezvousClassID, IModuleDefinitions.refRendezvousSpecID);
paramAdv.addService(IModuleDefinitions.pipeClassID, IModuleDefinitions.refPipeSpecID);
paramAdv.addService(IModuleDefinitions.peerinfoClassID, IModuleDefinitions.refPeerinfoSpecID);
paramAdv.addService(IModuleDefinitions.contentClassID, ContentServiceImpl.MODULE_SPEC_ID);
// // Applications
// ModuleImplAdvertisement moduleAdv = loader.findModuleImplAdvertisement(PeerGroup.refShellSpecID);
// if (null != moduleAdv) {
// paramAdv.addApp(PeerGroup.applicationClassID, PeerGroup.refShellSpecID);
// }
// Insert the newParamAdv in implAdv
XMLElement paramElement = (XMLElement) paramAdv.getDocument(MimeMediaType.XMLUTF8);
implAdv.setParam(paramElement);
return implAdv;
}
/**
* constructor
*/
public StdPeerGroup() {
// Empty
}
/**
* {@inheritDoc}
*/
// @Override
public boolean compatible(Element compat) {
return CompatibilityUtils.isCompatible(compat);
}
/**
* Builds a table of modules indexed by their class ID.
* The values are the loaded modules, the keys are their classId.
* This routine interprets the parameter list in the advertisement.
*
* @param modules The modules to load
* @param privileged if true then modules will get a real reference to
* the group loading them, otherwise its an interface object.
*/
protected void loadAllModules(Map<ModuleClassID, Object> modules, boolean privileged) {
Iterator<Map.Entry<ModuleClassID, Object>> eachModule = modules.entrySet().iterator();
while (eachModule.hasNext()) {
Map.Entry<ModuleClassID, Object> anEntry = eachModule.next();
ModuleClassID classID = anEntry.getKey();
Object value = anEntry.getValue();
// Already loaded.
if (value instanceof Module) {
continue;
}
// Try and load it.
try {
Module theModule = null;
if (value instanceof ModuleImplAdvertisement) {
// Load module will republish locally but not in the
// parent since that adv does not come from there.
theModule = loadModule(classID, (ModuleImplAdvertisement) value, privileged);
} else if (value instanceof ModuleSpecID) {
// loadModule will republish both locally and in the parent
// Where the module was fetched.
theModule = loadModule(classID, (ModuleSpecID) value, FromParent, privileged);
} else {
Logging.logCheckedError(LOG, "Skipping: ", classID, " Unsupported module descriptor : ", value.getClass().getName());
eachModule.remove();
continue;
}
if (theModule == null) throw new PeerGroupException("Could not find a loadable implementation for : " + classID);
anEntry.setValue(theModule);
} catch (Exception e) {
Logging.logCheckedWarning(LOG, "Could not load module for class ID : ", classID, "\n", e);
if (value instanceof ModuleImplAdvertisement) {
Logging.logCheckedWarning(LOG, "Will be missing from peer group : " + ((ModuleImplAdvertisement) value).getDescription());
} else {
Logging.logCheckedWarning(LOG, "Will be missing from peer group: ", value);
}
eachModule.remove();
}
}
}
/**
* The group does not care for start args, and does not come-up
* with args to pass to its main app. So, until we decide on something
* more useful, the args of the group's startApp are passed-on to the
* group's main app. NB: both the apps init and startApp methods are
* invoked.
*
* @return int Status.
*/
@Override
public int startApp(String[] arg) {
if (!initComplete) {
Logging.logCheckedError(LOG, "Group has not been initialized or init failed.");
return -1;
}
// FIXME: maybe concurrent callers should be blocked until the
// end of startApp(). That could mean forever, though.
if (started) {
return Module.START_OK;
}
started = true;
// Normally does nothing, but we have to.
int res = super.startApp(arg);
if (Module.START_OK != res) {
return res;
}
loadAllModules(applications, false); // Apps are non-privileged;
res = startModules((Map) applications);
return res;
}
/**
* {@inheritDoc}
*/
@Override
public void stopApp() {
// Shut down the group services and message transports.
Collections.reverse(moduleStartOrder);
for (ModuleClassID aModule : moduleStartOrder) {
try {
if (messageTransports.containsKey(aModule)) {
Module theMessageTransport = (Module) messageTransports.remove(aModule);
theMessageTransport.stopApp();
} else {
removeService(aModule);
}
} catch (Exception any) {
Logging.logCheckedWarning(LOG, "Failed to stop module: ", aModule, "\n", any);
}
}
moduleStartOrder.clear();
if (!messageTransports.isEmpty()) {
LOG.warn(messageTransports.size() + " message transports could not be shut down during peer group stop.");
}
messageTransports.clear();
super.stopApp();
if (cm != null) {
cm.stop();
cm = null;
}
}
/**
* Given a list of all the modules we need to start attempt to start them.
* There is an a-priori order, but we'll iterate over the list until all
* where able to complete their start phase or no progress is made. Since we
* give modules the opportunity to pretend that they are making progress, we
* need to have a safeguard: we will not iterate through the list more than
* N^2 + 1 times without at least one module completing; N being the number
* of modules still in the list. This should cover the worst case scenario
* and still allow the process to eventually fail if it has no chance of
* success.
*
* @param services The services to start.
*/
private int startModules(Map<ModuleClassID,Module> services) {
int iterations = 0;
int maxIterations = services.size() * services.size() + iterations + 1;
boolean progress = true;
while (!services.isEmpty() && (progress || (iterations < maxIterations))) {
progress = false;
iterations++;
Logging.logCheckedDebug(LOG, MessageFormat.format("Service startApp() round {0} of {1}(max)", iterations, maxIterations));
Iterator<Map.Entry<ModuleClassID, Module>> eachService = services.entrySet().iterator();
while (eachService.hasNext()) {
Map.Entry<ModuleClassID, Module> anEntry = eachService.next();
ModuleClassID mcid = anEntry.getKey();
Module aModule = anEntry.getValue();
int res;
try {
res = aModule.startApp(null);
} catch (Throwable all) {
Logging.logCheckedWarning(LOG, "Exception in startApp() : ", aModule, "\n", all);
res = -1;
}
switch (res) {
case Module.START_OK:
Logging.logCheckedDebug(LOG, "Module started : ", aModule);
if (aModule instanceof Service) {
addService(mcid, (Service) aModule);
} else {
messageTransports.put(mcid, aModule);
}
moduleStartOrder.add(mcid);
eachService.remove();
progress = true;
break;
case Module.START_AGAIN_PROGRESS:
// LOGGING: was Finer
Logging.logCheckedDebug(LOG, "Service made progress during start : ", aModule);
progress = true;
break;
case Module.START_AGAIN_STALLED:
// LOGGING: was Finer
Logging.logCheckedDebug(LOG, "Service stalled during start : ", aModule);
break;
case Module.START_DISABLED:
Logging.logCheckedDebug(LOG, "Service declined to start : ", aModule);
eachService.remove();
progress = true;
break;
default: // (negative)
Logging.logCheckedWarning(LOG, "Service failed to start (", res, ") : ", aModule);
eachService.remove();
progress = true;
break;
}
}
if (progress) {
maxIterations = services.size() * services.size() + iterations + 1;
}
}
// Uh-oh. Services co-dependency prevented them from starting.
if (!services.isEmpty()) {
if (Logging.SHOW_ERROR && LOG.isErrorEnabled()) {
StringBuilder failed = new StringBuilder( "No progress is being made in starting services after "
+ iterations + " iterations. Giving up.");
failed.append("\nThe following services could not be started : ");
for (Map.Entry<ModuleClassID, Module> aService : services.entrySet()) {
failed.append("\n\t");
failed.append(aService.getKey());
failed.append(" : ");
failed.append(aService.getValue());
}
LOG.error(failed.toString());
}
return -1;
}
return Module.START_OK;
}
/**
* {@inheritDoc}
* <p/>
* This method loads and initializes all of the peer group modules
* described in the provided implementation advertisement. Then, all modules
* are placed in a list and the list is processed iteratively. During each
* iteration, the {@link Module#startApp(String[])} method of each module
* is invoked once. Iterations continue until no progress is being made or
* the list is empty.
* <p/>
* The status returned by the {@link Module#startApp(String[])} method
* of each module is considered as follows:
* <p/>
* <ul>
* <li>{@link Module#START_OK}: The module is removed from the list of
* modules to be started and its {@link Module#startApp(String[])}
* method will not be invoked again.
* </li>
* <p/>
* <li>{@link Module#START_AGAIN_PROGRESS}: The module remains in the
* list of modules to be started and its {@link Module#startApp(String[])}
* method will be invoked during the next iteration, if there is one. </li>
* <p/>
* <li>{@link Module#START_AGAIN_STALLED}: The module remains in the list
* of modules to be started and its {@link Module#startApp(String[])}
* method will be invoked during the next iteration if there is one. </li>
* <p/>
* <li>Any other value: The module failed to initialize. Its
* {@link Module#startApp(String[])} method will not be invoked again.</li>
* </ul>
* <p/>
* Iterations through the list stop when:
* <ul>
* <li>The list is empty: the group initialization proceeds.</li>
* <p/>
* <li>A complete iteration was performed and all modules returned
* {@link Module#START_AGAIN_STALLED}: a {@link PeerGroupException}
* is thrown.</li>
* <p/>
* <li>A number of complete iteration completed without any module
* returning {@link Module#START_OK}: a {@link PeerGroupException}
* is thrown. The number of complete iterations before that happens is
* computed as 1 + the square of the number of modules currently in the
* list.</li>
* </ul>
*/
@Override
protected synchronized void initFirst(PeerGroup parent, ID assignedID, Advertisement impl) throws PeerGroupException {
if (initComplete) {
Logging.logCheckedWarning(LOG, "You cannot initialize a PeerGroup more than once !");
return;
}
// Set-up the minimal GenericPeerGroup
super.initFirst(parent, assignedID, impl);
// assignedID might have been null. It is now the peer group ID.
assignedID = getPeerGroupID();
// initialize cm before starting services.
try {
cm = new CacheManager(getStoreHome(), assignedID.getUniqueValue().toString(), getTaskManager(), 0L, false);
} catch (Exception e) {
Logging.logCheckedError(LOG, "Failure instantiating local store\n", e);
throw new PeerGroupException("Failure instantiating local store", e);
}
// flush srdi for this group
Srdi.clearSrdi(this);
// Load the list of peer group services from the impl advertisement params.
StdPeerGroupParamAdv paramAdv = new StdPeerGroupParamAdv(implAdvertisement.getParam());
Map<ModuleClassID, Object> initServices = new HashMap<ModuleClassID, Object>(paramAdv.getServices());
initServices.putAll(paramAdv.getProtos());
// Remove the modules disabled in the configuration file.
ConfigParams conf = getConfigAdvertisement();
if(null != conf) {
Iterator<ModuleClassID> eachModule = initServices.keySet().iterator();
while(eachModule.hasNext()) {
ModuleClassID aModule = eachModule.next();
if(!conf.isSvcEnabled(aModule)) {
// remove disabled module
Logging.logCheckedDebug(LOG, "Module disabled in configuration : ", aModule);
eachModule.remove();
}
}
}
//The membership service is mandatory from now on (Jan. 20, 2008). It will be loaded first
//and logged in. That will make sure the subsequent publishing will be signed.
//The objective of this section is to establish the peer's default credential for this group.
Object tempMsSpec = initServices.remove(IModuleDefinitions.membershipClassID);
if(tempMsSpec==null)
{
throw new PeerGroupException("Membership service is mandatory. It is not found for this group : " + this.getPeerGroupName());
}
else
{
Map<ModuleClassID, Object> tempMsMap = new HashMap<ModuleClassID, Object>();
tempMsMap.put(IModuleDefinitions.membershipClassID, tempMsSpec);
loadAllModules(tempMsMap,true);
int tempRes = startModules((Map)tempMsMap);
if(Module.START_OK ==tempRes)
{
MembershipService tempMs = this.getMembershipService();
Credential tempCred = null;
NetworkManager networkManager = JxtaApplication.findNetworkManager(getStoreHome());
assert networkManager != null;
String membershipAuthenticationType = "";
String membershipPassword = "";
try {
membershipAuthenticationType = networkManager.getConfigurator().getAuthenticationType();
membershipPassword = networkManager.getConfigurator().getPassword();
} catch (IOException ex) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Failed to retrieve network manager!");
stringBuilder.append(ex.getLocalizedMessage());
LOG.error(stringBuilder.toString());
}
tempCred = tempMs.getDefaultCredential();
if (null == tempCred)
{
if ("StringAuthentication".equals(membershipAuthenticationType)) {
AuthenticationCredential tempAuthCred = new AuthenticationCredential(this, "StringAuthentication", null);
StringAuthenticator tempAuth = null;
try
{
tempAuth = (StringAuthenticator) tempMs.apply(tempAuthCred);
}
catch(ProtocolNotSupportedException ex)
{
//Nothing can be done.
ex.printStackTrace();
}
if (null == tempAuth)
{
throw new PeerGroupException("Failed to get a StringAuthenticator for this group: "+this.getPeerGroupName()+". Error="+tempRes);
}
else
{
tempAuth.setAuth1_KeyStorePassword(membershipPassword);
tempAuth.setAuth2Identity(this.getPeerID());
tempAuth.setAuth3_IdentityPassword(membershipPassword);
if (tempAuth.isReadyForJoin())
{
tempMs.join(tempAuth);
if (tempMs.getDefaultCredential() == null)
{
throw new PeerGroupException("Failed to login to this group: "+this.getPeerGroupName()+". Error="+tempRes);
}
else
{
//The credential has been established. This is our objective.
//From now on, all the advertisements will be signed by this credential.
}
}
else
{
String peerGroupName = this.getPeerGroupName();
LOG.error("Failed to join the group: " + peerGroupName);
throw new PeerGroupAuthenticationException("Failed to join the group: " + peerGroupName);
}
}
} else if ("EngineAuthentication".equals(membershipAuthenticationType)) {
AuthenticationCredential tempAuthCred = new AuthenticationCredential(this, "EngineAuthentication", null);
EngineAuthenticator tempAuth = null;
try
{
tempAuth = (EngineAuthenticator) tempMs.apply(tempAuthCred);
}
catch(ProtocolNotSupportedException ex)
{
//Nothing can be done.
ex.printStackTrace();
}
if (null == tempAuth)
{
throw new PeerGroupException("Failed to get a EngineAuthentication for this group: " + this.getPeerGroupName() + ". Error = " + tempRes);
}
else
{
if (tempAuth.isReadyForJoin())
{
tempMs.join(tempAuth);
if (tempMs.getDefaultCredential() == null)
{
throw new PeerGroupException("Failed to login to this group: " + this.getPeerGroupName() + ". Error = " + tempRes);
}
else
{
//The credential has been established. This is our objective.
//From now on, all the advertisements will be signed by this credential.
}
}
else
{
String peerGroupName = this.getPeerGroupName();
LOG.error("Failed to join the group: " + peerGroupName);
throw new PeerGroupAuthenticationException("Failed to join the group: " + peerGroupName);
}
}
} else if ("DialogAuthentication".equals(membershipAuthenticationType) || "InteractiveAuthentication".equals(membershipAuthenticationType)) {
AuthenticationCredential tempAuthCred = new AuthenticationCredential(this, "DialogAuthentication", null);
DialogAuthenticator tempAuth = null;
try
{
tempAuth = (DialogAuthenticator) tempMs.apply(tempAuthCred);
}
catch(ProtocolNotSupportedException ex)
{
//Nothing can be done.
ex.printStackTrace();
}
if (null == tempAuth)
{
throw new PeerGroupException("Failed to get a DialogAuthenticator for this group: " + this.getPeerGroupName() + ". Error = " + tempRes);
}
else
{
char[] tempPass=null;
for(int attempt=0;attempt<3;attempt++)
{
net.jxta.impl.util.Password.singleton().setUsername(this.getPeerName());
tempPass = net.jxta.impl.util.Password.singleton().getPassword();
tempAuth.setAuth1_KeyStorePassword(tempPass);
tempAuth.setAuth2Identity(this.getPeerID());
tempAuth.setAuth3_IdentityPassword(tempPass);
if(tempAuth.isReadyForJoin())
{
break;
}
else
{
net.jxta.impl.util.Password.singleton().resetPassword();
}
}
if (tempAuth.isReadyForJoin())
{
tempMs.join(tempAuth);
if (tempMs.getDefaultCredential() == null)
{
throw new PeerGroupException("Failed to login to this group: " + this.getPeerGroupName() + ". Error = " + tempRes);
}
else
{
//The credential has been established. This is our objective.
//From now on, all the advertisements will be signed by this credential.
}
}
else
{
String peerGroupName = this.getPeerGroupName();
LOG.error("Failed to join the group: " + peerGroupName);
throw new PeerGroupAuthenticationException("Failed to join the group: " + peerGroupName);
}
}
}
}
else
{
//The credential has already been established, perhaps done during the module startup.
}
}
else
{
throw new PeerGroupException("Failed to start peer group membership service for this group: " + this.getPeerGroupName() + ". Error = " + tempRes);
}
}
// We Applications are shelved until startApp()
applications.putAll(paramAdv.getApps());
if(null != conf) {
Iterator<ModuleClassID> eachModule = applications.keySet().iterator();
while(eachModule.hasNext()) {
ModuleClassID aModule = eachModule.next();
if(!conf.isSvcEnabled(aModule)) {
// remove disabled module
Logging.logCheckedDebug(LOG, "Application disabled in configuration : ", aModule);
eachModule.remove();
}
}
}
loadAllModules(initServices, true);
int result = startModules((Map) initServices);
if(Module.START_OK != result) {
throw new PeerGroupException("Failed to start peer group services. Result : " + result);
}
// Make sure all the required services are loaded.
try {
checkServices();
} catch (ServiceNotFoundException e) {
LOG.error("Missing peer group service", e);
throw new PeerGroupException("Missing peer group service", e);
}
/*
* Publish a few things that have not been published in this
* group yet.
*/
DiscoveryService discoveryService = getDiscoveryService();
if (discoveryService != null) {
// It should work but if it does not we can survive.
try {
// Discovery service adv could not be published localy,
// since at that time there was no local discovery to
// publish to.
discoveryService.publish(discoveryService.getImplAdvertisement(), DEFAULT_LIFETIME, DEFAULT_EXPIRATION);
// Try to publish our impl adv within this group. (it was published
// in the parent automatically when loaded.
discoveryService.publish(implAdvertisement, DEFAULT_LIFETIME, DEFAULT_EXPIRATION);
} catch (Exception nevermind) {
Logging.logCheckedWarning(LOG, "Failed to publish Impl adv within group.", nevermind);
}
}
}
/**
* {@inheritDoc}
* <p/>
* Nothing special for now, but we might want to move some steps from
* initFirst() in the future.
* @throws net.jxta.exception.PeerGroupException
*/
@Override
protected synchronized void initLast() throws PeerGroupException {
super.initLast();
if (Logging.SHOW_CONFIG && LOG.isConfigEnabled()) {
StringBuilder configInfo = new StringBuilder("Configuring Group : " + getPeerGroupID());
configInfo.append("\n\tConfiguration :");
configInfo.append("\n\t\tCompatibility Statement :\n\t\t\t");
StringBuilder indent = new StringBuilder(
CompatibilityUtils.createDefaultCompatStatement().toString().trim());
int from = indent.length();
while (from > 0) {
int returnAt = indent.lastIndexOf("\n", from);
from = returnAt - 1;
if ((returnAt >= 0) && (returnAt != indent.length())) {
indent.insert(returnAt + 1, "\t\t\t");
}
}
configInfo.append(indent);
Iterator eachProto = messageTransports.entrySet().iterator();
if (eachProto.hasNext()) {
configInfo.append("\n\t\tMessage Transports :");
}
while (eachProto.hasNext()) {
Map.Entry anEntry = (Map.Entry) eachProto.next();
ModuleClassID aMCID = (ModuleClassID) anEntry.getKey();
Module anMT = (Module) anEntry.getValue();
configInfo.append("\n\t\t\t").append(aMCID).append("\t").append(
(anMT instanceof MessageTransport)
? ((MessageTransport) anMT).getProtocolName()
: anMT.getClass().getName());
}
Iterator<Map.Entry<ModuleClassID, Object>> eachApp = applications.entrySet().iterator();
if (eachApp.hasNext()) {
configInfo.append("\n\t\tApplications :");
}
while (eachApp.hasNext()) {
Map.Entry<ModuleClassID, Object> anEntry = eachApp.next();
ModuleClassID aMCID = anEntry.getKey();
Object anApp = anEntry.getValue();
if (anApp instanceof ModuleImplAdvertisement) {
ModuleImplAdvertisement adv = (ModuleImplAdvertisement) anApp;
configInfo.append("\n\t\t\t").append(aMCID).append("\t").append(adv.getCode());
} else {
configInfo.append("\n\t\t\t").append(aMCID).append("\t").append(anApp.getClass().getName());
}
}
LOG.config(configInfo.toString());
}
}
/**
* {@inheritDoc}
*/
// @Override
public ModuleImplAdvertisement getAllPurposePeerGroupImplAdvertisement() {
IJxtaLoader loader = getLoader();
// grab an impl adv
ModuleImplAdvertisement implAdv = loader.findModuleImplAdvertisement(IModuleDefinitions.allPurposePeerGroupSpecID);
return implAdv;
}
/**
* Returns the cache manager associated with this group.
*
* @return the cache manager associated with this group.
*/
public CacheManager getCacheManager() {
return cm;
}
/**
* Return a map of the applications for this group.
* <p/>
* <ul>
* <li>keys are {@link net.jxta.platform.ModuleClassID}</li>
* <li>values are {@link net.jxta.platform.Module} or
* {@link net.jxta.protocol.ModuleImplAdvertisement}</li>
* </ul>
*
* @return a map of the applications for this group.
*/
public Map<ModuleClassID, Object> getApplications() {
return Collections.unmodifiableMap(applications);
}
}