001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.monitoring.reporting.web.plugin.jmx;
018    
019    import org.apache.commons.codec.binary.Base64;
020    import org.apache.commons.lang3.StringEscapeUtils;
021    
022    import java.util.Collection;
023    import java.util.Collections;
024    import java.util.Comparator;
025    import java.util.Map;
026    import java.util.TreeMap;
027    
028    public class JMXNode {
029        private final String name;
030        private final Map<Key, JMXNode> children = new TreeMap<Key, JMXNode>();
031        private String base64 = null;
032    
033        public JMXNode(final String name) {
034            this.name = name;
035        }
036    
037        public static void addNode(final JMXNode rootNode, final String domain, final String props) {
038            final Map<String, String> properties = new TreeMap<String, String>(new JMXPropertiesComparator(props));
039            for (final String k : props.split(",")) {
040                final String[] kv = k.split("=");
041                if (kv.length < 2) {
042                    properties.put(StringEscapeUtils.escapeHtml4(kv[0]), "");
043                } else {
044                    properties.put(StringEscapeUtils.escapeHtml4(kv[0]), StringEscapeUtils.escapeHtml4(kv[1]));
045                }
046            }
047    
048            final Key rootKey = new Key("domain", domain);
049            JMXNode node = rootNode.children.get(rootKey);
050            if (node == null) {
051                node = new JMXNode(domain);
052                rootNode.children.put(rootKey, node);
053            }
054    
055            for (final Map.Entry<String, String> entry : properties.entrySet()) {
056                final Key key = new Key(entry.getKey(), entry.getValue());
057                final String value = entry.getValue();
058    
059                JMXNode child = node.children.get(key);
060                if (child == null) {
061                    child = new JMXNode(value);
062                    node.children.put(key, child);
063                }
064    
065                node = child;
066            }
067    
068            node.base64 = Base64.encodeBase64String((domain + ":" + props).getBytes());
069        }
070    
071        public String getName() {
072            return name;
073        }
074    
075        public boolean isLeaf() {
076            return base64 != null;
077        }
078    
079        public String getBase64() {
080            return base64;
081        }
082    
083        public Collection<JMXNode> getChildren() {
084            return Collections.unmodifiableCollection(children.values());
085        }
086    
087        protected static class Key implements Comparable<Key> {
088            private final String key;
089            private final String value;
090    
091            public Key(final String key, final String value) {
092                this.key = key;
093                this.value = value;
094            }
095    
096            @Override
097            public boolean equals(final Object o) {
098                if (this == o) {
099                    return true;
100                }
101                if (o == null || Key.class != o.getClass()) {
102                    return false;
103                }
104    
105                final Key key1 = Key.class.cast(o);
106                return key.equals(key1.key) && value.equals(key1.value);
107            }
108    
109            @Override
110            public int hashCode() {
111                int result = key.hashCode();
112                result = 31 * result + value.hashCode();
113                return result;
114            }
115    
116            @Override
117            public int compareTo(final Key o) {
118                if (equals(o)) {
119                    return 0;
120                }
121    
122                final int keys = key.compareTo(o.key);
123                if (keys != 0) {
124                    return keys;
125                }
126                return value.compareTo(o.value);
127            }
128    
129            @Override
130            public String toString() {
131                return "{" + key + " = " + value + '}';
132            }
133        }
134    
135        protected static class JMXPropertiesComparator implements Comparator<String> {
136            private final String properties;
137    
138            protected JMXPropertiesComparator(final String props) {
139                properties = props;
140            }
141    
142            @Override
143            public int compare(final String o1, final String o2) {
144                if (o1.equals(o2)) {
145                    return 0;
146                }
147    
148                if ("type".equals(o1)) {
149                    return -1;
150                }
151                if ("type".equals(o2)) {
152                    return 1;
153                }
154                if ("j2eeType".equals(o1)) {
155                    return -1;
156                }
157                if ("j2eeType".equals(o2)) {
158                    return 1;
159                }
160    
161                return properties.indexOf(o1 + "=") - properties.indexOf(o2 + "=");
162            }
163        }
164    }