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.
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed 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.wildfly.common.net;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.atomic.AtomicReference;
import org.wildfly.common.Assert;
/**
* A table for mapping IP addresses to objects using {@link CidrAddress} instances for matching.
*
* @author David M. Lloyd
*/
public final class CidrAddressTable implements Iterable> {
@SuppressWarnings("rawtypes")
private static final Mapping[] NO_MAPPINGS = new Mapping[0];
private final AtomicReference[]> mappingsRef;
public CidrAddressTable() {
mappingsRef = new AtomicReference<>(empty());
}
private CidrAddressTable(Mapping[] mappings) {
mappingsRef = new AtomicReference<>(mappings);
}
public T getOrDefault(InetAddress address, T defVal) {
Assert.checkNotNullParam("address", address);
final Mapping mapping = doGet(mappingsRef.get(), address.getAddress(), address instanceof Inet4Address ? 32 : 128, Inet.getScopeId(address));
return mapping == null ? defVal : mapping.value;
}
public T get(InetAddress address) {
return getOrDefault(address, null);
}
public T put(CidrAddress block, T value) {
Assert.checkNotNullParam("block", block);
Assert.checkNotNullParam("value", value);
return doPut(block, null, value, true, true);
}
public T putIfAbsent(CidrAddress block, T value) {
Assert.checkNotNullParam("block", block);
Assert.checkNotNullParam("value", value);
return doPut(block, null, value, true, false);
}
public T replaceExact(CidrAddress block, T value) {
Assert.checkNotNullParam("block", block);
Assert.checkNotNullParam("value", value);
return doPut(block, null, value, false, true);
}
public boolean replaceExact(CidrAddress block, T expect, T update) {
Assert.checkNotNullParam("block", block);
Assert.checkNotNullParam("expect", expect);
Assert.checkNotNullParam("update", update);
return doPut(block, expect, update, false, true) == expect;
}
public T removeExact(CidrAddress block) {
Assert.checkNotNullParam("block", block);
return doPut(block, null, null, false, true);
}
public boolean removeExact(CidrAddress block, T expect) {
Assert.checkNotNullParam("block", block);
return doPut(block, expect, null, false, true) == expect;
}
private T doPut(final CidrAddress block, final T expect, final T update, final boolean putIfAbsent, final boolean putIfPresent) {
assert putIfAbsent || putIfPresent;
final AtomicReference[]> mappingsRef = this.mappingsRef;
final byte[] bytes = block.getNetworkAddress().getAddress();
Mapping[] oldVal, newVal;
int idx;
T existing;
boolean matchesExpected;
do {
oldVal = mappingsRef.get();
idx = doFind(oldVal, bytes, block.getNetmaskBits(), block.getScopeId());
if (idx < 0) {
if (! putIfAbsent) {
return null;
}
existing = null;
} else {
existing = oldVal[idx].value;
}
if (expect != null) {
matchesExpected = Objects.equals(expect, existing);
if (! matchesExpected) {
return existing;
}
} else {
matchesExpected = false;
}
if (idx >= 0 && ! putIfPresent) {
return existing;
}
// now construct the new mapping
final int oldLen = oldVal.length;
if (update == null) {
assert idx >= 0;
// removal
if (oldLen == 1) {
newVal = empty();
} else {
final Mapping removing = oldVal[idx];
newVal = Arrays.copyOf(oldVal, oldLen - 1);
System.arraycopy(oldVal, idx + 1, newVal, idx, oldLen - idx - 1);
// now reparent any children that I was a parent of with my old parent
for (int i = 0; i < oldLen - 1; i ++) {
if (newVal[i].parent == removing) {
newVal[i] = newVal[i].withNewParent(removing.parent);
}
}
}
} else if (idx >= 0) {
// replace
newVal = oldVal.clone();
final Mapping oldMapping = oldVal[idx];
final Mapping newMapping = new Mapping<>(block, update, oldVal[idx].parent);
newVal[idx] = newMapping;
// now reparent any child to me
for (int i = 0; i < oldLen; i ++) {
if (i != idx && newVal[i].parent == oldMapping) {
newVal[i] = newVal[i].withNewParent(newMapping);
}
}
} else {
// add
newVal = Arrays.copyOf(oldVal, oldLen + 1);
final Mapping newMappingParent = doGet(oldVal, bytes, block.getNetmaskBits(), block.getScopeId());
final Mapping newMapping = new Mapping<>(block, update, newMappingParent);
newVal[-idx - 1] = newMapping;
System.arraycopy(oldVal, -idx - 1, newVal, -idx, oldLen + idx + 1);
// now reparent any children who have a parent of my (possibly null) parent but match me
for (int i = 0; i <= oldLen; i++) {
if (newVal[i] != newMapping && newVal[i].parent == newMappingParent && block.matches(newVal[i].range)) {
newVal[i] = newVal[i].withNewParent(newMapping);
}
}
}
} while (! mappingsRef.compareAndSet(oldVal, newVal));
return matchesExpected ? expect : existing;
}
@SuppressWarnings("unchecked")
private static Mapping[] empty() {
return NO_MAPPINGS;
}
public void clear() {
mappingsRef.set(empty());
}
public int size() {
return mappingsRef.get().length;
}
public boolean isEmpty() {
return size() == 0;
}
public CidrAddressTable clone() {
return new CidrAddressTable<>(mappingsRef.get());
}
public Iterator> iterator() {
final Mapping[] mappings = mappingsRef.get();
return new Iterator>() {
int idx;
public boolean hasNext() {
return idx < mappings.length;
}
public Mapping next() {
if (! hasNext()) throw new NoSuchElementException();
return mappings[idx++];
}
};
}
public Spliterator> spliterator() {
final Mapping[] mappings = mappingsRef.get();
return Spliterators.spliterator(mappings, Spliterator.IMMUTABLE | Spliterator.ORDERED);
}
public String toString() {
StringBuilder b = new StringBuilder();
final Mapping[] mappings = mappingsRef.get();
b.append(mappings.length).append(" mappings");
for (final Mapping mapping : mappings) {
b.append(System.lineSeparator()).append('\t').append(mapping.range);
if (mapping.parent != null) {
b.append(" (parent ").append(mapping.parent.range).append(')');
}
b.append(" -> ").append(mapping.value);
}
return b.toString();
}
private int doFind(Mapping[] table, byte[] bytes, int maskBits, final int scopeId) {
int low = 0;
int high = table.length - 1;
while (low <= high) {
// bisect the range
int mid = low + high >>> 1;
// compare the mapping at this location
Mapping mapping = table[mid];
int cmp = mapping.range.compareAddressBytesTo(bytes, maskBits, scopeId);
if (cmp < 0) {
// move to the latter half
low = mid + 1;
} else if (cmp > 0) {
// move to the former half
high = mid - 1;
} else {
// exact match is the best case
return mid;
}
}
// return the point we would insert at (plus one, negated)
return -(low + 1);
}
private Mapping doGet(Mapping[] table, byte[] bytes, final int netmaskBits, final int scopeId) {
int idx = doFind(table, bytes, netmaskBits, scopeId);
if (idx >= 0) {
// exact match
assert table[idx].range.matches(bytes, scopeId);
return table[idx];
}
// check immediate predecessor if there is one
int pre = -idx - 2;
if (pre >= 0) {
if (table[pre].range.matches(bytes, scopeId)) {
return table[pre];
}
// try parent
Mapping parent = table[pre].parent;
while (parent != null) {
if (parent.range.matches(bytes, scopeId)) {
return parent;
}
parent = parent.parent;
}
}
return null;
}
/**
* A single mapping in the table.
*
* @param the value type
*/
public static final class Mapping {
final CidrAddress range;
final T value;
final Mapping parent;
Mapping(final CidrAddress range, final T value, final Mapping parent) {
this.range = range;
this.value = value;
this.parent = parent;
}
Mapping withNewParent(Mapping newParent) {
return new Mapping(range, value, newParent);
}
/**
* Get the address range of this entry.
*
* @return the address range of this entry (not {@code null})
*/
public CidrAddress getRange() {
return range;
}
/**
* Get the stored value of this entry.
*
* @return the stored value of this entry
*/
public T getValue() {
return value;
}
/**
* Get the parent of this entry, if any.
*
* @return the parent of this entry, or {@code null} if there is no parent
*/
public Mapping getParent() {
return parent;
}
}
}