|
1 /* |
|
2 * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package com.sun.jmx.namespace.serial; |
|
27 |
|
28 |
|
29 import javax.management.ObjectInstance; |
|
30 import javax.management.ObjectName; |
|
31 |
|
32 /** |
|
33 * An object that can rewrite ObjectNames contained in input/output |
|
34 * parameters when entering/leaving a {@link javax.management.namespace |
|
35 * namespace}. |
|
36 * <p>When entering a {@link javax.management.namespace |
|
37 * namespace}, the {@code namespace} prefix is stripped from |
|
38 * ObjectNames contained in input parameters. When leaving a |
|
39 * {@code namespace}, |
|
40 * the {@code namespace} prefix is prepended to the ObjectNames contained in |
|
41 * the result parameters returned from that {@code namespace}. |
|
42 * </p> |
|
43 * <p>Objects that need to perform these operations usually use a |
|
44 * {@code RewritingProcessor} for that purpose.<br> |
|
45 * The {@code RewritingProcessor} allows a somewhat larger |
|
46 * transformation in which part of a prefix {@link #newRewritingProcessor |
|
47 * remove} can be replaced by another prefix {@link #newRewritingProcessor |
|
48 * add}. The transformation described above correspond to the case where |
|
49 * {@code remove} is the stripped {@link javax.management.namespace |
|
50 * namespace} prefix (removed when entering the {@code namespace}) and |
|
51 * {@code add} is the empty String {@code ""}. |
|
52 * <br> |
|
53 * It is interesting to note that {@link |
|
54 * javax.management.JMXNamespaces#narrowToNamespace narrowToNamespace} |
|
55 * operations use the inverse transformation (that is, {@code remove} is |
|
56 * the empty String {@code ""} and {@code add} is the {@link |
|
57 * javax.management.namespace namespace} prefix). |
|
58 * <br> |
|
59 * On a more general scale, {@link #rewriteInput rewriteInput} removes |
|
60 * {@link #newRewritingProcessor remove} and the prepend {@link |
|
61 * #newRewritingProcessor add}, and {@link #rewriteOutput rewriteOutput} |
|
62 * does the opposite, removing {@link #newRewritingProcessor add}, and |
|
63 * then adding {@link #newRewritingProcessor remove}. |
|
64 * <br> |
|
65 * An implementation of {@code RewritingProcessor} should make sure that |
|
66 * <code>rewriteInput(rewriteOutput(x,clp),clp)</code> and |
|
67 * <code>rewriteOutput(rewriteInput(x,clp),clp)</code> always return |
|
68 * {@code x} or an exact clone of {@code x}. |
|
69 * </p> |
|
70 * <p>A default implementation of {@code RewritingProcessor} based on |
|
71 * Java Object Serialization can be |
|
72 * obtained from {@link #newRewritingProcessor newRewritingProcessor}. |
|
73 * </p> |
|
74 * <p> |
|
75 * By default, the instances of {@code RewritingProcessor} returned by |
|
76 * {@link #newRewritingProcessor newRewritingProcessor} will rewrite |
|
77 * ObjectNames contained in instances of classes they don't know about by |
|
78 * serializing and then deserializing such object instances. This will |
|
79 * happen even if such instances don't - or can't contain ObjectNames, |
|
80 * because the default implementation of {@code RewritingProcessor} will |
|
81 * not be able to determine whether instances of such classes can/do contain |
|
82 * instance of ObjectNames before serializing/deserializing them. |
|
83 * </p> |
|
84 * <p>If you are using custom classes that the default implementation of |
|
85 * {@code RewritingProcessor} don't know about, it can be interesting to |
|
86 * prevent an instance of {@code RewritingProcessor} to serialize/deserialize |
|
87 * instances of such classes for nothing. In that case, you could customize |
|
88 * the behavior of such a {@code RewritingProcessor} by wrapping it in a |
|
89 * custom subclass of {@code RewritingProcessor} as shown below: |
|
90 * <pre> |
|
91 * public class MyRewritingProcessor extends RewritingProcessor { |
|
92 * MyRewritingProcessor(String remove, String add) { |
|
93 * this(RewritingProcessor.newRewritingProcessor(remove,add)); |
|
94 * } |
|
95 * MyRewritingProcessor(RewritingProcessor delegate) { |
|
96 * super(delegate); |
|
97 * } |
|
98 * |
|
99 * <T> T rewriteInput(T input) { |
|
100 * if (input == null) return null; |
|
101 * if (MyClass.equals(input.getClass())) { |
|
102 * // I know that MyClass doesn't contain any ObjectName |
|
103 * return (T) input; |
|
104 * } |
|
105 * return super.rewriteInput(input); |
|
106 * } |
|
107 * <T> T rewriteOutput(T result) { |
|
108 * if (result == null) return null; |
|
109 * if (MyClass.equals(result.getClass())) { |
|
110 * // I know that MyClass doesn't contain any ObjectName |
|
111 * return (T) result; |
|
112 * } |
|
113 * return super.rewriteOutput(result); |
|
114 * } |
|
115 * } |
|
116 * </pre> |
|
117 * </p> |
|
118 * <p>Such a subclass may also provide an alternate way of rewriting |
|
119 * custom subclasses for which rewriting is needed - for instance: |
|
120 * <pre> |
|
121 * public class MyRewritingProcessor extends RewritingProcessor { |
|
122 * MyRewritingProcessor(String remove, String add) { |
|
123 * this(RewritingProcessor.newRewritingProcessor(remove,add)); |
|
124 * } |
|
125 * MyRewritingProcessor(RewritingProcessor delegate) { |
|
126 * super(delegate); |
|
127 * } |
|
128 * |
|
129 * <T> T rewriteInput(T input) { |
|
130 * if (input == null) return null; |
|
131 * if (MyClass.equals(input.getClass())) { |
|
132 * // I know that MyClass doesn't contain any ObjectName |
|
133 * return (T) input; |
|
134 * } else if (MyOtherClass.equals(input.getClass())) { |
|
135 * // Returns a new instance in which ObjectNames have been |
|
136 * // replaced. |
|
137 * final ObjectName aname = ((MyOtherClass)input).getName(); |
|
138 * return (T) (new MyOtherClass(super.rewriteInput(aname))); |
|
139 * } |
|
140 * return super.rewriteInput(input,clp); |
|
141 * } |
|
142 * <T> T rewriteOutput(T result) { |
|
143 * if (result == null) return null; |
|
144 * if (MyClass.equals(result.getClass())) { |
|
145 * // I know that MyClass doesn't contain any ObjectName |
|
146 * return (T) result; |
|
147 * } else if (MyOtherClass.equals(result.getClass())) { |
|
148 * // Returns a new instance in which ObjectNames have been |
|
149 * // replaced. |
|
150 * final ObjectName aname = ((MyOtherClass)result).getName(); |
|
151 * return (T) (new MyOtherClass(super.rewriteOutput(aname))); |
|
152 * } |
|
153 * return super.rewriteOutput(result,clp); |
|
154 * } |
|
155 * } |
|
156 * </pre> |
|
157 * </p> |
|
158 * <p>If your application only uses {@link javax.management.MXBean MXBeans}, |
|
159 * or MBeans using simple types, and doesn't define any custom subclass of |
|
160 * {@link javax.management.Notification}, you should never write such |
|
161 * such {@code RewitingProcessor} implementations. |
|
162 * </p> |
|
163 * <p><b> |
|
164 * This API is a Sun internal API and is subject to changes without notice. |
|
165 * </b></p> |
|
166 * @since 1.7 |
|
167 */ |
|
168 public abstract class RewritingProcessor { |
|
169 /** |
|
170 * A logger for this class. |
|
171 **/ |
|
172 private final RewritingProcessor delegate; |
|
173 |
|
174 /** |
|
175 * Creates a new instance of RewritingProcessor. |
|
176 * <p>This is equivalent to calling {@link |
|
177 * #RewritingProcessor(RewritingProcessor) RewritingProcessor(null)}. |
|
178 * </p> |
|
179 **/ |
|
180 protected RewritingProcessor() { |
|
181 this(null); |
|
182 } |
|
183 |
|
184 /** |
|
185 * Creates a new instance of RewritingProcessor, with a delegate. |
|
186 * @param delegate a {@code RewritingProcessor} to which all the |
|
187 * calls will be delegated. When implementing a subclass |
|
188 * of {@code RewritingProcessor}, calling {@link |
|
189 * #rewriteInput super.rewriteInput} will invoke |
|
190 * {@code delegate.rewriteInput} and calling {@link |
|
191 * #rewriteOutput super.rewriteOutput} will invoke |
|
192 * {@code delegate.rewriteOutput}. |
|
193 * |
|
194 **/ |
|
195 protected RewritingProcessor(RewritingProcessor delegate) { |
|
196 this.delegate = delegate; |
|
197 } |
|
198 |
|
199 /** |
|
200 * Rewrites ObjectNames when {@link RewritingProcessor leaving} a {@link |
|
201 * javax.management.namespace namespace}. |
|
202 * <p> |
|
203 * Returns {@code obj}, if it is known that {@code obj} doesn't contain |
|
204 * any ObjectName, or a new copied instance of {@code obj} in which |
|
205 * ObjectNames (if any) will have been rewritten, if {@code obj} contains |
|
206 * ObjectNames, or if it is not known whether {@code obj} contains |
|
207 * ObjectNames or not. |
|
208 * </p> |
|
209 * <p> |
|
210 * The default implementation of this method is as follows: if the |
|
211 * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code |
|
212 * null}, throws an {@link IllegalArgumentException}. Otherwise, |
|
213 * returns {@code delegate.rewriteOutput(obj)}. |
|
214 * </p> |
|
215 * <p>This behavior can be overridden by subclasses as shown in this |
|
216 * class {@link RewritingProcessor description}. |
|
217 * </p> |
|
218 * @param obj The result to be rewritten if needed. |
|
219 * |
|
220 * @return {@code obj}, or a clone of {@code obj} in which ObjectNames |
|
221 * have been rewritten. See this class {@link RewritingProcessor |
|
222 * description} for more details. |
|
223 * @throws IllegalArgumentException if this implementation does not know |
|
224 * how to rewrite the object. |
|
225 **/ |
|
226 public <T> T rewriteOutput(T obj) { |
|
227 if (obj == null) return null; |
|
228 if (delegate != null) |
|
229 return delegate.rewriteOutput(obj); |
|
230 throw new IllegalArgumentException("can't rewrite "+ |
|
231 obj.getClass().getName()); |
|
232 } |
|
233 |
|
234 /** |
|
235 * Rewrites ObjectNames when {@link RewritingProcessor entering} a {@link |
|
236 * javax.management.namespace namespace}. |
|
237 * <p> |
|
238 * Returns {@code obj}, if it is known that {@code obj} doesn't contain |
|
239 * any ObjectName, or a new copied instance of {@code obj} in which |
|
240 * ObjectNames (if any) will have been rewritten, if {@code obj} contains |
|
241 * ObjectNames, or if it is not known whether {@code obj} contains |
|
242 * ObjectNames or not. |
|
243 * </p> |
|
244 * <p> |
|
245 * The default implementation of this method is as follows: if the |
|
246 * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code |
|
247 * null}, throws an {@link IllegalArgumentException}. Otherwise, |
|
248 * returns {@code delegate.rewriteInput(obj)}. |
|
249 * </p> |
|
250 * <p>This behavior can be overridden by subclasses as shown in this |
|
251 * class {@link RewritingProcessor description}. |
|
252 * </p> |
|
253 * @param obj The result to be rewritten if needed. |
|
254 * @return {@code obj}, or a clone of {@code obj} in which ObjectNames |
|
255 * have been rewritten. See this class {@link RewritingProcessor |
|
256 * description} for more details. |
|
257 * @throws IllegalArgumentException if this implementation does not know |
|
258 * how to rewrite the object. |
|
259 **/ |
|
260 public <T> T rewriteInput(T obj) { |
|
261 if (obj == null) return null; |
|
262 if (delegate != null) |
|
263 return delegate.rewriteInput(obj); |
|
264 throw new IllegalArgumentException("can't rewrite "+ |
|
265 obj.getClass().getName()); |
|
266 } |
|
267 |
|
268 /** |
|
269 * Translate a routing ObjectName from the target (calling) context to |
|
270 * the source (called) context when {@link RewritingProcessor entering} a |
|
271 * {@link javax.management.namespace namespace}. |
|
272 * <p> |
|
273 * The default implementation of this method is as follows: if the |
|
274 * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code |
|
275 * null}, throws an {@link IllegalArgumentException}. Otherwise, |
|
276 * returns {@code delegate.toSourceContext(targetName)}. |
|
277 * </p> |
|
278 * <p>This behavior can be overridden by subclasses as shown in this |
|
279 * class {@link RewritingProcessor description}. |
|
280 * </p> |
|
281 * @param targetName The routing target ObjectName to translate. |
|
282 * @return The ObjectName translated to the source context. |
|
283 * @throws IllegalArgumentException if this implementation does not know |
|
284 * how to rewrite the object. |
|
285 **/ |
|
286 public ObjectName toSourceContext(ObjectName targetName) { |
|
287 if (delegate != null) |
|
288 return delegate.toSourceContext(targetName); |
|
289 throw new IllegalArgumentException("can't rewrite targetName: "+ |
|
290 " no delegate."); |
|
291 } |
|
292 |
|
293 /** |
|
294 * Translate an ObjectName returned from the source context into |
|
295 * the target (calling) context when {@link RewritingProcessor leaving} a |
|
296 * {@link javax.management.namespace namespace}. |
|
297 * <p> |
|
298 * The default implementation of this method is as follows: if the |
|
299 * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code |
|
300 * null}, throws an {@link IllegalArgumentException}. Otherwise, |
|
301 * returns {@code delegate.toTargetContext(sourceName)}. |
|
302 * </p> |
|
303 * <p>This behavior can be overridden by subclasses as shown in this |
|
304 * class {@link RewritingProcessor description}. |
|
305 * </p> |
|
306 * @param sourceName The routing source ObjectName to translate to the |
|
307 * target context. |
|
308 * @return The ObjectName translated to the target context. |
|
309 * @throws IllegalArgumentException if this implementation does not know |
|
310 * how to rewrite the object. |
|
311 **/ |
|
312 public ObjectName toTargetContext(ObjectName sourceName) { |
|
313 if (delegate != null) |
|
314 return delegate.toTargetContext(sourceName); |
|
315 throw new IllegalArgumentException("can't rewrite sourceName: "+ |
|
316 " no delegate."); |
|
317 } |
|
318 |
|
319 /** |
|
320 * Translate an ObjectInstance returned from the source context into |
|
321 * the target (calling) context when {@link RewritingProcessor leaving} a |
|
322 * {@link javax.management.namespace namespace}. |
|
323 * <p> |
|
324 * The default implementation of this method is as follows: if the |
|
325 * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code |
|
326 * null}, throws an {@link IllegalArgumentException}. Otherwise, |
|
327 * returns {@code delegate.toTargetContext(sourceMoi)}. |
|
328 * </p> |
|
329 * <p>This behavior can be overridden by subclasses as shown in this |
|
330 * class {@link RewritingProcessor description}. |
|
331 * </p> |
|
332 * @param sourceMoi The routing source ObjectInstance to translate. |
|
333 * @return The ObjectInstance translated to the target context. |
|
334 * @throws IllegalArgumentException if this implementation does not know |
|
335 * how to rewrite the object. |
|
336 **/ |
|
337 public ObjectInstance toTargetContext(ObjectInstance sourceMoi) { |
|
338 if (delegate != null) |
|
339 return delegate.toTargetContext(sourceMoi); |
|
340 throw new IllegalArgumentException("can't rewrite sourceName: "+ |
|
341 " no delegate."); |
|
342 } |
|
343 |
|
344 /** |
|
345 * Creates a new default instance of {@link RewritingProcessor}. |
|
346 * @param remove The prefix to remove from {@link ObjectName ObjectNames} |
|
347 * when {@link RewritingProcessor entering} the {@link |
|
348 * javax.management.namespace namespace}. |
|
349 * @param add The prefix to add to {@link ObjectName ObjectNames} |
|
350 * when {@link RewritingProcessor entering} the {@link |
|
351 * javax.management.namespace namespace} (this is performed |
|
352 * after having removed the {@code remove} prefix. |
|
353 * @return A new {@link RewritingProcessor} processor object that will |
|
354 * perform the requested operation, using Java serialization if |
|
355 * necessary. |
|
356 **/ |
|
357 public static RewritingProcessor newRewritingProcessor(String remove, |
|
358 String add) { |
|
359 return new DefaultRewritingProcessor(remove,add); |
|
360 } |
|
361 |
|
362 } |