Add node equality predicates, and provide way to determine hasPermission behaviour using them (#782)

This commit is contained in:
Luck 2018-02-22 23:34:35 +00:00
parent b1fa4263ed
commit 736105cc12
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
10 changed files with 385 additions and 107 deletions

View File

@ -318,39 +318,81 @@ public interface Node extends Map.Entry<String, Boolean> {
Map.Entry<Integer, String> getSuffix() throws IllegalStateException;
/**
* Checks if this Node is equal to another node
* Returns if this Node is equal to another node
*
* @param obj the other node
* @return true if this node is equal to the other provided
* @see #equalsIgnoringValue(Node) for a less strict implementation of this method
* @see StandardNodeEquality#EXACT
*/
@Override
boolean equals(Object obj);
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the value
* Returns if this Node is equal to another node as defined by the given
* {@link StandardNodeEquality} predicate.
*
* @param other the other node
* @param equalityPredicate the predicate
* @return true if this node is considered equal
* @since 4.1
*/
boolean standardEquals(Node other, StandardNodeEquality equalityPredicate);
/**
* Returns if this Node is equal to another node as defined by the given
* {@link NodeEqualityPredicate}.
*
* @param other the other node
* @param equalityPredicate the predicate
* @return true if this node is considered equal
* @since 4.1
*/
default boolean equals(Node other, NodeEqualityPredicate equalityPredicate) {
return equalityPredicate.areEqual(this, other);
}
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* value.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
* @see StandardNodeEquality#IGNORE_VALUE
*/
boolean equalsIgnoringValue(@Nonnull Node other);
@Deprecated
default boolean equalsIgnoringValue(@Nonnull Node other) {
return equals(other, StandardNodeEquality.IGNORE_VALUE);
}
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the expiry time or value
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* expiry time or value.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
* @see StandardNodeEquality#IGNORE_EXPIRY_TIME_AND_VALUE
*/
boolean almostEquals(@Nonnull Node other);
@Deprecated
default boolean almostEquals(@Nonnull Node other) {
return equals(other, StandardNodeEquality.IGNORE_EXPIRY_TIME_AND_VALUE);
}
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the value or if the node is temporary
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* value or if the node is temporary.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @since 2.8
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
* @see StandardNodeEquality#IGNORE_VALUE_OR_IF_TEMPORARY
*/
boolean equalsIgnoringValueOrTemp(@Nonnull Node other);
@Deprecated
default boolean equalsIgnoringValueOrTemp(@Nonnull Node other) {
return equals(other, StandardNodeEquality.IGNORE_VALUE_OR_IF_TEMPORARY);
}
/**
* Builds a Node instance

View File

@ -0,0 +1,53 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import javax.annotation.Nonnull;
/**
* A rule for determining if two nodes are equal.
*
* <p>Generally, individual instances of this interface should fulfil the same
* requirements as the {@link Object#equals(Object)} contract.</p>
*
* <p>Some standard implementations are provided by
* {@link StandardNodeEquality}.</p>
*
* @since 4.1
*/
@FunctionalInterface
public interface NodeEqualityPredicate {
/**
* Returns if the two nodes are equal
*
* @param o1 the first node
* @param o2 the second node
* @return true if equal
*/
boolean areEqual(@Nonnull Node o1, @Nonnull Node o2);
}

View File

@ -271,6 +271,42 @@ public interface PermissionHolder {
*/
void auditTemporaryPermissions();
/**
* Checks to see if the object has a certain permission
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 4.1
*/
@Nonnull
Tristate hasPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object has a certain permission
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 4.1
*/
@Nonnull
Tristate hasTransientPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object inherits a certain permission
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders inheritance status for the node
* @throws NullPointerException if the node is null
* @since 4.1
*/
@Nonnull
Tristate inheritsPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object has a certain permission
*

View File

@ -0,0 +1,78 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import javax.annotation.Nonnull;
/**
* Standard {@link NodeEqualityPredicate}s.
*
* @since 4.1
*/
public enum StandardNodeEquality implements NodeEqualityPredicate {
/**
* Represents an exact match.
*
* <p>All attributes of the nodes must match for them to be considered
* equal.</p>
*/
EXACT,
/**
* All attributes must match, except for
* {@link Node#getValuePrimitive() value}, which is ignored.
*/
IGNORE_VALUE,
/**
* All attributes must match, except for the
* {@link Node#getExpiry() expiry time}, which is ignored.
*
* <p>Note that with this setting, whether a node is temporary or not is
* still considered.</p>
*/
IGNORE_EXPIRY_TIME,
/**
* All attributes must match, except for
* {@link Node#getValuePrimitive() value} and the
* {@link Node#getExpiry() expiry time}, which are ignored.
*/
IGNORE_EXPIRY_TIME_AND_VALUE,
/**
* All attributes must match, except for
* {@link Node#getValuePrimitive() value} and the if the node is
* {@link Node#isTemporary() temporary}, which are ignored.
*/
IGNORE_VALUE_OR_IF_TEMPORARY;
@Override
public boolean areEqual(@Nonnull Node o1, @Nonnull Node o2) {
return o1.standardEquals(o2, this);
}
}

View File

@ -35,6 +35,7 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.DataMutateResult;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.NodeEqualityPredicate;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.context.ContextSet;
@ -158,18 +159,42 @@ public class ApiPermissionHolder implements me.lucko.luckperms.api.PermissionHol
return ImmutableMap.copyOf(this.handle.exportNodesAndShorthand(contexts, lowerCase));
}
@Nonnull
@Override
public Tristate hasPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate) {
Objects.requireNonNull(node, "node");
Objects.requireNonNull(equalityPredicate, "equalityPredicate");
return this.handle.hasPermission(NodeMapType.ENDURING, node, equalityPredicate);
}
@Nonnull
@Override
public Tristate hasTransientPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate) {
Objects.requireNonNull(node, "node");
Objects.requireNonNull(equalityPredicate, "equalityPredicate");
return this.handle.hasPermission(NodeMapType.TRANSIENT, node, equalityPredicate);
}
@Nonnull
@Override
public Tristate inheritsPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate) {
Objects.requireNonNull(node, "node");
Objects.requireNonNull(equalityPredicate, "equalityPredicate");
return this.handle.inheritsPermission(node, equalityPredicate);
}
@Nonnull
@Override
public Tristate hasPermission(@Nonnull Node node) {
Objects.requireNonNull(node, "node");
return this.handle.hasPermission(node, NodeMapType.ENDURING);
return this.handle.hasPermission(NodeMapType.ENDURING, node);
}
@Nonnull
@Override
public Tristate hasTransientPermission(@Nonnull Node node) {
Objects.requireNonNull(node, "node");
return this.handle.hasPermission(node, NodeMapType.TRANSIENT);
return this.handle.hasPermission(NodeMapType.TRANSIENT, node);
}
@Nonnull

