jdk/src/share/classes/javax/management/namespace/JMXNamespaceView.java
changeset 1156 bbc2d15aaf7a
equal deleted inserted replaced
1155:a9a142fcf1b5 1156:bbc2d15aaf7a
       
     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 javax.management.namespace;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.util.Set;
       
    30 import javax.management.MBeanServer;
       
    31 import javax.management.MBeanServerConnection;
       
    32 import javax.management.MalformedObjectNameException;
       
    33 import javax.management.ObjectName;
       
    34 
       
    35 /**
       
    36  * This class makes it possible to navigate easily within a hierarchical
       
    37  * namespace view.
       
    38  *
       
    39  * <pre>
       
    40  * MBeanServerConnnection rootConnection = ...;
       
    41  *
       
    42  * // create a view at the local root of the namespace hierarchy.
       
    43  * //
       
    44  * JMXNamespaceView view = new JMXNamespaceView(rootConnection);
       
    45  *
       
    46  * // list all top level namespaces
       
    47  * String[] list = view.list();
       
    48  *
       
    49  * // select one namespace from the list
       
    50  * String whereToGo = ... ;
       
    51  *
       
    52  * // go down to the selected namespace:
       
    53  * view = view.down(whereToGo);
       
    54  * System.out.println("I am now in: " + view.where());
       
    55  * System.out.println("I can see these MBeans:" +
       
    56  *    view.getMBeanServerConnection().queryNames(null,null));
       
    57  *
       
    58  * // list sub namespaces in current view ('whereToGo')
       
    59  * list = view.list();
       
    60  * System.out.println("Here are the sub namespaces of "+view.where()+": "+
       
    61  *                    Arrays.toString(list));
       
    62  *
       
    63  * // go up one level
       
    64  * view = view.up();
       
    65  * System.out.println("I am now back to: " +
       
    66  *    (view.isRoot() ? "root namespace" : view.where()));
       
    67  * </pre>
       
    68  * @since 1.7
       
    69  */
       
    70 public class JMXNamespaceView {
       
    71 
       
    72     private static final ObjectName ALL_NAMESPACES;
       
    73     static {
       
    74         try {
       
    75             ALL_NAMESPACES = ObjectName.getInstance("*" +
       
    76                     JMXNamespaces.NAMESPACE_SEPARATOR + ":"+
       
    77                     JMXNamespace.TYPE_ASSIGNMENT);
       
    78         } catch (MalformedObjectNameException x) {
       
    79             throw new ExceptionInInitializerError(x);
       
    80         }
       
    81     }
       
    82     private static final int NAMESPACE_SEPARATOR_LENGTH =
       
    83             JMXNamespaces.NAMESPACE_SEPARATOR.length();
       
    84 
       
    85     private final JMXNamespaceView parent;
       
    86     private final MBeanServerConnection here;
       
    87     private final String where;
       
    88 
       
    89     private static MBeanServerConnection checkRoot(MBeanServerConnection root) {
       
    90         if (root == null)
       
    91             throw new IllegalArgumentException(
       
    92                     "namespaceRoot: null is not a valid value");
       
    93         return root;
       
    94     }
       
    95 
       
    96     /**
       
    97      * Creates a view at the top of a JMX namespace hierarchy.
       
    98      * @param namespaceRoot The {@code MBeanServerConnection} at the
       
    99      *        top of the hierarchy.
       
   100      */
       
   101     public JMXNamespaceView(MBeanServerConnection namespaceRoot) {
       
   102         this(null,checkRoot(namespaceRoot),"");
       
   103     }
       
   104 
       
   105     // This constructor should remain private. A user can only create
       
   106     // JMXNamespaceView at the top of the hierarchy.
       
   107     // JMXNamespaceView sub nodes are created by their parent nodes.
       
   108     private JMXNamespaceView(JMXNamespaceView parent,
       
   109             MBeanServerConnection here, String where) {
       
   110         this.parent = parent;
       
   111         this.here   = here;
       
   112         this.where  = where;
       
   113     }
       
   114 
       
   115     /**
       
   116      * Returns the path leading to the namespace in this view, from
       
   117      * the top of the hierarchy.
       
   118      * @return The path to the namespace in this view.
       
   119      */
       
   120     public String where() {
       
   121         return where;
       
   122     }
       
   123 
       
   124     /**
       
   125      * Lists all direct sub namespaces in this view.  The returned strings
       
   126      * do not contain the {@code //} separator.
       
   127      *
       
   128      * @return A list of direct sub name spaces accessible from this
       
   129      *         namespace.
       
   130      * @throws IOException if the attempt to list the namespaces fails because
       
   131      * of a communication problem.
       
   132      */
       
   133     public String[] list() throws IOException {
       
   134         final Set<ObjectName> names =
       
   135                 here.queryNames(ALL_NAMESPACES,null);
       
   136         final String[] res = new String[names.size()];
       
   137         int i = 0;
       
   138         for (ObjectName dirName : names) {
       
   139             final String dir = dirName.getDomain();
       
   140             res[i++]=dir.substring(0,dir.length()-NAMESPACE_SEPARATOR_LENGTH);
       
   141         }
       
   142         return res;
       
   143     }
       
   144 
       
   145     /**
       
   146      * Go down into a sub namespace.
       
   147      * @param namespace the namespace to go down to.  It can contain one or
       
   148      * more {@code //} separators, to traverse intermediate namespaces, but
       
   149      * it must not begin or end with {@code //} or contain an empty
       
   150      * intermediate namespace.  If it is the empty string, then {@code this} is
       
   151      * returned.
       
   152      * @return A view of the named sub namespace.
       
   153      * @throws IllegalArgumentException if the {@code namespace} begins or
       
   154      * ends with {@code //}.
       
   155      */
       
   156     public JMXNamespaceView down(String namespace) {
       
   157         if (namespace.equals("")) return this;
       
   158         if (namespace.startsWith(JMXNamespaces.NAMESPACE_SEPARATOR))
       
   159             throw new IllegalArgumentException(namespace+": can't start with "+
       
   160                     JMXNamespaces.NAMESPACE_SEPARATOR);
       
   161 
       
   162         // This is a convenience to handle paths like xxx//yyy
       
   163         final String[] elts =
       
   164                 namespace.split(JMXNamespaces.NAMESPACE_SEPARATOR);
       
   165 
       
   166         // Go down the path, creating all sub namespaces along the way.
       
   167         // Usually there will be a single element in the given namespace
       
   168         // name, but we don't want to forbid things like
       
   169         // down("xxx//yyy/www");
       
   170         //
       
   171         JMXNamespaceView previous = this;
       
   172         String cursor = where;
       
   173         for (String elt : elts) {
       
   174             // empty path elements are not allowed. It means we
       
   175             // had something like "xxx////yyy"
       
   176             if (elt.equals(""))
       
   177                 throw new IllegalArgumentException(namespace+
       
   178                         ": invalid path element");
       
   179 
       
   180             // compute the "where" for the child.
       
   181             cursor = JMXNamespaces.concat(cursor, elt);
       
   182 
       
   183             // create the child...
       
   184             final JMXNamespaceView next =
       
   185                     makeJMXNamespaceView(root(), previous, cursor);
       
   186 
       
   187             // the current child will be the parent of the next child...
       
   188             previous = next;
       
   189         }
       
   190 
       
   191         // We return the last child that was created.
       
   192         return previous;
       
   193     }
       
   194 
       
   195     /**
       
   196      * Go back up one level. If this view is at the root of the
       
   197      * hierarchy, returns {@code null}.
       
   198      * @return A view of the parent namespace, or {@code null} if we're at
       
   199      *         the root of the hierarchy.
       
   200      */
       
   201     public JMXNamespaceView up() {
       
   202         return parent;
       
   203     }
       
   204 
       
   205     /**
       
   206      * Tells whether this view is at the root of the hierarchy.
       
   207      * @return {@code true} if this view is at the root of the hierachy.
       
   208      */
       
   209     public boolean isRoot() {
       
   210         return parent == null;
       
   211     }
       
   212 
       
   213     /**
       
   214      * Returns the view at the root of the hierarchy.
       
   215      * If we are already at the root, this is {@code this}.
       
   216      * @return the view at the root of the hierarchy.
       
   217      */
       
   218     public JMXNamespaceView root() {
       
   219         if (parent == null) return this;
       
   220         return parent.root();
       
   221     }
       
   222 
       
   223     /**
       
   224      * A MBeanServerConnection to the namespace shown by this view.
       
   225      * This is what would have been obtained by doing:
       
   226      * <pre>
       
   227      *   JMX.narrowToNamespace(this.root().getMBeanServerConnection(),
       
   228      *       this.where());
       
   229      * </pre>
       
   230      * @return A MBeanServerConnection to the namespace shown by this view.
       
   231      */
       
   232     public MBeanServerConnection getMBeanServerConnection() {
       
   233         return here;
       
   234     }
       
   235 
       
   236     /**
       
   237      * <p>Get the name of the JMXNamespaceMBean handling the namespace shown by
       
   238      * this view, relative to the root of the hierarchy.  If we are at the root
       
   239      * of the hierarchy, this method returns {@code null}.</p>
       
   240      *
       
   241      * <p>You can use this method to make a proxy for the JMXNamespaceMBean
       
   242      * as follows:</p>
       
   243      *
       
   244      * <pre>
       
   245      * JMXNamespaceView view = ...;
       
   246      * ObjectName namespaceMBeanName = view.getJMXNamespaceMBeanName();
       
   247      * JMXNamespaceMBean namespaceMBean = JMX.newMBeanProxy(
       
   248      *     view.root().getMBeanServerConnection(), namespaceMBeanName,
       
   249      *     JMXNamespaceMBean.class);
       
   250      * </pre>
       
   251      *
       
   252      * @return The name of the {@code JMXNamespaceMBean} handling the namespace
       
   253      *         shown by this view, or {@code null}.
       
   254      */
       
   255     public ObjectName getJMXNamespaceMBeanName() {
       
   256         if (parent == null)
       
   257             return null;
       
   258         else
       
   259             return JMXNamespaces.getNamespaceObjectName(where);
       
   260     }
       
   261 
       
   262     @Override
       
   263     public int hashCode() {
       
   264         return where.hashCode();
       
   265     }
       
   266 
       
   267     /**
       
   268      * Returns true if this object is equal to the given object.  The
       
   269      * two objects are equal if the other object is also a {@code
       
   270      * JMXNamespaceView} and both objects have the same {@linkplain #root root}
       
   271      * MBeanServerConnection and the same {@linkplain #where path}.
       
   272      * @param o the other object to compare to.
       
   273      * @return true if both objects are equal.
       
   274      */
       
   275     @Override
       
   276     public boolean equals(Object o) {
       
   277         if (o==this) return true;
       
   278         if (! (o instanceof JMXNamespaceView)) return false;
       
   279         if (!where.equals(((JMXNamespaceView)o).where)) return false;
       
   280         return root().getMBeanServerConnection().equals(
       
   281                 ((JMXNamespaceView)o).root().getMBeanServerConnection());
       
   282     }
       
   283 
       
   284     private JMXNamespaceView makeJMXNamespaceView(final JMXNamespaceView root,
       
   285             final JMXNamespaceView directParent, final String pathFromRoot) {
       
   286         if (pathFromRoot.equals("")) return root;
       
   287 
       
   288         return new JMXNamespaceView(directParent,
       
   289                 narrowToNamespace(root.getMBeanServerConnection(),
       
   290                 pathFromRoot),pathFromRoot);
       
   291     }
       
   292 
       
   293     private MBeanServerConnection narrowToNamespace(MBeanServerConnection root,
       
   294             String path) {
       
   295         if (root instanceof MBeanServer)
       
   296             return JMXNamespaces.narrowToNamespace((MBeanServer)root, path);
       
   297         return JMXNamespaces.narrowToNamespace(root, path);
       
   298     }
       
   299 
       
   300 }