1 | package org.dcache.util; |
2 | |
3 | import java.util.Collections; |
4 | import java.util.Enumeration; |
5 | import java.util.Iterator; |
6 | import java.util.Properties; |
7 | import java.util.Set; |
8 | |
9 | import org.slf4j.Logger; |
10 | import org.slf4j.LoggerFactory; |
11 | |
12 | /** |
13 | * ReplaceableProperties that allows properties to be annotated as |
14 | * deprecated, obsolete or forbidden. A property is annotated as deprecated |
15 | * by prefixing the declaration with <code>(deprecated)</code>, as obsolete |
16 | * by prefixing the declaration with <code>(obsolete)</code>, and forbidden |
17 | * by prefixing it <code>(forbidden)</code>. |
18 | * |
19 | * These annotations have the following semantics: |
20 | * <ul> |
21 | * <li><i>deprecated</i> indicates that a property is supported but that a |
22 | * future version of dCache will likely remove that support. |
23 | * <li><i>obsolete</i> indicates that a property is no longer supported and |
24 | * that dCache will always behaves correctly without supporting this |
25 | * property. |
26 | * <li><i>forbidden</i> indicates that a property is no longer supported and |
27 | * dCache does not always behave correctly without further configuration or |
28 | * that support for some feature has been removed. |
29 | * </ul> |
30 | * <p> |
31 | * The intended behaviour of dCache when encountering sysadmin-supplied |
32 | * property assignment of some annotated property is dependent on the |
33 | * annotation. For deprecated and obsolete properties, a warning is emitted |
34 | * and dCache continues to start up. If the user assigns a value to a |
35 | * forbidden properties then dCache will refuse to start. |
36 | * <p> |
37 | * Such a declaration only affects following declarations. It does not affect |
38 | * any previous declarations of this property, nor does it generate any |
39 | * errors when such properties are referenced in any way. |
40 | */ |
41 | public class DeprecatableProperties extends ReplaceableProperties { |
42 | private static final long serialVersionUID = -5684848160314570455L; |
43 | |
44 | private final static Logger _log = |
45 | LoggerFactory.getLogger( DeprecatableProperties.class); |
46 | |
47 | private final static String FORBIDDEN = "(forbidden)"; |
48 | private final static String OBSOLETE = "(obsolete)"; |
49 | private final static String DEPRECATED = "(deprecated)"; |
50 | |
51 | public DeprecatableProperties(Properties properties) |
52 | { |
53 | super(properties); |
54 | } |
55 | |
56 | public boolean isForbidden(String key) |
57 | { |
58 | return getProperty(FORBIDDEN + key) != null; |
59 | } |
60 | |
61 | public boolean isObsolete(String key) |
62 | { |
63 | return getProperty(OBSOLETE + key) != null; |
64 | } |
65 | |
66 | public boolean isDeprecated(String key) |
67 | { |
68 | return getProperty(DEPRECATED + key) != null; |
69 | } |
70 | |
71 | @Override |
72 | public synchronized Object put(Object key, Object value) |
73 | { |
74 | String s = key.toString(); |
75 | actOnAnnotation(s); |
76 | if( isDeprecatedDeclaration(s)) { |
77 | super.put(s.substring(DEPRECATED.length()), value); |
78 | } |
79 | return super.put(key, value); |
80 | } |
81 | |
82 | private void actOnAnnotation(String key) |
83 | { |
84 | if( isForbidden( key)) { |
85 | String error = errorForForbiddenProperty( key); |
86 | throw new IllegalArgumentException( error); |
87 | } |
88 | |
89 | if( isObsolete( key)) { |
90 | _log.warn( "The property {} is no longer used.", key); |
91 | } else if( isDeprecated( key)) { |
92 | _log.warn( "The property {} is deprecated and will be removed.", key); |
93 | } |
94 | } |
95 | |
96 | private String errorForForbiddenProperty(String property) |
97 | { |
98 | String error = getProperty( FORBIDDEN + property); |
99 | |
100 | if( error.isEmpty()) { |
101 | error = "Adjusting property " + property + " is forbidden as different properties now control this aspect of dCache."; |
102 | } |
103 | |
104 | return error; |
105 | } |
106 | |
107 | @Override |
108 | public Enumeration<?> propertyNames() |
109 | { |
110 | return Collections.enumeration(stringPropertyNames()); |
111 | } |
112 | |
113 | @Override |
114 | public Set<String> stringPropertyNames() |
115 | { |
116 | Set<String> names = super.stringPropertyNames(); |
117 | Iterator<String> i = names.iterator(); |
118 | while (i.hasNext()) { |
119 | String name = i.next(); |
120 | if( isAnnotatedDeclaration(name)) { |
121 | i.remove(); |
122 | } |
123 | } |
124 | return names; |
125 | } |
126 | |
127 | private boolean isDeprecatedDeclaration(String name) |
128 | { |
129 | return name.startsWith(DEPRECATED); |
130 | } |
131 | |
132 | private boolean isAnnotatedDeclaration(String name) |
133 | { |
134 | boolean isDeprecated = isDeprecatedDeclaration( name); |
135 | |
136 | boolean isForbidden = name.startsWith(FORBIDDEN); |
137 | boolean isObsolete = name.startsWith(OBSOLETE); |
138 | |
139 | return isForbidden || isDeprecated || isObsolete; |
140 | } |
141 | } |