Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.artemis.core.postoffice.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
public final class AddressPartNode {
protected final String ANY_CHILD;
protected final String ANY_DESCENDENT;
private final AddressPartNode parent;
private final List values = new CopyOnWriteArrayList<>();
private final Map> childNodes = new ConcurrentHashMap<>();
private final String path;
public AddressPartNode(final String path, final AddressPartNode parent) {
this.parent = parent;
this.ANY_DESCENDENT = parent.ANY_DESCENDENT;
this.ANY_CHILD = parent.ANY_CHILD;
// allow '==' equality wildcard nodes
if (ANY_DESCENDENT.equals(path)) {
this.path = ANY_DESCENDENT;
} else if (ANY_CHILD.equals(path)) {
this.path = ANY_CHILD;
} else {
this.path = path;
}
}
public AddressPartNode(String anyDescendent, String anyChild) {
ANY_DESCENDENT = anyDescendent;
ANY_CHILD = anyChild;
path = "Root";
parent = null;
}
public AddressPartNode getChild(final String path) {
return childNodes.get(path);
}
public Collection> getChildren() {
return childNodes.values();
}
public AddressPartNode getChildOrCreate(final String path) {
AddressPartNode answer = childNodes.get(path);
if (answer == null) {
answer = new AddressPartNode<>(path, this);
childNodes.put(path, answer);
}
return answer;
}
public void add(final String[] paths, final int idx, final T value) {
if (idx >= paths.length) {
values.add(value);
} else {
getChildOrCreate(paths[idx]).add(paths, idx + 1, value);
}
}
public void remove(final String[] paths, final int idx, final T value) {
if (idx >= paths.length) {
values.remove(value);
pruneIfEmpty();
} else {
getChildOrCreate(paths[idx]).remove(paths, idx + 1, value);
}
}
public void visitDescendantNonWildcardValues(final AddressMapVisitor collector) throws Exception {
visitValues(collector);
for (AddressPartNode child : childNodes.values()) {
if (ANY_CHILD == child.getPath() || ANY_DESCENDENT == child.getPath()) {
continue;
}
child.visitDescendantNonWildcardValues(collector);
}
}
public void visitPathTailNonWildcard(final String[] paths,
final int startIndex,
final AddressMapVisitor collector) throws Exception {
if (childNodes.isEmpty()) {
return;
}
// look for a path match after 0-N skips among children
AddressPartNode match = null;
for (int i = startIndex; i < paths.length; i++) {
match = getChild(paths[i]);
if (match != null) {
if (ANY_CHILD == match.getPath() || ANY_DESCENDENT == match.getPath()) {
continue;
}
match.visitNonWildcard(paths, i + 1, collector);
break;
}
}
// walk the rest of the sub tree to find a tail path match
for (AddressPartNode child : childNodes.values()) {
// instance equality arranged in node creation getChildOrCreate
if (child != match && ANY_DESCENDENT != child.getPath() && ANY_CHILD != child.getPath()) {
child.visitPathTailNonWildcard(paths, startIndex, collector);
}
}
}
public void visitPathTailMatch(final String[] paths, final int startIndex, final AddressMapVisitor collector) throws Exception {
if (childNodes.isEmpty()) {
return;
}
// look for a path match after 0-N skips among immediate children
ArrayList visitedSet = new ArrayList<>(paths.length);
for (int i = startIndex; i < paths.length; i++) {
final AddressPartNode match = getChild(paths[i]);
if (match != null) {
match.visitMatchingWildcards(paths, i + 1, collector);
visitedSet.add(match);
}
}
// walk the rest of the sub tree to find a tail path match
for (AddressPartNode child : childNodes.values()) {
if (alreadyVisited(child, visitedSet)) {
continue;
}
child.visitPathTailMatch(paths, startIndex, collector);
}
}
private boolean alreadyVisited(final AddressPartNode child, final ArrayList matches) {
if (!matches.isEmpty()) {
for (AddressPartNode alreadyMatched : matches) {
if (child == alreadyMatched) {
return true;
}
}
}
return false;
}
// wildcards in the paths, ignore wildcard expansions in the map
public void visitNonWildcard(final String[] paths, final int startIndex, final AddressMapVisitor collector) throws Exception {
boolean canVisitAnyDescendent = true;
AddressPartNode node = this;
final int size = paths.length;
for (int i = startIndex; i < size && node != null; i++) {
final String path = paths[i];
// snuff out any descendant postfix in the paths ....#
if (ANY_DESCENDENT.equals(path)) {
if (i == size - 1) {
node.visitDescendantNonWildcardValues(collector);
canVisitAnyDescendent = false;
break;
}
}
if (ANY_CHILD.equals(path)) {
for (AddressPartNode anyChild : node.getChildren()) {
if (ANY_CHILD == anyChild.getPath() || ANY_DESCENDENT == anyChild.getPath()) {
continue;
}
anyChild.visitNonWildcard(paths, i + 1, collector);
}
// once we have done depth first on all children we are done with our paths
return;
} else if (ANY_DESCENDENT.equals(path)) {
node.visitValues(collector);
node.visitPathTailNonWildcard(paths, i + 1, collector);
// once we have done depth first on all children we are done with our paths
return;
} else {
node = node.getChild(path);
}
}
if (node != null) {
if (canVisitAnyDescendent) {
node.visitValues(collector);
}
}
}
// non wildcard paths, match any expanded wildcards in the map
public void visitMatchingWildcards(final String[] paths, final int startIndex, final AddressMapVisitor collector) throws Exception {
boolean canVisitAnyDescendent = true;
AddressPartNode node = this;
AddressPartNode anyDescendentNode = null;
AddressPartNode anyChildNode = null;
final int size = paths.length;
for (int i = startIndex; i < size && node != null; i++) {
final String path = paths[i];
anyDescendentNode = node.getChild(ANY_DESCENDENT);
if (anyDescendentNode != null) {
anyDescendentNode.visitValues(collector);
// match tail with current path, such that ANY_DESCENDENT can match zero
anyDescendentNode.visitPathTailMatch(paths, i, collector);
canVisitAnyDescendent = false;
}
anyChildNode = node.getChild(ANY_CHILD);
if (anyChildNode != null) {
anyChildNode.visitMatchingWildcards(paths, i + 1, collector);
}
node = node.getChild(path);
if (node != null && (node == anyChildNode || node == anyDescendentNode)) {
// down that path before, out of here
return;
}
}
if (node != null) {
node.visitValues(collector);
if (canVisitAnyDescendent) {
// allow zero node any descendant at the end of path node
anyDescendentNode = node.getChild(ANY_DESCENDENT);
if (anyDescendentNode != null) {
anyDescendentNode.visitValues(collector);
}
}
}
}
public void visitValues(final AddressMapVisitor collector) throws Exception {
for (T o : values) {
collector.visit(o);
}
}
public String getPath() {
return path;
}
protected void pruneIfEmpty() {
if (parent != null && childNodes.isEmpty() && values.isEmpty()) {
parent.removeChild(this);
}
}
protected void removeChild(final AddressPartNode node) {
childNodes.remove(node.getPath());
pruneIfEmpty();
}
public void reset() {
values.clear();
childNodes.clear();
}
}