2 * Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved.
4 * The Sun Project JXTA(TM) Software License
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * 3. The end-user documentation included with the redistribution, if any, must
17 * include the following acknowledgment: "This product includes software
18 * developed by Sun Microsystems, Inc. for JXTA(TM) technology."
19 * Alternately, this acknowledgment may appear in the software itself, if
20 * and wherever such third-party acknowledgments normally appear.
22 * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
23 * not be used to endorse or promote products derived from this software
24 * without prior written permission. For written permission, please contact
25 * Project JXTA at http://www.jxta.org.
27 * 5. Products derived from this software may not be called "JXTA", nor may
28 * "JXTA" appear in their name, without prior written permission of Sun.
30 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
32 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
33 * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
36 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
39 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 * JXTA is a registered trademark of Sun Microsystems, Inc. in the United
42 * States and other countries.
44 * Please see the license information page at :
45 * <http://www.jxta.org/project/www/license.html> for instructions on use of
46 * the license in source files.
48 * ====================================================================
50 * This software consists of voluntary contributions made by many individuals
51 * on behalf of Project JXTA. For more information on Project JXTA, please see
52 * http://www.jxta.org.
54 * This license is based on the BSD license adopted by the Apache Foundation.
57 package net.jxta.impl.peergroup;
60 import net.jxta.document.Advertisement;
61 import net.jxta.document.AdvertisementFactory;
62 import net.jxta.document.Document;
63 import net.jxta.document.Element;
64 import net.jxta.document.MimeMediaType;
65 import net.jxta.document.StructuredDocument;
66 import net.jxta.document.StructuredDocumentFactory;
67 import net.jxta.document.StructuredDocumentUtils;
68 import net.jxta.document.XMLElement;
69 import net.jxta.id.IDFactory;
70 import net.jxta.logging.Logging;
71 import net.jxta.peergroup.PeerGroup;
72 import net.jxta.platform.ModuleClassID;
73 import net.jxta.platform.ModuleSpecID;
74 import net.jxta.protocol.ModuleImplAdvertisement;
77 import java.util.Enumeration;
78 import java.util.HashMap;
80 import java.util.logging.Level;
81 import java.util.logging.Logger;
85 * Not actually an advertisement, but often acts as part of one.
87 * @deprecated This internal class will eventually be removed. It has several
88 * problems which make it difficult to support. (The most obvious that it
89 * provides poor abstraction and provides references to its' own internal data
90 * structures). This class is expected to be replaced by a public API class
91 * performing a similar function though such an alternative is not yet available.
92 * You are encouraged to copy this code into your own application or service if
93 * if you depend upon it.
96 public class StdPeerGroupParamAdv {
101 private static final Logger LOG = Logger.getLogger(StdPeerGroupParamAdv.class.getName());
103 private static final String PARAM_TAG = "Parm";
104 private static final String PROTO_TAG = "Proto";
105 private static final String APP_TAG = "App";
106 private static final String SVC_TAG = "Svc";
107 private static final String MCID_TAG = "MCID";
108 private static final String MSID_TAG = "MSID";
109 private static final String MIA_TAG = ModuleImplAdvertisement.getAdvertisementType();
111 // In the future we should be able to manipulate all modules regardless of
112 // their kind, but right now it helps to keep them categorized as follows.
115 * The services which will be loaded for this peer group.
118 * <li>Keys are {@link net.jxta.platform.ModuleClassID}.</li>
119 * <li>Values are {@link net.jxta.platform.ModuleSpecID} or
120 * {@link net.jxta.protocol.ModuleImplAdvertisement}.</li>
123 private final Map<ModuleClassID, Object> services = new HashMap<ModuleClassID, Object>();
126 * The protocols (message transports) which will be loaded for this peer
130 * <li>Keys are {@link net.jxta.platform.ModuleClassID}.</li>
131 * <li>Values are {@link net.jxta.platform.ModuleSpecID} or
132 * {@link net.jxta.protocol.ModuleImplAdvertisement}.</li>
135 private final Map<ModuleClassID, Object> transports = new HashMap<ModuleClassID, Object>();
138 * The applications which will be loaded for this peer group.
141 * <li>Keys are {@link net.jxta.platform.ModuleClassID}.</li>
142 * <li>Values are {@link net.jxta.platform.ModuleSpecID} or
143 * {@link net.jxta.protocol.ModuleImplAdvertisement}.</li>
146 private final Map<ModuleClassID, Object> apps = new HashMap<ModuleClassID, Object>();
149 * Private constructor for new instances.
151 public StdPeerGroupParamAdv() {
155 * Private constructor for serialized instances.
157 * @param root the root element
159 public StdPeerGroupParamAdv(Element root) {
160 if (!(root instanceof XMLElement)) {
161 throw new IllegalArgumentException(getClass().getName() + " only supports XMLElement");
163 initialize((XMLElement) root);
167 * Private constructor for xml serialized instances.
169 * @param doc The XML serialization of the advertisement.
171 public StdPeerGroupParamAdv(XMLElement doc) {
176 * Add a service to the set of services entries described in this
179 * @param mcid The module class id of the module being added.
180 * @param module The module being added.
182 public void addService(ModuleClassID mcid, Object module) {
184 throw new IllegalArgumentException("Illegal ModuleClassID");
188 throw new IllegalArgumentException("Illegal module");
191 services.put(mcid, module);
195 * Return the services entries described in this Advertisement.
197 * The result (very unwisely) is the internal map of this
198 * Advertisement. Modifying it results in changes to this Advertisement.
199 * For safety the Map should be copied before being modified.
201 * @return the services entries described in this Advertisement.
203 public Map<ModuleClassID, Object> getServices() {
208 * Add a protocol (message transport) to the set of protocol entries
209 * described in this Advertisement.
211 * @param mcid The module class id of the module being added.
212 * @param module The module being added.
214 public void addProto(ModuleClassID mcid, Object module) {
216 throw new IllegalArgumentException("Illegal ModuleClassID");
220 throw new IllegalArgumentException("Illegal module");
223 transports.put(mcid, module);
227 * Return the protocols (message transports) entries described in this Advertisement.
229 * The result (very unwisely) is the internal map of this Advertisement.
230 * Modifying it results in changes to this Advertisement.
231 * For safety the Map should be copied before being modified.
233 * @return the protocols (message transports) entries described in this Advertisement.
235 public Map<ModuleClassID, Object> getProtos() {
240 * Add an application to the set of application entries described in this
243 * @param mcid The module class id of the module being added.
244 * @param module The module being added.
246 public void addApp(ModuleClassID mcid, Object module) {
248 throw new IllegalArgumentException("Illegal ModuleClassID");
252 throw new IllegalArgumentException("Illegal module");
255 apps.put(mcid, module);
259 * Return the application entries described in this Advertisement.
261 * The result (very unwisely) is the internal map of this Advertisement.
262 * Modifying it results in changes to this Advertisement.
263 * For safety the Map should be copied before being modified.
265 * @return the application entries described in this Advertisement.
267 public Map<ModuleClassID, Object> getApps() {
272 * Replaces the table of services described by this Advertisement. All
273 * existing entries are lost.
275 * @param servicesTable the services table
277 public void setServices(Map<ModuleClassID, Object> servicesTable) {
278 if(servicesTable.containsKey(null)) {
279 throw new IllegalArgumentException("null key in servicesTable");
282 if(servicesTable.containsValue(null)) {
283 throw new IllegalArgumentException("null value in servicesTable");
286 if (servicesTable == this.services) {
290 this.services.clear();
292 if (null != servicesTable) {
293 this.services.putAll(servicesTable);
298 * Replaces the table of protocols described by this Advertisement. All
299 * existing entries are lost.
301 * @param protosTable The message transport descriptors for the group.
303 public void setProtos(Map<ModuleClassID, Object> protosTable) {
304 if(protosTable.containsKey(null)) {
305 throw new IllegalArgumentException("null key in protosTable");
308 if(protosTable.containsValue(null)) {
309 throw new IllegalArgumentException("null value in protosTable");
312 if (protosTable == this.transports) {
316 this.transports.clear();
318 if (null != protosTable) {
319 this.transports.putAll(protosTable);
324 * Replaces the table of applications described by this Advertisement. All
325 * existing entries are lost.
327 * @param appsTable The application descriptors for the group.
329 public void setApps(Map<ModuleClassID, Object> appsTable) {
330 if(appsTable.containsKey(null)) {
331 throw new IllegalArgumentException("null key in appsTable");
334 if(appsTable.containsValue(null)) {
335 throw new IllegalArgumentException("null value in appsTable");
338 if (appsTable == this.apps) {
344 if (null != appsTable) {
345 this.apps.putAll(appsTable);
349 private void initialize(XMLElement doc) {
350 if (!doc.getName().equals(PARAM_TAG)) {
351 throw new IllegalArgumentException("Can not construct " + getClass().getName() + "from doc containing a " + doc.getName());
356 Enumeration<XMLElement> modules = doc.getChildren();
358 while (modules.hasMoreElements()) {
359 XMLElement module = modules.nextElement();
360 String tagName = module.getName();
362 Map<ModuleClassID, Object> theTable;
364 if (SVC_TAG.equals(tagName)) {
366 } else if (APP_TAG.equals(tagName)) {
368 } else if (PROTO_TAG.equals(tagName)) {
369 theTable = transports;
371 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
372 LOG.log(Level.WARNING, "Unhandled top-level tag : " + tagName);
377 ModuleSpecID specID = null;
378 ModuleClassID classID = null;
379 ModuleImplAdvertisement inLineAdv = null;
382 if (module.getTextValue() != null) {
383 specID = (ModuleSpecID) IDFactory.fromURI(new URI(module.getTextValue()));
386 // Check for children anyway.
387 Enumeration<XMLElement> fields = module.getChildren();
389 while (fields.hasMoreElements()) {
390 XMLElement field = fields.nextElement();
392 String fieldName = field.getName();
394 if (MCID_TAG.equals(fieldName)) {
395 classID = (ModuleClassID) IDFactory.fromURI(new URI(field.getTextValue()));
396 } else if (MSID_TAG.equals(field.getName())) {
397 specID = (ModuleSpecID) IDFactory.fromURI(new URI(field.getTextValue()));
398 } else if (MIA_TAG.equals(field.getName())) {
399 inLineAdv = (ModuleImplAdvertisement) AdvertisementFactory.newAdvertisement(field);
401 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
402 LOG.log(Level.WARNING, "Unhandled field : " + fieldName);
406 } catch (Exception any) {
407 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
408 LOG.log(Level.WARNING, "Broken entry; skipping", any);
413 if (inLineAdv == null && specID == null) {
414 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
415 LOG.warning("Insufficent entry; skipping");
422 if (inLineAdv != null) {
423 specID = inLineAdv.getModuleSpecID();
424 theValue = inLineAdv;
429 if (classID == null) {
430 classID = specID.getBaseClass();
433 // For applications, the role does not matter. We just create a
434 // unique role ID on the fly.
435 // When outputing the adv we get rid of it to save space.
437 if (theTable == apps) {
438 // Only the first (or only) one may use the base class.
439 if (classID == PeerGroup.applicationClassID) {
440 if (appCount++ != 0) {
441 classID = IDFactory.newModuleClassID(classID);
445 theTable.put(classID, theValue);
452 public Document getDocument(MimeMediaType encodeAs) {
453 StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(encodeAs, PARAM_TAG);
455 outputModules(doc, services, SVC_TAG);
456 outputModules(doc, transports, PROTO_TAG);
457 outputModules(doc, apps, APP_TAG);
462 private void outputModules(StructuredDocument doc, Map<ModuleClassID, Object> modulesTable, String mainTag) {
464 for (Map.Entry<ModuleClassID, Object> entry : modulesTable.entrySet()) {
465 ModuleClassID mcid = entry.getKey();
466 Object val = entry.getValue();
470 throw new IllegalStateException("null ModuleClassID in " + mainTag );
473 // For applications, we ignore the role ID. It is not meaningfull,
474 // and a new one is assigned on the fly when loading this adv.
476 if (val instanceof Advertisement) {
477 m = doc.createElement(mainTag);
480 if (modulesTable != apps && !mcid.equals(mcid.getBaseClass())) {
481 // It is not an app and there is a role ID. Output it.
482 Element i = doc.createElement(MCID_TAG, mcid.toString());
487 StructuredDocument advdoc = (StructuredDocument) ((Advertisement) val).getDocument(doc.getMimeType());
489 StructuredDocumentUtils.copyElements(doc, m, advdoc);
490 } else if (val instanceof ModuleSpecID) {
491 if (modulesTable == apps || mcid.equals(mcid.getBaseClass())) {
492 // Either it is an app or there is no role ID.
493 // So the specId is good enough.
494 m = doc.createElement(mainTag, val.toString());
497 // The role ID matters, so the classId must be separate.
498 m = doc.createElement(mainTag);
503 i = doc.createElement(MCID_TAG, mcid.toString());
506 i = doc.createElement(MSID_TAG, val.toString());
510 if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
511 LOG.severe("unsupported descriptor for " + mcid + " in " + mainTag +" module table : " + val);
513 throw new IllegalStateException("unsupported descriptor for " + mcid + " in " + mainTag +" module table : " + val);