001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.metadata;
023:
024: import javax.management.MBeanAttributeInfo;
025: import javax.management.MBeanInfo;
026: import javax.management.MBeanOperationInfo;
027: import javax.management.MBeanParameterInfo;
028:
029: /**
030: * AttributeOperationResolver is a modified TST for mapping an Integer code against attribute and operation keys.
031: *
032: * Note that this implementation was chosen to allow fast resolution of compound keys - namely the
033: * operationName and signature[] passed to an MBean's invoke() method. For consistency it also
034: * keeps track of attribute names (which are a single key), although for those a hashmap would
035: * have done just as well.
036: *
037: * @author <a href="mailto:trevor@protocool.com">Trevor Squires</a>.
038: */
039: public class AttributeOperationResolver {
040: private Node opRoot = null;
041: private Node atRoot = null;
042:
043: /**
044: * Default constructor.
045: */
046: public AttributeOperationResolver() {
047: }
048:
049: /**
050: * Uses the AttributeInfo and OperationInfo arrays in the MBeanInfo to configure the
051: * resolver. Each attribute and operation will be assigned a code which corresponds
052: * to it's position in the info array.
053: */
054: public AttributeOperationResolver(MBeanInfo info) {
055: this (info.getAttributes(), info.getOperations());
056: }
057:
058: /**
059: * Uses the AttributeInfo and OperationInfo arrays to configure the resolver.
060: * Each attribute and operation will be assigned a code which corresponds to it's
061: * position in the info array.
062: */
063: public AttributeOperationResolver(MBeanAttributeInfo[] attributes,
064: MBeanOperationInfo[] operations) {
065: int attributeCount = (attributes != null) ? attributes.length
066: : 0;
067: for (int i = 0; i < attributeCount; i++) {
068: store(attributes[i].getName(), new Integer(i));
069: }
070:
071: int operationCount = (operations != null) ? operations.length
072: : 0;
073: for (int i = 0; i < operationCount; i++) {
074: MBeanOperationInfo operation = operations[i];
075: MBeanParameterInfo[] params = operation.getSignature();
076: String[] signature = new String[params.length];
077: for (int j = 0; j < signature.length; j++) {
078: signature[j] = params[j].getType();
079: }
080: store(operation.getName(), signature, new Integer(i));
081: }
082: }
083:
084: public Integer lookup(String actionName, String[] signature) {
085: String word = actionName;
086: int wordh = word.hashCode();
087: int wordpos = -1;
088: int maxword = (signature != null) ? signature.length : 0;
089:
090: Node node = opRoot;
091: Integer rval = null;
092: OUTER_NODE: while (node != null) {
093: if (wordh < node.hash) {
094: node = node.loKid;
095: } else if (wordh > node.hash) {
096: node = node.hiKid;
097: } else {
098: for (int i = node.eqKid.length - 1; i > -1; i--) {
099: if (word.equals(node.eqKid[i].val)) {
100: if (++wordpos < maxword) {
101: node = node.eqKid[i];
102: word = signature[wordpos];
103: wordh = word.hashCode();
104: continue OUTER_NODE;
105: } else {
106: rval = node.eqKid[i].code;
107: break OUTER_NODE;
108: }
109: }
110: }
111: }
112: }
113: return rval;
114: }
115:
116: public Integer lookup(String attrName) {
117: int attrh = attrName.hashCode();
118:
119: Node node = atRoot;
120: Integer rval = null;
121: OUTER_NODE: while (node != null) {
122: if (attrh < node.hash) {
123: node = node.loKid;
124: } else if (attrh > node.hash) {
125: node = node.hiKid;
126: } else {
127: for (int i = node.eqKid.length - 1; i > -1; i--) {
128: if (attrName.equals(node.eqKid[i].val)) {
129: rval = node.eqKid[i].code;
130: break OUTER_NODE;
131: }
132: }
133: }
134: }
135: return rval;
136: }
137:
138: public void store(String mname, String[] signature, Integer code) {
139: if (opRoot == null) {
140: opRoot = createNode(mname);
141: createValueNode(opRoot, mname);
142: }
143:
144: int word = -1;
145: int maxword = (signature != null) ? signature.length : 0;
146:
147: Node current = createOrGetNode(opRoot, mname);
148: while (++word < maxword) {
149: current = createOrGetNode(current, signature[word]);
150: }
151:
152: current.code = code;
153: }
154:
155: public void store(String attrName, Integer code) {
156: Node current = null;
157:
158: if (atRoot == null) {
159: atRoot = createNode(attrName);
160: current = createValueNode(atRoot, attrName);
161: } else {
162: current = createOrGetNode(atRoot, attrName);
163: }
164:
165: current.code = code;
166: }
167:
168: protected Node createNode(String key) {
169: Node h = new Node();
170: h.hash = key.hashCode();
171: h.val = key;
172: return h;
173: }
174:
175: protected Node createValueNode(Node parent, String key) {
176: Node h = new Node();
177: h.val = key;
178: h.hash = key.hashCode();
179: int insertAt = 0;
180: if (parent.eqKid == null) {
181: parent.eqKid = new Node[1];
182: } else {
183: Node[] old = parent.eqKid;
184: insertAt = old.length;
185: parent.eqKid = new Node[insertAt + 1];
186: System.arraycopy(old, 0, parent.eqKid, 0, insertAt);
187: }
188:
189: parent.eqKid[insertAt] = h;
190: return h;
191: }
192:
193: protected Node createOrGetNode(Node parent, String key) {
194: Node realParent = parent;
195: int keycode = key.hashCode();
196:
197: while (true) {
198: if (keycode < realParent.hash) {
199: if (realParent.loKid == null) {
200: realParent.loKid = createNode(key);
201: return createValueNode(realParent.loKid, key);
202: }
203: realParent = realParent.loKid;
204: } else if (keycode > realParent.hash) {
205: if (realParent.hiKid == null) {
206: realParent.hiKid = createNode(key);
207: return createValueNode(realParent.hiKid, key);
208: }
209: realParent = realParent.hiKid;
210: } else {
211: if (realParent.eqKid != null) {
212: for (int i = 0; i < realParent.eqKid.length; i++) {
213: if (key.equals(realParent.eqKid[i].val)) {
214: return realParent.eqKid[i];
215: }
216: }
217: }
218: return createValueNode(realParent, key);
219: }
220: }
221: }
222:
223: public static class Node {
224: public int hash = 0;
225: public String val = null;
226:
227: public Node hiKid = null;
228: public Node loKid = null;
229: public Node[] eqKid = null;
230:
231: public Integer code = null;
232: }
233: }
|