alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (AbstractTreeNode.java)

This example Glassfish source code file (AbstractTreeNode.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

arraylist, collection, concurrenthashmap, list, list, mondot, override, override, pattern, regex, slash, string, string, threading, threads, treenode, treenode, util

The Glassfish AbstractTreeNode.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2009-2011 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.flashlight.datatree.impl;

import static com.sun.enterprise.util.StringUtils.ok;
import com.sun.enterprise.util.ObjectAnalyzer;
import static com.sun.enterprise.util.SystemPropertyConstants.MONDOT;
import static com.sun.enterprise.util.SystemPropertyConstants.SLASH;
import org.glassfish.flashlight.datatree.TreeNode;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author Harpreet Singh
 * @author Byron Nevins
 * 12/18/2010 -- Added encode/decode.  Note that the encoded form for a dot is
 * NOT something like "\\." -- there is too much code around making assumptions
 * about dots, splitting strings, etc.  So we replace with ___MONDOT___
 */
public abstract class AbstractTreeNode implements TreeNode, Comparable {

    protected Map<String, TreeNode> children =
            new ConcurrentHashMap<String, TreeNode>();
    private static Map<String, TreeNode> normalizedChildren =
            new ConcurrentHashMap<String, TreeNode>();
    protected String name;    // The node object itself
    protected String category;
    protected String description;
    protected boolean enabled = false;
    private static String NAME_SEPARATOR = ".";
    private static String REGEX = "(?<!\\\\)\\.";
    private TreeNode parent = null;
    // Special character Regex to be converted to .* for v2 compatibility
    private String STAR = "*";

    @Override
    public String toString() {
        return ObjectAnalyzer.toString(this);
    }

    @Override
    public String getName() {

        return decodeName();
    }

    @Override
    public void setName(String aname) {

        if (aname == null)
            throw new RuntimeException("Flashlight-utils: Tree Node needs a"
                    + " non-null name");
        name = encodeNodeName(aname);
    }

    // should be implemented at the sub-class level
    @Override
    public Object getValue() {
        if (enabled) {
            return getChildNodes();
        }
        return null;
    }

    @Override
    public boolean isEnabled() {
        return this.enabled;
    }

    @Override
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    @Override
    public TreeNode addChild(TreeNode newChild) {
        if (newChild == null) {
            return null;
        }
        else if (newChild.getName() == null) {
            // log it and return null
            return null;
        }
        newChild.setParent(this);
        normalizedChildren.put(decodeNameToDots(newChild.getCompletePathName()), newChild);
        return children.put(newChild.getName(), newChild);
    }

    @Override
    public String getCompletePathName() {

        if (getParent() != null) {
            return getParent().getCompletePathName()
                    + this.NAME_SEPARATOR + getName();
        }
        else {
            return getName();
        }
    }

    @Override
    public void setParent(TreeNode parent) {
        this.parent = parent;
    }

    @Override
    public TreeNode getParent() {
        return this.parent;
    }

    /**
     * Returns a mutable view of the children
     * @return
     */
    @Override
    public Collection<TreeNode> getChildNodes() {
        return children.values();
    }

    /**
     * Returns a mutable view of the children
     * @return
     */
    @Override
    public Collection<TreeNode> getEnabledChildNodes() {
        List<TreeNode> childNodes = new ArrayList();
        for (TreeNode child : children.values()) {
            if (child.isEnabled())
                childNodes.add(child);
        }
        return childNodes;
    }

    public Enumeration<TreeNode> getChildNodesImmutable() {

        return ((ConcurrentHashMap) children).elements();
    }

    @Override
    public boolean hasChildNodes() {
        return !children.isEmpty();

    }

    @Override
    public void removeChild(TreeNode oldChild) {
        String child = oldChild.getName();
        if (child != null) {
            children.remove(child);
        }

        // too fragile to hunt for the matching key...
        Iterator<TreeNode> it = normalizedChildren.values().iterator();
        while(it.hasNext()) {
            if(it.next() == oldChild) {
                it.remove();
                break;
            }
        }
    }

    @Override
    public String getCategory() {
        return category;
    }

    @Override
    public void setCategory(String category) {
        this.category = category;
    }

    @Override
    public String getDescription() {
        return this.description;
    }

    @Override
    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public TreeNode getChild(String childName) {
        if (childName == null) {
            return null;
        }
        else {
            return children.get(childName);
        }
    }

    @Override
    public TreeNode getNode(String completeName) {
        if (completeName == null) {
            return null;
        }
        completeName = encodePath(completeName);
        Pattern pattern = Pattern.compile(AbstractTreeNode.REGEX);
        String[] tokens = pattern.split(completeName);
        TreeNode n = findNodeInTree(tokens);

        if(n == null)
            n = findNodeInTreeNormalized(completeName);

        return n;
    }

    // confused?  That's expected!  This should be refactored/re-done for 3.2
    // we store dots and slashes encoded.  THe tokens coming in to this method
    // are encoded.  That's because there is lots of other code scattered around
    // that looks for these special meta-characters.  To be safe I'm storing them
    // in the node encoded.
    // But the "children" object has keys that come from the getName() of the node
    // which is the value.
    private TreeNode findNodeInTree(String[] tokens) {
        if (tokens == null) {
            return null;
        }
        TreeNode child = getChild(tokens[0]);

        if (child == null)
            child = getChild(decodeName(tokens[0]));

        if (child == null)
            return null;

        if (tokens.length > 1)
            child = ((AbstractTreeNode) child).findNodeInTree(dropFirstStringToken(tokens));

        return child;

    }

    private String[] dropFirstStringToken(String[] token) {
        if (token.length == 0) {
            return null;
        }
        if (token.length == 1) {
            return null;
        }
        String[] newToken = new String[token.length - 1];
        for (int i = 0; i < newToken.length; i++) {
            newToken[i] = token[i + 1];
        }
        return newToken;
    }

    /**
     * Returns all the nodes under the current tree
     * @return List of all nodes in the current tree
     */
    @Override
    public List<TreeNode> traverse(boolean ignoreDisabled) {
//        System.out.println ("Node: " + this.getName ()+ " is enabled "+isEnabled());
        List<TreeNode> list = new ArrayList();

        if (ignoreDisabled) {
            if (!this.enabled) {
                return list;
            }
        }
        list.add(this);

        if (!hasChildNodes()) {
            return list;
        }

        Collection<TreeNode> childList = children.values();
        for (TreeNode node : childList) {
            list.addAll(node.traverse(ignoreDisabled));
        }
        return list;
    }

    @Override
    public List<TreeNode> getNodes(String pattern, boolean ignoreDisabled, boolean gfv2Compatible) {
        pattern = pattern.replace("\\.", "\\\\\\."); // \.  goes to \\\.

        // bnevins October 2010
        // design gotcha -- It used to be IMPOSSIBLE to tell the difference between
        // a literal slash in a name and a slash used as a delimiter.  Deep down
        // under dozens of calls in the stack -- Strings are concatanated together
        // Simple solution is to replace literal slashes with a token.  The probe
        // provider code needs to do that.  jndi names are an example of this.
        // Here we replace slash in the given pattern with the token to pull out
        // the right stuff.
        // This is a ARCHITECTURE flaw.  This hack can be replaced with an
        // ARCHITECTURAL fix later if desired.
        
        List<TreeNode> list = getNodesInternal(pattern, ignoreDisabled, gfv2Compatible);
        
        if(list == null || list.size() <= 0)
            list = getNodesInternal(pattern.replace("/", SLASH), ignoreDisabled, gfv2Compatible);

        if(list == null || list.size() <= 0)
            list = getNodesInternal(decodeNameToDots(pattern), ignoreDisabled, gfv2Compatible);

        return list;
    }

    private List<TreeNode> getNodesInternal(String pattern, boolean ignoreDisabled, boolean gfv2Compatible) {
        List<TreeNode> regexMatchedTree = new ArrayList();


        try {
            if (gfv2Compatible)
                pattern = convertGFv2PatternToRegex(pattern);

            Pattern mPattern = Pattern.compile(pattern);
            List<TreeNode> completeTree = traverse(ignoreDisabled);

            for (TreeNode node : completeTree) {
                String path = node.getCompletePathName();
                String path2 = null;

                if (path.indexOf("\\") >= 0)
                    path2 = path.replace("\\", "");

                Matcher matcher = mPattern.matcher(path);

                if (matcher.matches()) {
                    regexMatchedTree.add(node);
                }
                else if (path2 != null) {
                    Matcher matcher2 = mPattern.matcher(path2);
                    if (matcher2.matches()) {
                        regexMatchedTree.add(node);
                    }
                }
            }
        }
        catch (java.util.regex.PatternSyntaxException e) {
            // log this
            // e.printStackTrace ();
        }
        return regexMatchedTree;
    }

    @Override
    public List<TreeNode> getNodes(String pattern) {
        return getNodes(pattern, true, true);
    }

    private String convertGFv2PatternToRegex(String pattern) {
        if (pattern.equals(STAR)) {
            return ".*";
        }
        // Doing this intermediate step as replacing "*" in a pattern with ".*"
        // is too hassling

        String modifiedPattern = pattern.replaceAll("\\*", ":");
        String regex = modifiedPattern.replaceAll(":", ".*");
        return regex;
    }

    @Override
    public int compareTo(Object o) {
        return this.getName().compareTo(((TreeNode) o).getName());
    }

    @Override
    public TreeNode getPossibleParentNode(String pattern) {
        // simplify by bailing out early if preconditions are not met...
        if (pattern == null || pattern.length() <= 0 || pattern.indexOf('*') >= 0)
            return null;

        TreeNode node = null;
        int longest = 0;

        for (TreeNode n : traverse(true)) {
            String aname = n.getCompletePathName();

            if (aname == null)
                continue;   // defensive pgming

            // JIRA 15500 -- there may be a backslash in the name!

            if (pattern.startsWith(aname) || pattern.startsWith(aname.replace("\\", ""))) {
                int thisLength = aname.length();

                // keep the longest match ONLY!
                if (node == null || thisLength > longest) {
                    node = n;
                    longest = thisLength;
                }
            }
        }

        return node;
    }

    private String encodeNodeName(String nodeName) {
        // The order is important!!
        return nodeName
                .replace("\\.", MONDOT)
                .replace(".", MONDOT)
                .replace("\\/", SLASH)
                .replace("/", SLASH);
    }

    private String encodePath(String thePath) {
        // REST encodes (1) to (2)
        //  aaa    bbb.x   cccc
        //  aaa.bbb\\x.cccc
        // we want aaa.bbb___MONDOT___x.cccc

        return thePath.replace("\\/", SLASH).replace("\\.", MONDOT);
    }

    // todo replace with \\. ???
    private String decodeName() {
        return decodeName(name);
    }

    private static String decodeName(String s) {
        return s.replace(SLASH, "/").replace(MONDOT, "\\.");
    }

    private static String decodeNameToDots(String s) {
        return s
                .replace(SLASH, ".")
                .replace(MONDOT, ".")
                .replace("\\/", ".")
                .replace("\\.", ".")
                .replace('/', '.');
    }

    private TreeNode findNodeInTreeNormalized(String desiredName) {
        // this is ONLY called when there is no match using the tools prior to 2/10/11
        // so the performance hit should be reasonable

        if(!ok(desiredName))
            return null;

        desiredName = decodeNameToDots(desiredName);
        TreeNode node = normalizedChildren.get(desiredName);

        // one more try.  GUI sometimes chops off the starting "server".
        if (node == null && !desiredName.startsWith("server.")) {
            node = normalizedChildren.get("server." + desiredName);

            // one final try.  The string might be "instance1.blah" -- we must change that
            // to "instance1.server.blah"
            if (node == null && (desiredName = insertServerString(desiredName)) != null)
                node = normalizedChildren.get(desiredName);
        }

        return node;
    }

    private static String insertServerString(String desiredName) {
        try {
            String[] bits = desiredName.split("\\.");

            if (bits != null && bits.length >= 2) {
                
                if(bits[1].equals("server"))
                    return desiredName;

                StringBuilder sb = new StringBuilder(bits[0]);
                sb.append(".server");

                for (int i = 1; i < bits.length; i++) {
                    sb.append('.').append(bits[i]);
                }
                return sb.toString();
            }
        }
        catch (Exception e) {
            // fall through
        }
        return null;
    }
}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish AbstractTreeNode.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.