/* * 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 net.jxta.document.Advertisement; import net.jxta.document.AdvertisementFactory; import net.jxta.document.Document; import net.jxta.document.Element; import net.jxta.document.MimeMediaType; import net.jxta.document.StructuredDocument; import net.jxta.document.StructuredDocumentFactory; import net.jxta.document.StructuredDocumentUtils; import net.jxta.document.XMLElement; import net.jxta.id.IDFactory; import net.jxta.logging.Logging; import net.jxta.peergroup.PeerGroup; import net.jxta.platform.ModuleClassID; import net.jxta.platform.ModuleSpecID; import net.jxta.protocol.ModuleImplAdvertisement; import java.net.URI; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; /** * Not actually an advertisement, but often acts as part of one. * * @deprecated This internal class will eventually be removed. It has several * problems which make it difficult to support. (The most obvious that it * provides poor abstraction and provides references to its' own internal data * structures). This class is expected to be replaced by a public API class * performing a similar function though such an alternative is not yet available. * You are encouraged to copy this code into your own application or service if * if you depend upon it. */ @Deprecated public class StdPeerGroupParamAdv { /** * Logger */ private static final Logger LOG = Logger.getLogger(StdPeerGroupParamAdv.class.getName()); private static final String PARAM_TAG = "Parm"; private static final String PROTO_TAG = "Proto"; private static final String APP_TAG = "App"; private static final String SVC_TAG = "Svc"; private static final String MCID_TAG = "MCID"; private static final String MSID_TAG = "MSID"; private static final String MIA_TAG = ModuleImplAdvertisement.getAdvertisementType(); // In the future we should be able to manipulate all modules regardless of // their kind, but right now it helps to keep them categorized as follows. /** * The services which will be loaded for this peer group. * <p/> * <ul> * <li>Keys are {@link net.jxta.platform.ModuleClassID}.</li> * <li>Values are {@link net.jxta.platform.ModuleSpecID} or * {@link net.jxta.protocol.ModuleImplAdvertisement}.</li> * </ul> */ private final Map<ModuleClassID, Object> services = new HashMap<ModuleClassID, Object>(); /** * The protocols (message transports) which will be loaded for this peer * group. * <p/> * <ul> * <li>Keys are {@link net.jxta.platform.ModuleClassID}.</li> * <li>Values are {@link net.jxta.platform.ModuleSpecID} or * {@link net.jxta.protocol.ModuleImplAdvertisement}.</li> * </ul> */ private final Map<ModuleClassID, Object> transports = new HashMap<ModuleClassID, Object>(); /** * The applications which will be loaded for this peer group. * <p/> * <ul> * <li>Keys are {@link net.jxta.platform.ModuleClassID}.</li> * <li>Values are {@link net.jxta.platform.ModuleSpecID} or * {@link net.jxta.protocol.ModuleImplAdvertisement}.</li> * </ul> */ private final Map<ModuleClassID, Object> apps = new HashMap<ModuleClassID, Object>(); /** * Private constructor for new instances. */ public StdPeerGroupParamAdv() { } /** * Private constructor for serialized instances. * * @param root the root element */ public StdPeerGroupParamAdv(Element root) { if (!(root instanceof XMLElement)) { throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement"); } initialize((XMLElement) root); } /** * Private constructor for xml serialized instances. * * @param doc The XML serialization of the advertisement. */ public StdPeerGroupParamAdv(XMLElement doc) { initialize(doc); } /** * Add a service to the set of services entries described in this * Advertisement. * * @param mcid The module class id of the module being added. * @param module The module being added. */ public void addService(ModuleClassID mcid, Object module) { if(null == mcid) { throw new IllegalArgumentException("Illegal ModuleClassID"); } if(null == module) { throw new IllegalArgumentException("Illegal module"); } services.put(mcid, module); } /** * Return the services entries described in this Advertisement. * <p/> * The result (very unwisely) is the internal map of this * Advertisement. Modifying it results in changes to this Advertisement. * For safety the Map should be copied before being modified. * * @return the services entries described in this Advertisement. */ public Map<ModuleClassID, Object> getServices() { return services; } /** * Add a protocol (message transport) to the set of protocol entries * described in this Advertisement. * * @param mcid The module class id of the module being added. * @param module The module being added. */ public void addProto(ModuleClassID mcid, Object module) { if(null == mcid) { throw new IllegalArgumentException("Illegal ModuleClassID"); } if(null == module) { throw new IllegalArgumentException("Illegal module"); } transports.put(mcid, module); } /** * Return the protocols (message transports) entries described in this Advertisement. * <p/> * The result (very unwisely) is the internal map of this Advertisement. * Modifying it results in changes to this Advertisement. * For safety the Map should be copied before being modified. * * @return the protocols (message transports) entries described in this Advertisement. */ public Map<ModuleClassID, Object> getProtos() { return transports; } /** * Add an application to the set of application entries described in this * Advertisement. * * @param mcid The module class id of the module being added. * @param module The module being added. */ public void addApp(ModuleClassID mcid, Object module) { if(null == mcid) { throw new IllegalArgumentException("Illegal ModuleClassID"); } if(null == module) { throw new IllegalArgumentException("Illegal module"); } apps.put(mcid, module); } /** * Return the application entries described in this Advertisement. * <p/> * The result (very unwisely) is the internal map of this Advertisement. * Modifying it results in changes to this Advertisement. * For safety the Map should be copied before being modified. * * @return the application entries described in this Advertisement. */ public Map<ModuleClassID, Object> getApps() { return apps; } /** * Replaces the table of services described by this Advertisement. All * existing entries are lost. * * @param servicesTable the services table */ public void setServices(Map<ModuleClassID, Object> servicesTable) { if(servicesTable.containsKey(null)) { throw new IllegalArgumentException("null key in servicesTable"); } if(servicesTable.containsValue(null)) { throw new IllegalArgumentException("null value in servicesTable"); } if (servicesTable == this.services) { return; } this.services.clear(); if (null != servicesTable) { this.services.putAll(servicesTable); } } /** * Replaces the table of protocols described by this Advertisement. All * existing entries are lost. * * @param protosTable The message transport descriptors for the group. */ public void setProtos(Map<ModuleClassID, Object> protosTable) { if(protosTable.containsKey(null)) { throw new IllegalArgumentException("null key in protosTable"); } if(protosTable.containsValue(null)) { throw new IllegalArgumentException("null value in protosTable"); } if (protosTable == this.transports) { return; } this.transports.clear(); if (null != protosTable) { this.transports.putAll(protosTable); } } /** * Replaces the table of applications described by this Advertisement. All * existing entries are lost. * * @param appsTable The application descriptors for the group. */ public void setApps(Map<ModuleClassID, Object> appsTable) { if(appsTable.containsKey(null)) { throw new IllegalArgumentException("null key in appsTable"); } if(appsTable.containsValue(null)) { throw new IllegalArgumentException("null value in appsTable"); } if (appsTable == this.apps) { return; } this.apps.clear(); if (null != appsTable) { this.apps.putAll(appsTable); } } private void initialize(XMLElement doc) { if (!doc.getName().equals(PARAM_TAG)) { throw new IllegalArgumentException("Can not construct " + getClass().getName() + "from doc containing a " + doc.getName()); } // set defaults int appCount = 0; Enumeration<XMLElement> modules = doc.getChildren(); while (modules.hasMoreElements()) { XMLElement module = modules.nextElement(); String tagName = module.getName(); Map<ModuleClassID, Object> theTable; if (SVC_TAG.equals(tagName)) { theTable = services; } else if (APP_TAG.equals(tagName)) { theTable = apps; } else if (PROTO_TAG.equals(tagName)) { theTable = transports; } else { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "Unhandled top-level tag : " + tagName); } continue; } ModuleSpecID specID = null; ModuleClassID classID = null; ModuleImplAdvertisement inLineAdv = null; try { if (module.getTextValue() != null) { specID = (ModuleSpecID) IDFactory.fromURI(new URI(module.getTextValue())); } // Check for children anyway. Enumeration<XMLElement> fields = module.getChildren(); while (fields.hasMoreElements()) { XMLElement field = fields.nextElement(); String fieldName = field.getName(); if (MCID_TAG.equals(fieldName)) { classID = (ModuleClassID) IDFactory.fromURI(new URI(field.getTextValue())); } else if (MSID_TAG.equals(field.getName())) { specID = (ModuleSpecID) IDFactory.fromURI(new URI(field.getTextValue())); } else if (MIA_TAG.equals(field.getName())) { inLineAdv = (ModuleImplAdvertisement) AdvertisementFactory.newAdvertisement(field); } else { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "Unhandled field : " + fieldName); } } } } catch (Exception any) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "Broken entry; skipping", any); } continue; } if (inLineAdv == null && specID == null) { if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.warning("Insufficent entry; skipping"); } continue; } Object theValue; if (inLineAdv != null) { specID = inLineAdv.getModuleSpecID(); theValue = inLineAdv; } else { theValue = specID; } if (classID == null) { classID = specID.getBaseClass(); } // For applications, the role does not matter. We just create a // unique role ID on the fly. // When outputing the adv we get rid of it to save space. if (theTable == apps) { // Only the first (or only) one may use the base class. if (classID == PeerGroup.applicationClassID) { if (appCount++ != 0) { classID = IDFactory.newModuleClassID(classID); } } } theTable.put(classID, theValue); } } /** * Get the adv as a document of the specified MIME media type. * * @param encodeAs mime type to encode as * @return document instance */ public Document getDocument(MimeMediaType encodeAs) { StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(encodeAs, PARAM_TAG); outputModules(doc, services, SVC_TAG); outputModules(doc, transports, PROTO_TAG); outputModules(doc, apps, APP_TAG); return doc; } private void outputModules(StructuredDocument doc, Map<ModuleClassID, Object> modulesTable, String mainTag) { for (Map.Entry<ModuleClassID, Object> entry : modulesTable.entrySet()) { ModuleClassID mcid = entry.getKey(); Object val = entry.getValue(); Element m; if(null == mcid) { throw new IllegalStateException("null ModuleClassID in " + mainTag ); } // For applications, we ignore the role ID. It is not meaningfull, // and a new one is assigned on the fly when loading this adv. if (val instanceof Advertisement) { m = doc.createElement(mainTag); doc.appendChild(m); if (modulesTable != apps && !mcid.equals(mcid.getBaseClass())) { // It is not an app and there is a role ID. Output it. Element i = doc.createElement(MCID_TAG, mcid.toString()); m.appendChild(i); } StructuredDocument advdoc = (StructuredDocument) ((Advertisement) val).getDocument(doc.getMimeType()); StructuredDocumentUtils.copyElements(doc, m, advdoc); } else if (val instanceof ModuleSpecID) { if (modulesTable == apps || mcid.equals(mcid.getBaseClass())) { // Either it is an app or there is no role ID. // So the specId is good enough. m = doc.createElement(mainTag, val.toString()); doc.appendChild(m); } else { // The role ID matters, so the classId must be separate. m = doc.createElement(mainTag); doc.appendChild(m); Element i; i = doc.createElement(MCID_TAG, mcid.toString()); m.appendChild(i); i = doc.createElement(MSID_TAG, val.toString()); m.appendChild(i); } } else { if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { LOG.severe("unsupported descriptor for " + mcid + " in " + mainTag +" module table : " + val); } throw new IllegalStateException("unsupported descriptor for " + mcid + " in " + mainTag +" module table : " + val); } } } }