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.protocol;
60 import net.jxta.document.*;
61 import net.jxta.id.ID;
62 import net.jxta.id.IDFactory;
63 import java.util.logging.Level;
64 import net.jxta.logging.Logging;
65 import java.util.logging.Logger;
68 import java.net.URISyntaxException;
70 import java.util.concurrent.atomic.AtomicInteger;
74 * A container for collections of configuration parameters. Configuration
75 * parameters are stored in a Map which is keyed by {@code JXTA ID}s and whose
76 * values are {@code Advertisement}s.
78 public abstract class ConfigParams extends ExtendableAdvertisement implements Cloneable {
83 private final static transient Logger LOG = Logger.getLogger(ConfigParams.class.getName());
85 private static final String SVC_TAG = "Svc";
86 private static final String MCID_TAG = "MCID";
87 private static final String PARAM_TAG = "Parm";
90 * A table of structured documents to be interpreted by each service.
91 * For safe operation these elements should be immutable, but we're helpless
94 private final Map<ID, StructuredDocument> params = new HashMap<ID, StructuredDocument>();
97 * A map of advertisements to be interpreted by each service.
98 * For safe operation we clone the advertisements when they are added to the
99 * map and only ever return clones of the advertisements.
101 private final Map<ID, Advertisement> ads = new HashMap<ID, Advertisement>();
104 * The ids of the advertisements and/or params which have been explicitly
105 * marked as disabled.
107 private final Set<ID> disabled = new HashSet<ID>();
110 * Counts the changes made to this object. The API increments it every time
111 * some change is not proven to be idempotent. We rely on implementations to
112 * increment modCount every time something is changed without going through
115 protected final transient AtomicInteger modCount = new AtomicInteger(0);
118 * Returns the identifying type of this Advertisement.
120 * @return String the type of advertisement
122 public static String getAdvertisementType() {
127 * Default Constructor. We want all ConfigParams derived advertisements to
130 protected ConfigParams() {
138 public ConfigParams clone() {
141 ConfigParams result = (ConfigParams) super.clone();
143 for (Map.Entry<ID, StructuredDocument> anEntry : params.entrySet()) {
144 result.params.put(anEntry.getKey(), StructuredDocumentUtils.copyAsDocument(anEntry.getValue()));
147 for (Map.Entry<ID, Advertisement> anEntry : ads.entrySet()) {
148 result.ads.put(anEntry.getKey(), anEntry.getValue().clone());
151 result.disabled.addAll(disabled);
154 } catch (CloneNotSupportedException impossible) {
155 throw new Error("Object.clone() threw CloneNotSupportedException", impossible);
163 public boolean equals(Object other) {
168 if(other instanceof ConfigParams) {
169 ConfigParams likeMe = (ConfigParams) other;
171 boolean ep = params.equals(likeMe.params);
172 boolean ea = ads.equals(likeMe.ads);
173 boolean ed = disabled.equals(likeMe.disabled);
175 return ep && ea && ed;
186 public final String getBaseAdvType() {
187 return getAdvertisementType();
194 protected boolean handleElement(Element raw) {
196 if (super.handleElement(raw)) {
200 XMLElement elem = (XMLElement) raw;
202 if (SVC_TAG.equals(elem.getName())) {
203 Attribute disabledAttr = elem.getAttribute("disabled");
204 boolean isDisabled = (null != disabledAttr) && Boolean.parseBoolean(disabledAttr.getValue());
206 Enumeration<XMLElement> elems = elem.getChildren();
209 XMLElement param = null;
211 while (elems.hasMoreElements()) {
212 XMLElement e = elems.nextElement();
214 if (MCID_TAG.equals(e.getName())) {
216 URI mcid = new URI(e.getTextValue());
218 key = IDFactory.fromURI(mcid);
219 } catch (URISyntaxException badID) {
220 throw new IllegalArgumentException("Bad ID in advertisement: " + e.getTextValue());
222 } else if (PARAM_TAG.equals(e.getName())) {
225 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
226 LOG.warning("Unrecognized <Svc> tag : " + e.getName());
231 if (key != null && param != null) {
233 // Backwards compatibility support.
234 Enumeration<XMLElement> isOff = param.getChildren("isOff");
236 isDisabled = isOff.hasMoreElements();
239 putServiceParam(key, param);
244 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
245 LOG.warning("Incomplete Service Param : id=" + key + " param=" + param);
256 * Return the advertisement as a document.
258 * @param adv the document to add elements to.
259 * @return true if elements were added otherwise false.
261 public boolean addDocumentElements(StructuredDocument adv) {
263 for (Map.Entry<ID, StructuredDocument> anEntry : params.entrySet()) {
264 ID anID = anEntry.getKey();
265 StructuredDocument aDoc = anEntry.getValue();
267 Element s = adv.createElement(SVC_TAG);
271 if(disabled.contains(anID)) {
272 ((Attributable)s).addAttribute("disabled", "true");
275 Element e = adv.createElement(MCID_TAG, anID.toString());
279 StructuredDocumentUtils.copyElements(adv, s, aDoc, PARAM_TAG);
282 for (Map.Entry<ID, Advertisement> anEntry : ads.entrySet()) {
283 ID anID = anEntry.getKey();
284 Advertisement anAdv = anEntry.getValue();
286 Element s = adv.createElement(SVC_TAG);
290 if(disabled.contains(anID)) {
291 ((Attributable)s).addAttribute("disabled", "true");
294 Element e = adv.createElement(MCID_TAG, anID.toString());
298 StructuredDocument asDoc = (StructuredDocument) anAdv.getDocument(adv.getMimeType());
300 StructuredDocumentUtils.copyElements(adv, s, asDoc, PARAM_TAG);
307 * Returns the number of times this object has been modified since it was
308 * created. This permits the detection of local changes that require
309 * refreshing some other data.
311 * @return int the current modification count.
313 public int getModCount() {
314 return modCount.get();
318 * Increases the modification count of this instance.
320 * @return modification count
322 protected synchronized int incModCount() {
323 return modCount.incrementAndGet();
327 * Puts a service parameter in the service parameters table
328 * under the given key. The key is usually a ModuleClassID. This method
329 * makes a clone of the given element into an independent document.
331 * @param key The key.
332 * @param param The parameter document.
334 public void putServiceParam(ID key, Element param) {
344 boolean isDisabled = false;
346 if (param instanceof XMLElement) {
347 Enumeration<XMLElement> isOff = param.getChildren("isOff");
349 isDisabled = isOff.hasMoreElements();
351 Advertisement adv = null;
354 adv = AdvertisementFactory.newAdvertisement((XMLElement) param);
355 } catch (RuntimeException ignored) {
361 setSvcConfigAdvertisement(key,adv, !isDisabled);
366 StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(param);
371 disabled.remove(key);
374 params.put(key, newDoc);
379 * Puts an advertisement into the service parameters table under the given
380 * key. The key is usually a {@code ModuleClassID}. This method makes a
381 * clone of the advertisement.
383 * @param key The key.
384 * @param adv The advertisement, a clone of which is stored or {@code null}
385 * to forget this key.
387 public void setSvcConfigAdvertisement(ID key, Advertisement adv) {
388 setSvcConfigAdvertisement(key, adv, true);
392 * Puts an advertisement into the service parameters table under the given
393 * key. The key is usually a {@code ModuleClassID}. This method makes a
394 * clone of the advertisement.
396 * @param key The key.
397 * @param adv The advertisement, a clone of which is stored or {@code null}
398 * to forget this key.
399 * @param enabled If true then the service is enabled or disabled if false.
401 public void setSvcConfigAdvertisement(ID key, Advertisement adv, boolean enabled) {
408 disabled.remove(key);
418 ads.put(key, adv.clone());
419 } catch (CloneNotSupportedException failed) {
420 if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
421 LOG.log(Level.SEVERE, "Unclonable Advertisements may not be used : " + adv.getClass().getName(), failed);
424 throw new IllegalArgumentException("Unclonable Advertisements may not be used : " + adv.getClass().getName());
429 * Gets an advertisement from the service parameters table under the given
430 * key. The key is usually a {@code ModuleClassID}. This method makes a
431 * clone of the advertisement.
433 * @param key The key.
434 * @return If {@code true} then the service is enabled otherwise {@false} if
435 * the service is disabled.
437 public boolean isSvcEnabled(ID key) {
438 return !disabled.contains(key);
442 * Gets an advertisement from the service parameters table under the given
443 * key. The key is usually a {@code ModuleClassID}. This method makes a
444 * clone of the advertisement.
446 * @param key The key.
447 * @return The advertisement for the specified key otherwise {@code null}.
449 public Advertisement getSvcConfigAdvertisement(ID key) {
450 Advertisement adv = ads.get(key);
453 if (params.containsKey(key)) {
454 throw new IllegalStateException("Unable to return advertisement, params are not an advertisement.");
462 } catch (CloneNotSupportedException failed) {
463 if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
464 LOG.log(Level.SEVERE, "Unclonable Advertisements may not be used : " + adv.getClass().getName(), failed);
467 throw new IllegalArgumentException("Unclonable Advertisements may not be used : " + adv.getClass().getName());
472 * Returns the parameter element that matches the given key from the
473 * service parameters table. The key is of a subclass of ID; usually a
476 * @param key The key.
477 * @return StructuredDocument The matching parameter document or null if
480 public StructuredDocument getServiceParam(ID key) {
481 StructuredDocument param = params.get(key);
484 Advertisement ad = ads.get(key);
490 return (XMLDocument) ad.getDocument(MimeMediaType.XMLUTF8);
493 StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(param);
495 if(disabled.contains(key)) {
496 Enumeration<Element> isOffAlready = newDoc.getChildren("isOff");
498 if(!isOffAlready.hasMoreElements()) {
499 newDoc.appendChild(newDoc.createElement("isOff", null));
507 * Removes and returns the parameter element that matches the given key
508 * from the service parameters table. The key is of a subclass of ID;
509 * usually a ModuleClassID.
511 * @param key The key.
513 * @return The removed parameter element or {@code null} if not found.
515 public StructuredDocument removeServiceParam(ID key) {
517 StructuredDocument param = params.remove(key);
520 Advertisement ad = ads.remove(key);
526 return (XMLDocument) ad.getDocument(MimeMediaType.XMLUTF8);
533 // It sound silly to clone it, but remember that we could be sharing
534 // this element with a clone of ours, so we have the duty to still
537 StructuredDocument newDoc = StructuredDocumentUtils.copyAsDocument(param);
539 if(disabled.contains(key)) {
540 newDoc.appendChild(newDoc.createElement("isOff", null));
541 disabled.remove(key);
548 * Removes any parameters for the given key from the service parameters
551 * @param key The key.
553 public void removeSvcConfigAdvertisement(ID key) {
561 * Returns the set of params held by this object. The parameters are not
562 * copied and any changes to the Set are reflected in this object's version.
563 * incModCount should be called as appropriate.
565 * @deprecated This method exposes the internal data structures of the
566 * advertisement and will be removed in order to prevent unexpected
570 public Set<Map.Entry<ID, StructuredDocument>> getServiceParamsEntrySet() {
571 Map<ID, StructuredDocument> result = new HashMap<ID, StructuredDocument>();
573 result.putAll(params);
575 for (Map.Entry<ID, Advertisement> anEntry : ads.entrySet()) {
576 XMLDocument entryDoc = (XMLDocument) anEntry.getValue().getDocument(MimeMediaType.XMLUTF8);
578 if(disabled.contains(anEntry.getKey())) {
579 entryDoc.appendChild(entryDoc.createElement("isOff", null));
582 result.put(anEntry.getKey(), entryDoc);
585 return Collections.unmodifiableSet(result.entrySet());