src/share/jaxws_classes/com/sun/xml/internal/ws/api/PropertySet.java

changeset 368
0989ad8c0860
parent 286
f50545b5e2f1
child 637
9c07ef4934dd
equal deleted inserted replaced
366:8c0b6bccfe47 368:0989ad8c0860
1 /* 1 /*
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. 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. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this 7 * published by the Free Software Foundation. Oracle designates this
23 * questions. 23 * questions.
24 */ 24 */
25 25
26 package com.sun.xml.internal.ws.api; 26 package com.sun.xml.internal.ws.api;
27 27
28 import com.sun.istack.internal.NotNull;
29 import com.sun.istack.internal.Nullable;
30 import com.sun.xml.internal.ws.util.ReadOnlyPropertyException;
31
32 import java.lang.reflect.Field;
33 import java.lang.reflect.InvocationTargetException;
34 import java.lang.reflect.Method;
35 import java.security.AccessController;
36 import java.security.PrivilegedAction;
37 import java.util.AbstractMap;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.Map; 28 import java.util.Map;
29 import java.util.Set;
41 import java.util.Map.Entry; 30 import java.util.Map.Entry;
42 import java.util.Set;
43 31
44 /** 32 /**
45 * A set of "properties" that can be accessed via strongly-typed fields 33 * Placeholder for backwards compatibility.
46 * as well as reflexibly through the property name.
47 * 34 *
48 * @author Kohsuke Kawaguchi 35 * @deprecated Use com.oracle.webservices.internal.api.message.PropertySet instead.
36 * @author snajper
49 */ 37 */
50 @SuppressWarnings("SuspiciousMethodCalls") 38 public abstract class PropertySet extends com.oracle.webservices.internal.api.message.BasePropertySet {
51 public abstract class PropertySet implements com.sun.xml.internal.org.jvnet.ws.message.PropertySet {
52
53 /** 39 /**
54 * Creates a new instance of TypedMap. 40 * Represents the list of strongly-typed known properties
55 */
56 protected PropertySet() {}
57
58 /**
59 * Represents the list of strongly-typed known propertyies
60 * (keyed by property names.) 41 * (keyed by property names.)
61 * 42 *
62 * <p> 43 * <p>
63 * Just giving it an alias to make the use of this class more fool-proof. 44 * Just giving it an alias to make the use of this class more fool-proof.
45 * @deprecated
64 */ 46 */
65 protected static final class PropertyMap extends HashMap<String,Accessor> {} 47 protected static class PropertyMap extends com.oracle.webservices.internal.api.message.BasePropertySet.PropertyMap {}
66 48
67 /** 49 /**
68 * Map representing the Fields and Methods annotated with {@link Property}. 50 * @deprecated
69 * Model of {@link PropertySet} class.
70 *
71 * <p>
72 * At the end of the derivation chain this method just needs to be implemented
73 * as:
74 *
75 * <pre>
76 * private static final PropertyMap model;
77 * static {
78 * model = parse(MyDerivedClass.class);
79 * }
80 * protected PropertyMap getPropertyMap() {
81 * return model;
82 * }
83 * </pre>
84 */
85 protected abstract PropertyMap getPropertyMap();
86
87 // maybe we can use this some time
88 ///**
89 // * If all the properties defined on this {@link PropertySet} has a certain prefix
90 // * (such as, say, "javax.xml.ws.http."), then return it.
91 // *
92 // * <p>
93 // * Returning a non-null name from this method allows methods like
94 // * {@link #get(Object)} and {@link #put(String, Object)} to work faster.
95 // * This is especially so with {@link DistributedPropertySet}, so implementations
96 // * are encouraged to set a common prefix, as much as possible.
97 // *
98 // * <p>
99 // * Currently, this is used only by {@link DistributedPropertySet}.
100 // *
101 // * @return
102 // * Null if no such common prefix exists. Otherwise string like
103 // * "javax.xml.ws.http." (the dot at the last is usually preferrable,
104 // * so that properties like "javax.xml.ws.https.something" won't match.
105 // */
106 //protected abstract String getPropertyPrefix();
107
108 /**
109 * This method parses a class for fields and methods with {@link Property}.
110 */ 51 */
111 protected static PropertyMap parse(final Class clazz) { 52 protected static PropertyMap parse(final Class clazz) {
112 // make all relevant fields and methods accessible. 53 com.oracle.webservices.internal.api.message.BasePropertySet.PropertyMap pm = com.oracle.webservices.internal.api.message.BasePropertySet.parse(clazz);
113 // this allows runtime to skip the security check, so they runs faster. 54 PropertyMap map = new PropertyMap();
114 return AccessController.doPrivileged(new PrivilegedAction<PropertyMap>() { 55 map.putAll(pm);
115 public PropertyMap run() { 56 return map;
116 PropertyMap props = new PropertyMap();
117 for( Class c=clazz; c!=null; c=c.getSuperclass()) {
118 for (Field f : c.getDeclaredFields()) {
119 Property cp = f.getAnnotation(Property.class);
120 if(cp!=null) {
121 for(String value : cp.value()) {
122 props.put(value, new FieldAccessor(f, value));
123 }
124 }
125 }
126 for (Method m : c.getDeclaredMethods()) {
127 Property cp = m.getAnnotation(Property.class);
128 if(cp!=null) {
129 String name = m.getName();
130 assert name.startsWith("get") || name.startsWith("is");
131
132 String setName = name.startsWith("is") ? "set"+name.substring(3) : // isFoo -> setFoo
133 's'+name.substring(1); // getFoo -> setFoo
134 Method setter;
135 try {
136 setter = clazz.getMethod(setName,m.getReturnType());
137 } catch (NoSuchMethodException e) {
138 setter = null; // no setter
139 }
140 for(String value : cp.value()) {
141 props.put(value, new MethodAccessor(m, setter, value));
142 }
143 }
144 }
145 }
146
147 return props;
148 }
149 });
150 }
151
152 /**
153 * Represents a typed property defined on a {@link PropertySet}.
154 */
155 protected interface Accessor {
156 String getName();
157 boolean hasValue(PropertySet props);
158 Object get(PropertySet props);
159 void set(PropertySet props, Object value);
160 }
161
162 static final class FieldAccessor implements Accessor {
163 /**
164 * Field with the annotation.
165 */
166 private final Field f;
167
168 /**
169 * One of the values in {@link Property} annotation on {@link #f}.
170 */
171 private final String name;
172
173 protected FieldAccessor(Field f, String name) {
174 this.f = f;
175 f.setAccessible(true);
176 this.name = name;
177 }
178
179 public String getName() {
180 return name;
181 }
182
183 public boolean hasValue(PropertySet props) {
184 return get(props)!=null;
185 }
186
187 public Object get(PropertySet props) {
188 try {
189 return f.get(props);
190 } catch (IllegalAccessException e) {
191 throw new AssertionError();
192 }
193 }
194
195 public void set(PropertySet props, Object value) {
196 try {
197 f.set(props,value);
198 } catch (IllegalAccessException e) {
199 throw new AssertionError();
200 }
201 }
202 }
203
204 static final class MethodAccessor implements Accessor {
205 /**
206 * Getter method.
207 */
208 private final @NotNull Method getter;
209 /**
210 * Setter method.
211 * Some property is read-only.
212 */
213 private final @Nullable Method setter;
214
215 /**
216 * One of the values in {@link Property} annotation on {@link #getter}.
217 */
218 private final String name;
219
220 protected MethodAccessor(Method getter, Method setter, String value) {
221 this.getter = getter;
222 this.setter = setter;
223 this.name = value;
224 getter.setAccessible(true);
225 if(setter!=null)
226 setter.setAccessible(true);
227 }
228
229 public String getName() {
230 return name;
231 }
232
233 public boolean hasValue(PropertySet props) {
234 return get(props)!=null;
235 }
236
237 public Object get(PropertySet props) {
238 try {
239 return getter.invoke(props);
240 } catch (IllegalAccessException e) {
241 throw new AssertionError();
242 } catch (InvocationTargetException e) {
243 handle(e);
244 return 0; // never reach here
245 }
246 }
247
248 public void set(PropertySet props, Object value) {
249 if(setter==null)
250 throw new ReadOnlyPropertyException(getName());
251 try {
252 setter.invoke(props,value);
253 } catch (IllegalAccessException e) {
254 throw new AssertionError();
255 } catch (InvocationTargetException e) {
256 handle(e);
257 }
258 }
259
260 /**
261 * Since we don't expect the getter/setter to throw a checked exception,
262 * it should be possible to make the exception propagation transparent.
263 * That's what we are trying to do here.
264 */
265 private Exception handle(InvocationTargetException e) {
266 Throwable t = e.getTargetException();
267 if(t instanceof Error)
268 throw (Error)t;
269 if(t instanceof RuntimeException)
270 throw (RuntimeException)t;
271 throw new Error(e);
272 }
273 }
274
275
276 public final boolean containsKey(Object key) {
277 return get(key)!=null;
278 } 57 }
279 58
280 /** 59 /**
281 * Gets the name of the property. 60 * Gets the name of the property.
282 * 61 *
314 } else { 93 } else {
315 throw new IllegalArgumentException("Undefined property "+key); 94 throw new IllegalArgumentException("Undefined property "+key);
316 } 95 }
317 } 96 }
318 97
319 /**
320 * Checks if this {@link PropertySet} supports a property of the given name.
321 */
322 public boolean supports(Object key) { 98 public boolean supports(Object key) {
323 return getPropertyMap().containsKey(key); 99 return getPropertyMap().containsKey(key);
324 } 100 }
325 101
326 public Object remove(Object key) { 102 public Object remove(Object key) {
332 } else { 108 } else {
333 throw new IllegalArgumentException("Undefined property "+key); 109 throw new IllegalArgumentException("Undefined property "+key);
334 } 110 }
335 } 111 }
336 112
337 113 protected void createEntrySet(Set<Entry<String,Object>> core) {
338 /**
339 * Lazily created view of {@link Property}s that
340 * forms the core of {@link #createMapView()}.
341 */
342 /*package*/ Set<Entry<String,Object>> mapViewCore;
343
344 /**
345 * Creates a {@link Map} view of this {@link PropertySet}.
346 *
347 * <p>
348 * This map is partially live, in the sense that values you set to it
349 * will be reflected to {@link PropertySet}.
350 *
351 * <p>
352 * However, this map may not pick up changes made
353 * to {@link PropertySet} after the view is created.
354 *
355 * @return
356 * always non-null valid instance.
357 */
358 public final Map<String,Object> createMapView() {
359 final Set<Entry<String,Object>> core = new HashSet<Entry<String,Object>>();
360 createEntrySet(core);
361
362 return new AbstractMap<String, Object>() {
363 public Set<Entry<String,Object>> entrySet() {
364 return core;
365 }
366 };
367 }
368
369 /*package*/ void createEntrySet(Set<Entry<String,Object>> core) {
370 for (final Entry<String, Accessor> e : getPropertyMap().entrySet()) { 114 for (final Entry<String, Accessor> e : getPropertyMap().entrySet()) {
371 core.add(new Entry<String, Object>() { 115 core.add(new Entry<String, Object>() {
372 public String getKey() { 116 public String getKey() {
373 return e.getKey(); 117 return e.getKey();
374 } 118 }
384 return old; 128 return old;
385 } 129 }
386 }); 130 });
387 } 131 }
388 } 132 }
133
134 protected abstract PropertyMap getPropertyMap();
389 } 135 }

mercurial