1 /*
   2  * Copyright (c) 1998, 2012, 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 
  27 package com.sun.jmx.snmp.daemon;
  28 
  29 
  30 
  31 // java imports
  32 //
  33 import java.util.Vector;
  34 import java.util.Enumeration;
  35 
  36 // jmx imports
  37 //
  38 import com.sun.jmx.snmp.SnmpOid;
  39 
  40 // SNMP Runtime imports
  41 //
  42 import com.sun.jmx.snmp.agent.SnmpMibAgent;
  43 
  44 /**
  45  * The class is used for building a tree representation of the different
  46  * root oids of the supported MIBs. Each node is associated to a specific MIB.
  47  */
  48 final class SnmpMibTree {
  49 
  50     public SnmpMibTree() {
  51       defaultAgent= null;
  52       root= new TreeNode(-1, null, null);
  53     }
  54 
  55     public void setDefaultAgent(SnmpMibAgent def) {
  56         defaultAgent= def;
  57         root.agent= def;
  58     }
  59 
  60     public SnmpMibAgent getDefaultAgent() {
  61         return defaultAgent;
  62     }
  63 
  64     public void register(SnmpMibAgent agent) {
  65         root.registerNode(agent);
  66     }
  67 
  68     public void register(SnmpMibAgent agent, long[] oid) {
  69       root.registerNode(oid, 0, agent);
  70     }
  71 
  72     public SnmpMibAgent getAgentMib(SnmpOid oid) {
  73         TreeNode node= root.retrieveMatchingBranch(oid.longValue(), 0);
  74         if (node == null)
  75             return defaultAgent;
  76         else
  77             if(node.getAgentMib() == null)
  78                 return defaultAgent;
  79             else
  80                 return node.getAgentMib();
  81     }
  82 
  83     public void unregister(SnmpMibAgent agent, SnmpOid[] oids) {
  84         for(int i = 0; i < oids.length; i++) {
  85             long[] oid = oids[i].longValue();
  86             TreeNode node = root.retrieveMatchingBranch(oid, 0);
  87             if (node == null)
  88                 continue;
  89             node.removeAgent(agent);
  90         }
  91     }
  92 
  93 
  94     public void unregister(SnmpMibAgent agent) {
  95 
  96         root.removeAgentFully(agent);
  97     }
  98 
  99     /*
 100     public void unregister(SnmpMibAgent agent) {
 101         long[] oid= agent.getRootOid();
 102         TreeNode node= root.retrieveMatchingBranch(oid, 0);
 103         if (node == null)
 104             return;
 105         node.removeAgent(agent);
 106     }
 107     */
 108     public void printTree() {
 109         root.printTree(">");
 110     }
 111 
 112     private SnmpMibAgent defaultAgent;
 113     private TreeNode root;
 114 
 115     // A SnmpMibTree object is a tree of TreeNode
 116     //
 117     final class TreeNode {
 118 
 119         void registerNode(SnmpMibAgent agent) {
 120             long[] oid= agent.getRootOid();
 121             registerNode(oid, 0, agent);
 122         }
 123 
 124         TreeNode retrieveMatchingBranch(long[] oid, int cursor) {
 125             TreeNode node= retrieveChild(oid, cursor);
 126             if (node == null)
 127                 return this;
 128             if (children.isEmpty()) {
 129                 // In this case, the node does not have any children. So no point to
 130                 // continue the search ...
 131                 return node;
 132             }
 133             if( cursor + 1 == oid.length) {
 134                 // In this case, the oid does not have any more element. So the search
 135                 // is over.
 136                 return node;
 137             }
 138 
 139             TreeNode n = node.retrieveMatchingBranch(oid, cursor + 1);
 140             //If the returned node got a null agent, we have to replace it by
 141             //the current one (in case it is not null)
 142             //
 143             return n.agent == null ? this : n;
 144         }
 145 
 146         SnmpMibAgent getAgentMib() {
 147             return agent;
 148         }
 149 
 150         public void printTree(String ident) {
 151 
 152             StringBuilder buff= new StringBuilder();
 153             if (agents == null) {
 154                 return;
 155             }
 156 
 157             for(Enumeration<SnmpMibAgent> e= agents.elements(); e.hasMoreElements(); ) {
 158                 SnmpMibAgent mib= e.nextElement();
 159                 if (mib == null)
 160                     buff.append("empty ");
 161                 else
 162                     buff.append(mib.getMibName()).append(" ");
 163             }
 164             ident+= " ";
 165             if (children == null) {
 166                 return;
 167             }
 168             for(Enumeration<TreeNode> e= children.elements(); e.hasMoreElements(); ) {
 169                 TreeNode node= e.nextElement();
 170                 node.printTree(ident);
 171             }
 172         }
 173 
 174         // PRIVATE STUFF
 175         //--------------
 176 
 177         /**
 178          * Only the treeNode class can create an instance of treeNode.
 179          * The creation occurs when registering a new oid.
 180          */
 181         private TreeNode(long nodeValue, SnmpMibAgent agent, TreeNode sup) {
 182             this.nodeValue= nodeValue;
 183             this.parent= sup;
 184             agents.addElement(agent);
 185         }
 186 
 187         private void removeAgentFully(SnmpMibAgent agent) {
 188             Vector<TreeNode> v = new Vector<>();
 189             for(Enumeration<TreeNode> e= children.elements();
 190                 e.hasMoreElements(); ) {
 191 
 192                 TreeNode node= e.nextElement();
 193                 node.removeAgentFully(agent);
 194                 if(node.agents.isEmpty())
 195                     v.add(node);
 196 
 197             }
 198             for(Enumeration<TreeNode> e= v.elements(); e.hasMoreElements(); ) {
 199                 children.removeElement(e.nextElement());
 200             }
 201             removeAgent(agent);
 202 
 203         }
 204 
 205         private void removeAgent(SnmpMibAgent mib) {
 206             if (!agents.contains(mib))
 207                 return;
 208             agents.removeElement(mib);
 209 
 210             if (!agents.isEmpty())
 211                 agent= agents.firstElement();
 212 
 213         }
 214 
 215         private void setAgent(SnmpMibAgent agent) {
 216             this.agent = agent;
 217         }
 218 
 219         private void registerNode(long[] oid, int cursor, SnmpMibAgent agent) {
 220 
 221             if (cursor >= oid.length)
 222                 //That's it !
 223                 //
 224                 return;
 225             TreeNode child = retrieveChild(oid, cursor);
 226             if (child == null) {
 227                 // Create a child and register it !
 228                 //
 229                 long theValue= oid[cursor];
 230                 child= new TreeNode(theValue, agent, this);
 231                 children.addElement(child);
 232             }
 233             else
 234                 if (agents.contains(agent) == false) {
 235                     agents.addElement(agent);
 236                 }
 237 
 238             // We have to set the agent attribute
 239             //
 240             if(cursor == (oid.length - 1)) {
 241               child.setAgent(agent);
 242             }
 243             else
 244               child.registerNode(oid, cursor+1, agent);
 245         }
 246 
 247         private TreeNode retrieveChild(long[] oid, int current) {
 248             long theValue= oid[current];
 249 
 250             for(Enumeration<TreeNode> e= children.elements(); e.hasMoreElements(); ) {
 251                 TreeNode node= e.nextElement();
 252                 if (node.match(theValue))
 253                     return node;
 254             }
 255             return null;
 256         }
 257 
 258         private boolean match(long value) {
 259             return (nodeValue == value) ? true : false;
 260         }
 261 
 262         private Vector<TreeNode> children= new Vector<>();
 263         private Vector<SnmpMibAgent> agents= new Vector<>();
 264         private long nodeValue;
 265         private SnmpMibAgent agent;
 266         private TreeNode parent;
 267 
 268     }; // end of class TreeNode
 269 }