1 /*
   2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.ws.api;
  27 
  28 import com.sun.istack.internal.NotNull;
  29 import com.sun.istack.internal.Nullable;
  30 import com.sun.xml.internal.ws.api.message.Packet;
  31 import com.sun.xml.internal.ws.client.RequestContext;
  32 import com.sun.xml.internal.ws.client.ResponseContext;
  33 
  34 import javax.xml.soap.SOAPException;
  35 import javax.xml.soap.SOAPMessage;
  36 import javax.xml.ws.WebServiceContext;
  37 import java.util.Map.Entry;
  38 import java.util.IdentityHashMap;
  39 import java.util.Map;
  40 import java.util.Set;
  41 
  42 /**
  43  * {@link PropertySet} that combines properties exposed from multiple
  44  * {@link PropertySet}s into one.
  45  *
  46  * <p>
  47  * This implementation allows one {@link PropertySet} to assemble
  48  * all properties exposed from other "satellite" {@link PropertySet}s.
  49  * (A satellite may itself be a {@link DistributedPropertySet}, so
  50  * in general this can form a tree.)
  51  *
  52  * <p>
  53  * This is useful for JAX-WS because the properties we expose to the application
  54  * are contributed by different pieces, and therefore we'd like each of them
  55  * to have a separate {@link PropertySet} implementation that backs up
  56  * the properties. For example, this allows FastInfoset to expose its
  57  * set of properties to {@link RequestContext} by using a strongly-typed fields.
  58  *
  59  * <p>
  60  * This is also useful for a client-side transport to expose a bunch of properties
  61  * into {@link ResponseContext}. It simply needs to create a {@link PropertySet}
  62  * object with methods for each property it wants to expose, and then add that
  63  * {@link PropertySet} to {@link Packet}. This allows property values to be
  64  * lazily computed (when actually asked by users), thus improving the performance
  65  * of the typical case where property values are not asked.
  66  *
  67  * <p>
  68  * A similar benefit applies on the server-side, for a transport to expose
  69  * a bunch of properties to {@link WebServiceContext}.
  70  *
  71  * <p>
  72  * To achieve these benefits, access to {@link DistributedPropertySet} is slower
  73  * compared to {@link PropertySet} (such as get/set), while adding a satellite
  74  * object is relatively fast.
  75  *
  76  * @author Kohsuke Kawaguchi
  77  */
  78 public abstract class DistributedPropertySet
  79     extends PropertySet
  80     implements com.sun.xml.internal.org.jvnet.ws.message.DistributedPropertySet
  81 {
  82     /**
  83      * All {@link PropertySet}s that are bundled into this {@link PropertySet}.
  84      */
  85     private final Map<Class, PropertySet> satellites = new IdentityHashMap<Class, PropertySet>();
  86 
  87     public void addSatellite(@NotNull PropertySet satellite) {
  88         addSatellite(satellite.getClass(), satellite);
  89     }
  90 
  91     public void addSatellite(@NotNull Class keyClass, @NotNull PropertySet satellite) {
  92         satellites.put(keyClass, satellite);
  93     }
  94 
  95     public void copySatelliteInto(@NotNull DistributedPropertySet r) {
  96         r.satellites.putAll(this.satellites);
  97     }
  98 
  99     public @Nullable <T extends com.sun.xml.internal.org.jvnet.ws.message.PropertySet> T getSatellite(Class<T> satelliteClass) {
 100         T satellite = (T) satellites.get(satelliteClass);
 101         if (satellite != null)
 102                 return satellite;
 103 
 104         for (PropertySet child : satellites.values()) {
 105             if (satelliteClass.isInstance(child)) {
 106                 return satelliteClass.cast(child);
 107             }
 108 
 109             if (DistributedPropertySet.class.isInstance(child)) {
 110                 satellite = DistributedPropertySet.class.cast(child).getSatellite(satelliteClass);
 111                 if (satellite != null) {
 112                     return satellite;
 113                 }
 114             }
 115         }
 116         return null;
 117     }
 118 
 119     @Override
 120     public Object get(Object key) {
 121         // check satellites
 122         for (PropertySet child : satellites.values()) {
 123             if(child.supports(key))
 124                 return child.get(key);
 125         }
 126 
 127         // otherwise it must be the master
 128         return super.get(key);
 129     }
 130 
 131     @Override
 132     public Object put(String key, Object value) {
 133         // check satellites
 134         for (PropertySet child : satellites.values()) {
 135             if(child.supports(key))
 136                 return child.put(key,value);
 137         }
 138 
 139         // otherwise it must be the master
 140         return super.put(key,value);
 141     }
 142 
 143     @Override
 144     public boolean supports(Object key) {
 145         // check satellites
 146         for (PropertySet child : satellites.values()) {
 147             if(child.supports(key))
 148                 return true;
 149         }
 150 
 151         return super.supports(key);
 152     }
 153 
 154     @Override
 155     public Object remove(Object key) {
 156         // check satellites
 157         for (PropertySet child : satellites.values()) {
 158             if(child.supports(key))
 159                 return child.remove(key);
 160         }
 161 
 162         return super.remove(key);
 163     }
 164 
 165     @Override
 166     /*package*/ void createEntrySet(Set<Entry<String, Object>> core) {
 167         super.createEntrySet(core);
 168         for (PropertySet child : satellites.values()) {
 169             child.createEntrySet(core);
 170         }
 171     }
 172 
 173     public void addSatellite(com.sun.xml.internal.org.jvnet.ws.message.PropertySet satellite) {
 174         addSatellite((PropertySet)satellite);
 175     }
 176 
 177     public void addSatellite(@NotNull Class keyClass, @NotNull com.sun.xml.internal.org.jvnet.ws.message.PropertySet satellite) {
 178         addSatellite(keyClass, (PropertySet)satellite);
 179     }
 180 
 181     public void removeSatellite(com.sun.xml.internal.org.jvnet.ws.message.PropertySet satellite) {
 182         removeSatellite((PropertySet)satellite);
 183     }
 184 
 185     public void copySatelliteInto(com.sun.xml.internal.org.jvnet.ws.message.MessageContext r) {
 186         copySatelliteInto((DistributedPropertySet)r);
 187     }
 188 }