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

Print this page


   1 /*
   2  * Copyright (c) 1997, 2010, 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.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;
  41 import java.util.Map.Entry;
  42 import java.util.Set;

  43 
  44 /**
  45  * A set of "properties" that can be accessed via strongly-typed fields
  46  * as well as reflexibly through the property name.
  47  *
  48  * @author Kohsuke Kawaguchi
  49  */
  50 @SuppressWarnings("SuspiciousMethodCalls")
  51 public abstract class PropertySet implements com.sun.xml.internal.org.jvnet.ws.message.PropertySet {
  52 
  53     /**
  54      * Creates a new instance of TypedMap.
  55      */
  56     protected PropertySet() {}
  57 
  58     /**
  59      * Represents the list of strongly-typed known propertyies
  60      * (keyed by property names.)
  61      *
  62      * <p>
  63      * Just giving it an alias to make the use of this class more fool-proof.

  64      */
  65     protected static final class PropertyMap extends HashMap<String,Accessor> {}
  66 
  67     /**
  68      * Map representing the Fields and Methods annotated with {@link Property}.
  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      */
 111     protected static PropertyMap parse(final Class clazz) {
 112         // make all relevant fields and methods accessible.
 113         // this allows runtime to skip the security check, so they runs faster.
 114         return AccessController.doPrivileged(new PrivilegedAction<PropertyMap>() {
 115             public PropertyMap run() {
 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     }
 279 
 280     /**
 281      * Gets the name of the property.
 282      *
 283      * @param key
 284      *      This field is typed as {@link Object} to follow the {@link Map#get(Object)}
 285      *      convention, but if anything but {@link String} is passed, this method
 286      *      just returns null.
 287      */
 288     public Object get(Object key) {
 289         Accessor sp = getPropertyMap().get(key);
 290         if(sp!=null)
 291             return sp.get(this);
 292         throw new IllegalArgumentException("Undefined property "+key);
 293     }
 294 
 295     /**
 296      * Sets a property.
 297      *


 299      * This method is slow. Code inside JAX-WS should define strongly-typed
 300      * fields in this class and access them directly, instead of using this.
 301      *
 302      * @throws ReadOnlyPropertyException
 303      *      if the given key is an alias of a strongly-typed field,
 304      *      and if the name object given is not assignable to the field.
 305      *
 306      * @see Property
 307      */
 308     public Object put(String key, Object value) {
 309         Accessor sp = getPropertyMap().get(key);
 310         if(sp!=null) {
 311             Object old = sp.get(this);
 312             sp.set(this,value);
 313             return old;
 314         } else {
 315             throw new IllegalArgumentException("Undefined property "+key);
 316         }
 317     }
 318 
 319     /**
 320      * Checks if this {@link PropertySet} supports a property of the given name.
 321      */
 322     public boolean supports(Object key) {
 323         return getPropertyMap().containsKey(key);
 324     }
 325 
 326     public Object remove(Object key) {
 327         Accessor sp = getPropertyMap().get(key);
 328         if(sp!=null) {
 329             Object old = sp.get(this);
 330             sp.set(this,null);
 331             return old;
 332         } else {
 333             throw new IllegalArgumentException("Undefined property "+key);
 334         }
 335     }
 336 
 337 
 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()) {
 371             core.add(new Entry<String, Object>() {
 372                 public String getKey() {
 373                     return e.getKey();
 374                 }
 375 
 376                 public Object getValue() {
 377                     return e.getValue().get(PropertySet.this);
 378                 }
 379 
 380                 public Object setValue(Object value) {
 381                     Accessor acc = e.getValue();
 382                     Object old = acc.get(PropertySet.this);
 383                     acc.set(PropertySet.this,value);
 384                     return old;
 385                 }
 386             });
 387         }
 388     }


 389 }
   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  */
  25 
  26 package com.sun.xml.internal.ws.api;
  27 












  28 import java.util.Map;

  29 import java.util.Set;
  30 import java.util.Map.Entry;
  31 
  32 /**
  33  * Placeholder for backwards compatibility.

  34  *
  35  * @deprecated Use com.oracle.webservices.internal.api.message.PropertySet instead.
  36  * @author snajper





  37  */
  38 public abstract class PropertySet extends com.oracle.webservices.internal.api.message.BasePropertySet {

  39     /**
  40      * Represents the list of strongly-typed known properties
  41      * (keyed by property names.)
  42      *
  43      * <p>
  44      * Just giving it an alias to make the use of this class more fool-proof.
  45      * @deprecated
  46      */
  47     protected static class PropertyMap extends com.oracle.webservices.internal.api.message.BasePropertySet.PropertyMap {}









































  48 
  49     /**
  50      * @deprecated
  51      */
  52     protected static PropertyMap parse(final Class clazz) {
  53         com.oracle.webservices.internal.api.message.BasePropertySet.PropertyMap pm = com.oracle.webservices.internal.api.message.BasePropertySet.parse(clazz);
  54         PropertyMap map = new PropertyMap();
  55         map.putAll(pm);
  56         return map;


































































































































































  57     }
  58 
  59     /**
  60      * Gets the name of the property.
  61      *
  62      * @param key
  63      *      This field is typed as {@link Object} to follow the {@link Map#get(Object)}
  64      *      convention, but if anything but {@link String} is passed, this method
  65      *      just returns null.
  66      */
  67     public Object get(Object key) {
  68         Accessor sp = getPropertyMap().get(key);
  69         if(sp!=null)
  70             return sp.get(this);
  71         throw new IllegalArgumentException("Undefined property "+key);
  72     }
  73 
  74     /**
  75      * Sets a property.
  76      *


  78      * This method is slow. Code inside JAX-WS should define strongly-typed
  79      * fields in this class and access them directly, instead of using this.
  80      *
  81      * @throws ReadOnlyPropertyException
  82      *      if the given key is an alias of a strongly-typed field,
  83      *      and if the name object given is not assignable to the field.
  84      *
  85      * @see Property
  86      */
  87     public Object put(String key, Object value) {
  88         Accessor sp = getPropertyMap().get(key);
  89         if(sp!=null) {
  90             Object old = sp.get(this);
  91             sp.set(this,value);
  92             return old;
  93         } else {
  94             throw new IllegalArgumentException("Undefined property "+key);
  95         }
  96     }
  97 



  98     public boolean supports(Object key) {
  99         return getPropertyMap().containsKey(key);
 100     }
 101 
 102     public Object remove(Object key) {
 103         Accessor sp = getPropertyMap().get(key);
 104         if(sp!=null) {
 105             Object old = sp.get(this);
 106             sp.set(this,null);
 107             return old;
 108         } else {
 109             throw new IllegalArgumentException("Undefined property "+key);
 110         }
 111     }
 112 
 113     protected void createEntrySet(Set<Entry<String,Object>> core) {
































 114         for (final Entry<String, Accessor> e : getPropertyMap().entrySet()) {
 115             core.add(new Entry<String, Object>() {
 116                 public String getKey() {
 117                     return e.getKey();
 118                 }
 119 
 120                 public Object getValue() {
 121                     return e.getValue().get(PropertySet.this);
 122                 }
 123 
 124                 public Object setValue(Object value) {
 125                     Accessor acc = e.getValue();
 126                     Object old = acc.get(PropertySet.this);
 127                     acc.set(PropertySet.this,value);
 128                     return old;
 129                 }
 130             });
 131         }
 132     }
 133 
 134     protected abstract PropertyMap getPropertyMap();
 135 }