jdk/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java
changeset 4159 9e3aae7675f1
parent 4158 0b4d21bc8b5c
parent 4156 acaa49a2768a
child 4160 bda0a85afcb7
equal deleted inserted replaced
4158:0b4d21bc8b5c 4159:9e3aae7675f1
     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 }