Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 1997, 2013, 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 */
26 package com.oracle.webservices.internal.api.message;
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;
34 import javax.xml.ws.WebServiceContext;
36 import java.util.AbstractMap;
37 import java.util.Map.Entry;
38 import java.util.HashSet;
39 import java.util.IdentityHashMap;
40 import java.util.Map;
41 import java.util.Set;
43 /**
44 * {@link PropertySet} that combines properties exposed from multiple
45 * {@link PropertySet}s into one.
46 *
47 * <p>
48 * This implementation allows one {@link PropertySet} to assemble
49 * all properties exposed from other "satellite" {@link PropertySet}s.
50 * (A satellite may itself be a {@link DistributedPropertySet}, so
51 * in general this can form a tree.)
52 *
53 * <p>
54 * This is useful for JAX-WS because the properties we expose to the application
55 * are contributed by different pieces, and therefore we'd like each of them
56 * to have a separate {@link PropertySet} implementation that backs up
57 * the properties. For example, this allows FastInfoset to expose its
58 * set of properties to {@link RequestContext} by using a strongly-typed fields.
59 *
60 * <p>
61 * This is also useful for a client-side transport to expose a bunch of properties
62 * into {@link ResponseContext}. It simply needs to create a {@link PropertySet}
63 * object with methods for each property it wants to expose, and then add that
64 * {@link PropertySet} to {@link Packet}. This allows property values to be
65 * lazily computed (when actually asked by users), thus improving the performance
66 * of the typical case where property values are not asked.
67 *
68 * <p>
69 * A similar benefit applies on the server-side, for a transport to expose
70 * a bunch of properties to {@link WebServiceContext}.
71 *
72 * <p>
73 * To achieve these benefits, access to {@link DistributedPropertySet} is slower
74 * compared to {@link PropertySet} (such as get/set), while adding a satellite
75 * object is relatively fast.
76 *
77 * @author Kohsuke Kawaguchi
78 */
79 public abstract class BaseDistributedPropertySet extends BasePropertySet implements DistributedPropertySet {
81 /**
82 * All {@link PropertySet}s that are bundled into this {@link PropertySet}.
83 */
84 private final Map<Class<? extends com.oracle.webservices.internal.api.message.PropertySet>, PropertySet> satellites
85 = new IdentityHashMap<Class<? extends com.oracle.webservices.internal.api.message.PropertySet>, PropertySet>();
87 private final Map<String, Object> viewthis;
89 public BaseDistributedPropertySet() {
90 this.viewthis = super.createView();
91 }
93 @Override
94 public void addSatellite(@NotNull PropertySet satellite) {
95 addSatellite(satellite.getClass(), satellite);
96 }
98 @Override
99 public void addSatellite(@NotNull Class<? extends com.oracle.webservices.internal.api.message.PropertySet> keyClass, @NotNull PropertySet satellite) {
100 satellites.put(keyClass, satellite);
101 }
103 @Override
104 public void removeSatellite(PropertySet satellite) {
105 satellites.remove(satellite.getClass());
106 }
108 public void copySatelliteInto(@NotNull DistributedPropertySet r) {
109 for (Map.Entry<Class<? extends com.oracle.webservices.internal.api.message.PropertySet>, PropertySet> entry : satellites.entrySet()) {
110 r.addSatellite(entry.getKey(), entry.getValue());
111 }
112 }
114 @Override
115 public void copySatelliteInto(MessageContext r) {
116 copySatelliteInto((DistributedPropertySet)r);
117 }
119 @Override
120 public @Nullable <T extends com.oracle.webservices.internal.api.message.PropertySet> T getSatellite(Class<T> satelliteClass) {
121 T satellite = (T) satellites.get(satelliteClass);
122 if (satellite != null) {
123 return satellite;
124 }
126 for (PropertySet child : satellites.values()) {
127 if (satelliteClass.isInstance(child)) {
128 return satelliteClass.cast(child);
129 }
131 if (DistributedPropertySet.class.isInstance(child)) {
132 satellite = DistributedPropertySet.class.cast(child).getSatellite(satelliteClass);
133 if (satellite != null) {
134 return satellite;
135 }
136 }
137 }
138 return null;
139 }
141 @Override
142 public Map<Class<? extends com.oracle.webservices.internal.api.message.PropertySet>, com.oracle.webservices.internal.api.message.PropertySet> getSatellites() {
143 return satellites;
144 }
146 @Override
147 public Object get(Object key) {
148 // check satellites
149 for (PropertySet child : satellites.values()) {
150 if (child.supports(key)) {
151 return child.get(key);
152 }
153 }
155 // otherwise it must be the master
156 return super.get(key);
157 }
159 @Override
160 public Object put(String key, Object value) {
161 // check satellites
162 for (PropertySet child : satellites.values()) {
163 if(child.supports(key)) {
164 return child.put(key,value);
165 }
166 }
168 // otherwise it must be the master
169 return super.put(key,value);
170 }
172 @Override
173 public boolean containsKey(Object key) {
174 if (viewthis.containsKey(key))
175 return true;
176 for (PropertySet child : satellites.values()) {
177 if (child.containsKey(key)) {
178 return true;
179 }
180 }
181 return false;
182 }
184 @Override
185 public boolean supports(Object key) {
186 // check satellites
187 for (PropertySet child : satellites.values()) {
188 if (child.supports(key)) {
189 return true;
190 }
191 }
193 return super.supports(key);
194 }
196 @Override
197 public Object remove(Object key) {
198 // check satellites
199 for (PropertySet child : satellites.values()) {
200 if (child.supports(key)) {
201 return child.remove(key);
202 }
203 }
205 return super.remove(key);
206 }
208 @Override
209 protected void createEntrySet(Set<Entry<String, Object>> core) {
210 super.createEntrySet(core);
211 for (PropertySet child : satellites.values()) {
212 ((BasePropertySet) child).createEntrySet(core);
213 }
214 }
216 protected Map<String, Object> asMapLocal() {
217 return viewthis;
218 }
220 protected boolean supportsLocal(Object key) {
221 return super.supports(key);
222 }
224 class DistributedMapView extends AbstractMap<String, Object> {
225 @Override
226 public Object get(Object key) {
227 for (PropertySet child : satellites.values()) {
228 if (child.supports(key)) {
229 return child.get(key);
230 }
231 }
233 return viewthis.get(key);
234 }
236 @Override
237 public int size() {
238 int size = viewthis.size();
239 for (PropertySet child : satellites.values()) {
240 size += child.asMap().size();
241 }
242 return size;
243 }
245 @Override
246 public boolean containsKey(Object key) {
247 if (viewthis.containsKey(key))
248 return true;
249 for (PropertySet child : satellites.values()) {
250 if (child.containsKey(key))
251 return true;
252 }
253 return false;
254 }
256 @Override
257 public Set<Entry<String, Object>> entrySet() {
258 Set<Entry<String, Object>> entries = new HashSet<Entry<String, Object>>();
259 for (PropertySet child : satellites.values()) {
260 for (Entry<String,Object> entry : child.asMap().entrySet()) {
261 // the code below is here to avoid entries.addAll(child.asMap().entrySet()); which works differently on JDK6/7
262 // see DMI_ENTRY_SETS_MAY_REUSE_ENTRY_OBJECTS
263 entries.add(new SimpleImmutableEntry<String, Object>(entry.getKey(), entry.getValue()));
264 }
265 }
266 for (Entry<String,Object> entry : viewthis.entrySet()) {
267 // the code below is here to avoid entries.addAll(child.asMap().entrySet()); which works differently on JDK6/7
268 // see DMI_ENTRY_SETS_MAY_REUSE_ENTRY_OBJECTS
269 entries.add(new SimpleImmutableEntry<String, Object>(entry.getKey(), entry.getValue()));
270 }
272 return entries;
273 }
275 @Override
276 public Object put(String key, Object value) {
277 for (PropertySet child : satellites.values()) {
278 if (child.supports(key)) {
279 return child.put(key, value);
280 }
281 }
283 return viewthis.put(key, value);
284 }
286 @Override
287 public void clear() {
288 satellites.clear();
289 viewthis.clear();
290 }
292 @Override
293 public Object remove(Object key) {
294 for (PropertySet child : satellites.values()) {
295 if (child.supports(key)) {
296 return child.remove(key);
297 }
298 }
300 return viewthis.remove(key);
301 }
302 }
304 @Override
305 protected Map<String, Object> createView() {
306 return new DistributedMapView();
307 }
308 }