View File

@ -25,6 +25,7 @@
package me.lucko.luckperms.common.commands.impl.generic.permission;
import me.lucko.luckperms.api.StandardNodeEquality;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.commands.ArgumentPermissions;
@ -62,7 +63,7 @@ public class PermissionCheck extends SharedSubCommand {
String node = ArgumentUtils.handleString(0, args);
MutableContextSet context = ArgumentUtils.handleContext(1, args, plugin);
Tristate result = holder.hasPermission(NodeFactory.builder(node).withExtraContext(context).build());
Tristate result = holder.hasPermission(NodeFactory.builder(node).withExtraContext(context).build(), StandardNodeEquality.IGNORE_VALUE_OR_IF_TEMPORARY);
String s = CommandUtils.formatTristate(result);
Message.CHECK_PERMISSION.send(sender, holder.getFriendlyName(), node, s, CommandUtils.contextSetToString(context));

View File

@ -25,6 +25,7 @@
package me.lucko.luckperms.common.commands.impl.generic.permission;
import me.lucko.luckperms.api.StandardNodeEquality;
import me.lucko.luckperms.api.context.MutableContextSet;
import me.lucko.luckperms.common.commands.ArgumentPermissions;
import me.lucko.luckperms.common.commands.CommandException;
@ -62,7 +63,7 @@ public class PermissionCheckInherits extends SharedSubCommand {
String node = ArgumentUtils.handleString(0, args);
MutableContextSet context = ArgumentUtils.handleContext(1, args, plugin);
InheritanceInfo result = holder.inheritsPermissionInfo(NodeFactory.builder(node).withExtraContext(context).build());
InheritanceInfo result = holder.searchForInheritedMatch(NodeFactory.builder(node).withExtraContext(context).build(), StandardNodeEquality.IGNORE_VALUE_OR_IF_TEMPORARY);
String location = result.getLocation().orElse(null);
if (location == null || location.equalsIgnoreCase(holder.getObjectName())) {

View File

@ -35,6 +35,8 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.DataMutateResult;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.NodeEqualityPredicate;
import me.lucko.luckperms.api.StandardNodeEquality;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
@ -578,44 +580,53 @@ public abstract class PermissionHolder {
return transientWork || enduringWork;
}
private Optional<Node> getAlmostEquals(Node node, NodeMapType type) {
private Optional<Node> searchForMatch(NodeMapType type, Node node, NodeEqualityPredicate equalityPredicate) {
for (Node n : getData(type).immutable().values()) {
if (n.almostEquals(node)) {
if (n.equals(node, equalityPredicate)) {
return Optional.of(n);
}
}
return Optional.empty();
}
/**
* Check if the holder has a permission node
*
* @param node the node to check
* @param type which backing map to check
* @return a tristate
* @param node the node to check
* @param equalityPredicate how to match
* @return a tristate, returns undefined if no match
*/
public Tristate hasPermission(Node node, NodeMapType type) {
public Tristate hasPermission(NodeMapType type, Node node, NodeEqualityPredicate equalityPredicate) {
if (this.getType().isGroup() && node.isGroupNode() && node.getGroupName().equalsIgnoreCase(getObjectName())) {
return Tristate.TRUE;
}
return getAlmostEquals(node, type).map(Node::getTristate).orElse(Tristate.UNDEFINED);
return searchForMatch(type, node, equalityPredicate).map(Node::getTristate).orElse(Tristate.UNDEFINED);
}
public Tristate hasPermission(NodeMapType type, Node node) {
return hasPermission(type, node, StandardNodeEquality.IGNORE_EXPIRY_TIME_AND_VALUE);
}
public Tristate hasPermission(Node node, NodeEqualityPredicate equalityPredicate) {
return hasPermission(NodeMapType.ENDURING, node, equalityPredicate);
}
public Tristate hasPermission(Node node) {
return hasPermission(node, NodeMapType.ENDURING);
return hasPermission(NodeMapType.ENDURING, node, StandardNodeEquality.IGNORE_EXPIRY_TIME_AND_VALUE);
}
/**
* Check if the holder inherits a node
*
* @param node the node to check
* @param equalityPredicate how to match
* @return the result of the lookup
*/
public InheritanceInfo inheritsPermissionInfo(Node node) {
public InheritanceInfo searchForInheritedMatch(Node node, NodeEqualityPredicate equalityPredicate) {
for (LocalizedNode n : resolveInheritances()) {
if (n.getNode().almostEquals(node)) {
if (n.getNode().equals(node, equalityPredicate)) {
return InheritanceInfo.of(n);
}
}
@ -627,10 +638,15 @@ public abstract class PermissionHolder {
* Check if the holder inherits a node
*
* @param node the node to check
* @param equalityPredicate how to match
* @return the Tristate result
*/
public Tristate inheritsPermission(Node node, NodeEqualityPredicate equalityPredicate) {
return searchForInheritedMatch(node, equalityPredicate).getResult();
}
public Tristate inheritsPermission(Node node) {
return inheritsPermissionInfo(node).getResult();
return inheritsPermission(node, StandardNodeEquality.IGNORE_EXPIRY_TIME_AND_VALUE);
}
/**
@ -639,7 +655,7 @@ public abstract class PermissionHolder {
* @param node the node to set
*/
public DataMutateResult setPermission(Node node) {
if (hasPermission(node, NodeMapType.ENDURING) != Tristate.UNDEFINED) {
if (hasPermission(NodeMapType.ENDURING, node) != Tristate.UNDEFINED) {
return DataMutateResult.ALREADY_HAS;
}
@ -663,7 +679,7 @@ public abstract class PermissionHolder {
if (node.isTemporary()) {
if (modifier == TemporaryModifier.ACCUMULATE) {
// Try to accumulate with an existing node
Optional<Node> existing = getAlmostEquals(node, NodeMapType.ENDURING);
Optional<Node> existing = searchForMatch(NodeMapType.ENDURING, node, StandardNodeEquality.IGNORE_EXPIRY_TIME_AND_VALUE);
// An existing node was found
if (existing.isPresent()) {
@ -684,7 +700,7 @@ public abstract class PermissionHolder {
} else if (modifier == TemporaryModifier.REPLACE) {
// Try to replace an existing node
Optional<Node> existing = getAlmostEquals(node, NodeMapType.ENDURING);
Optional<Node> existing = searchForMatch(NodeMapType.ENDURING, node, StandardNodeEquality.IGNORE_EXPIRY_TIME_AND_VALUE);
// An existing node was found
if (existing.isPresent()) {
@ -717,7 +733,7 @@ public abstract class PermissionHolder {
* @param node the node to set
*/
public DataMutateResult setTransientPermission(Node node) {
if (hasPermission(node, NodeMapType.TRANSIENT) != Tristate.UNDEFINED) {
if (hasPermission(NodeMapType.TRANSIENT, node) != Tristate.UNDEFINED) {
return DataMutateResult.ALREADY_HAS;
}
@ -732,7 +748,7 @@ public abstract class PermissionHolder {
* @param node the node to unset
*/
public DataMutateResult unsetPermission(Node node) {
if (hasPermission(node, NodeMapType.ENDURING) == Tristate.UNDEFINED) {
if (hasPermission(NodeMapType.ENDURING, node) == Tristate.UNDEFINED) {
return DataMutateResult.LACKS;
}
@ -751,7 +767,7 @@ public abstract class PermissionHolder {
* @param node the node to unset
*/
public DataMutateResult unsetTransientPermission(Node node) {
if (hasPermission(node, NodeMapType.TRANSIENT) == Tristate.UNDEFINED) {
if (hasPermission(NodeMapType.TRANSIENT, node) == Tristate.UNDEFINED) {
return DataMutateResult.LACKS;
}

View File

@ -26,6 +26,7 @@
package me.lucko.luckperms.common.node;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.StandardNodeEquality;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
@ -224,18 +225,8 @@ public abstract class ForwardingNode implements Node {
}
@Override
public boolean equalsIgnoringValue(@Nonnull Node other) {
return delegate().equalsIgnoringValue(other);
}
@Override
public boolean almostEquals(@Nonnull Node other) {
return delegate().almostEquals(other);
}
@Override
public boolean equalsIgnoringValueOrTemp(@Nonnull Node other) {
return delegate().equalsIgnoringValueOrTemp(other);
public boolean standardEquals(Node other, StandardNodeEquality equalityPredicate) {
return delegate().standardEquals(other, equalityPredicate);
}
@Override

View File

@ -29,6 +29,7 @@ import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.StandardNodeEquality;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.context.MutableContextSet;
@ -320,27 +321,41 @@ public final class ImmutableNode implements Node {
return this.resolvedShorthand;
}
@SuppressWarnings("StringEquality")
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Node)) return false;
final Node other = (Node) o;
if (this.permission != other.getPermission()) return false;
if (this.value != other.getValuePrimitive()) return false;
if (this.override != other.isOverride()) return false;
Node other = (Node) o;
while (other instanceof ForwardingNode) {
other = ((ForwardingNode) other).delegate();
}
return other instanceof ImmutableNode && Equality.EXACT.areEqual(this, (ImmutableNode) other);
}
final String thisServer = this.server;
final String otherServer = other.getServer().orElse(null);
if (thisServer == null ? otherServer != null : !thisServer.equals(otherServer)) return false;
final String thisWorld = this.world;
final String otherWorld = other.getWorld().orElse(null);
if (thisWorld == null ? otherWorld != null : !thisWorld.equals(otherWorld)) return false;
final long otherExpireAt = other.isTemporary() ? other.getExpiryUnixTime() : 0L;
return this.expireAt == otherExpireAt && this.getContexts().equals(other.getContexts());
@Override
public boolean standardEquals(Node o, StandardNodeEquality equalityPredicate) {
while (o instanceof ForwardingNode) {
o = ((ForwardingNode) o).delegate();
}
if (!(o instanceof ImmutableNode)) {
return false;
}
ImmutableNode other = (ImmutableNode) o;
switch (equalityPredicate) {
case EXACT:
return Equality.EXACT.areEqual(this, other);
case IGNORE_VALUE:
return Equality.IGNORE_VALUE.areEqual(this, other);
case IGNORE_EXPIRY_TIME:
return Equality.IGNORE_EXPIRY_TIME.areEqual(this, other);
case IGNORE_EXPIRY_TIME_AND_VALUE:
return Equality.IGNORE_EXPIRY_TIME_AND_VALUE.areEqual(this, other);
case IGNORE_VALUE_OR_IF_TEMPORARY:
return Equality.IGNORE_VALUE_OR_IF_TEMPORARY.areEqual(this, other);
default:
throw new AssertionError();
}
}
@Override
@ -362,57 +377,70 @@ public final class ImmutableNode implements Node {
}
@SuppressWarnings("StringEquality")
@Override
public boolean equalsIgnoringValue(@Nonnull Node other) {
if (this.permission != other.getPermission()) return false;
if (this.override != other.isOverride()) return false;
private enum Equality {
EXACT {
@Override
public boolean areEqual(@Nonnull ImmutableNode o1, @Nonnull ImmutableNode o2) {
return o1 == o2 ||
o1.permission == o2.permission &&
o1.value == o2.value &&
o1.override == o2.override &&
(o1.server == null ? o2.server == null : o1.server.equals(o2.server)) &&
(o1.world == null ? o2.world == null : o1.world.equals(o2.world)) &&
o1.expireAt == o2.expireAt &&
o1.getContexts().equals(o2.getContexts());
}
},
IGNORE_VALUE {
@Override
public boolean areEqual(@Nonnull ImmutableNode o1, @Nonnull ImmutableNode o2) {
return o1 == o2 ||
o1.permission == o2.permission &&
o1.override == o2.override &&
(o1.server == null ? o2.server == null : o1.server.equals(o2.server)) &&
(o1.world == null ? o2.world == null : o1.world.equals(o2.world)) &&
o1.expireAt == o2.expireAt &&
o1.getContexts().equals(o2.getContexts());
}
},
IGNORE_EXPIRY_TIME {
@Override
public boolean areEqual(@Nonnull ImmutableNode o1, @Nonnull ImmutableNode o2) {
return o1 == o2 ||
o1.permission == o2.permission &&
o1.value == o2.value &&
o1.override == o2.override &&
(o1.server == null ? o2.server == null : o1.server.equals(o2.server)) &&
(o1.world == null ? o2.world == null : o1.world.equals(o2.world)) &&
o1.isTemporary() == o2.isTemporary() &&
o1.getContexts().equals(o2.getContexts());
}
},
IGNORE_EXPIRY_TIME_AND_VALUE {
@Override
public boolean areEqual(@Nonnull ImmutableNode o1, @Nonnull ImmutableNode o2) {
return o1 == o2 ||
o1.permission == o2.permission &&
o1.override == o2.override &&
(o1.server == null ? o2.server == null : o1.server.equals(o2.server)) &&
(o1.world == null ? o2.world == null : o1.world.equals(o2.world)) &&
o1.isTemporary() == o2.isTemporary() &&
o1.getContexts().equals(o2.getContexts());
}
},
IGNORE_VALUE_OR_IF_TEMPORARY {
@Override
public boolean areEqual(@Nonnull ImmutableNode o1, @Nonnull ImmutableNode o2) {
return o1 == o2 ||
o1.permission == o2.permission &&
o1.override == o2.override &&
(o1.server == null ? o2.server == null : o1.server.equals(o2.server)) &&
(o1.world == null ? o2.world == null : o1.world.equals(o2.world)) &&
o1.getContexts().equals(o2.getContexts());
}
};
final String thisServer = this.server;
final String otherServer = other.getServer().orElse(null);
if (thisServer == null ? otherServer != null : !thisServer.equals(otherServer)) return false;
final String thisWorld = this.world;
final String otherWorld = other.getWorld().orElse(null);
if (thisWorld == null ? otherWorld != null : !thisWorld.equals(otherWorld)) return false;
final long otherExpireAt = other.isTemporary() ? other.getExpiryUnixTime() : 0L;
return this.expireAt == otherExpireAt && this.getContexts().equals(other.getContexts());
}
@SuppressWarnings("StringEquality")
@Override
public boolean almostEquals(@Nonnull Node other) {
if (this.permission != other.getPermission()) return false;
if (this.override != other.isOverride()) return false;
final String thisServer = this.server;
final String otherServer = other.getServer().orElse(null);
if (thisServer == null ? otherServer != null : !thisServer.equals(otherServer))
return false;
final String thisWorld = this.world;
final String otherWorld = other.getWorld().orElse(null);
return (thisWorld == null ? otherWorld == null : thisWorld.equals(otherWorld)) &&
this.isTemporary() == other.isTemporary() &&
this.getContexts().equals(other.getContexts());
}
@SuppressWarnings("StringEquality")
@Override
public boolean equalsIgnoringValueOrTemp(@Nonnull Node other) {
if (this.permission != other.getPermission()) return false;
if (this.override != other.isOverride()) return false;
final String thisServer = this.server;
final String otherServer = other.getServer().orElse(null);
if (thisServer == null ? otherServer != null : !thisServer.equals(otherServer))
return false;
final String thisWorld = this.world;
final String otherWorld = other.getWorld().orElse(null);
return (thisWorld == null ? otherWorld == null : thisWorld.equals(otherWorld)) &&
this.getContexts().equals(other.getContexts());
public abstract boolean areEqual(@Nonnull ImmutableNode o1, @Nonnull ImmutableNode o2);
}
@Override
@ -443,6 +471,13 @@ public final class ImmutableNode implements Node {
@Override
public String toString() {
return "ImmutableNode(permission=" + this.permission + ", value=" + this.value + ", override=" + this.override + ", server=" + this.getServer() + ", world=" + this.getWorld() + ", expireAt=" + this.expireAt + ", contexts=" + this.contexts + ")";
return "ImmutableNode(" +
"permission=" + this.permission + ", " +
"value=" + this.value + ", " +
"override=" + this.override + ", " +
"server=" + this.getServer() + ", " +
"world=" + this.getWorld() + ", " +
"expireAt=" + this.expireAt + ", " +
"contexts=" + this.contexts + ")";
}
}