001/* 002 * PermissionsEx 003 * Copyright (C) zml and PermissionsEx contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * 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 */ 017package ca.stellardrift.permissionsex.context; 018 019import org.checkerframework.checker.nullness.qual.Nullable; 020 021/** 022 * A (key, value) pair for one specific context entry. 023 * 024 * <p>This value holds both raw and parsed context values.</p> 025 * 026 * @param <V> value type 027 */ 028public final class ContextValue<V> { 029 private final String key; 030 private final String rawValue; 031 private @Nullable ContextDefinition<V> definition; 032 private @Nullable V parsedValue; 033 034 public ContextValue(final String key, final String rawValue) { 035 this.key = key; 036 this.rawValue = rawValue; 037 } 038 039 ContextValue(final ContextDefinition<V> def, final V value) { 040 this(def.name(), def.serialize(value)); 041 this.definition = def; 042 this.parsedValue = value; 043 } 044 045 /** 046 * Get the key used to resolve a context value. 047 * 048 * @return value key 049 */ 050 public String key() { 051 return this.key; 052 } 053 054 /** 055 * The raw value, before being deserialized by a context definition. 056 * 057 * @return raw value, as provided by the user 058 */ 059 public String rawValue() { 060 return this.rawValue; 061 } 062 063 public @Nullable ContextDefinition<V> definition() { 064 return this.definition; 065 } 066 067 public @Nullable V parsedValue() { 068 return this.parsedValue; 069 } 070 071 @SuppressWarnings("unchecked") 072 public boolean tryResolve(final ContextDefinitionProvider provider) { 073 if (this.definition != null && !(this.definition instanceof SimpleContextDefinition.Fallback)) { 074 return this.parsedValue != null; 075 } 076 final @Nullable ContextDefinition<V> definition = (ContextDefinition<V>) provider.contextDefinition(this.key); 077 if (definition != null) { 078 this.definition = definition; 079 this.parsedValue = definition.deserialize(this.rawValue); 080 return this.parsedValue != null; 081 } 082 return false; 083 } 084 085 public V getParsedValue(final ContextDefinition<V> definition) { 086 if (this.definition != null && !this.definition.equals(definition)) { 087 throw new IllegalStateException("The provided context definition does not match the one this context object currently knows about"); 088 } 089 090 this.definition = definition; 091 @Nullable V parsedValue = this.parsedValue; 092 if (parsedValue == null) { 093 parsedValue = definition.deserialize(this.rawValue); 094 this.parsedValue = parsedValue; 095 } 096 if (parsedValue == null) { 097 throw new IllegalArgumentException("Invalid value provided for context " + definition.name()); 098 } 099 return parsedValue; 100 } 101 102 @SuppressWarnings("unchecked") 103 public V getParsedValue(final ContextDefinitionProvider provider) { 104 @Nullable V tempParsed = parsedValue; 105 if (tempParsed != null) { 106 return tempParsed; 107 } 108 109 final @Nullable ContextDefinition<?> def = provider.contextDefinition(this.key); 110 tempParsed = def == null ? null : (V) def.deserialize(this.rawValue); 111 if (tempParsed == null) { 112 throw new RuntimeException("No definition for context " + this.key); 113 } 114 115 parsedValue = tempParsed; 116 return tempParsed; 117 } 118 119 @Override 120 public boolean equals(final @Nullable Object other) { 121 if (this == other) return true; 122 if (!(other instanceof ContextValue<?>)) return false; 123 124 final ContextValue<?> that = (ContextValue<?>) other; 125 if (!this.key.equals(that.key)) return false; 126 if (!this.rawValue.equals(that.rawValue)) return false; 127 128 return true; 129 } 130 131 @Override 132 public int hashCode() { 133 int result = this.key.hashCode(); 134 result = 31 * result + this.rawValue.hashCode(); 135 return result; 136 } 137 138 @Override 139 public String toString() { 140 return this.key + ":" + this.parsedValue + " (raw: " + this.rawValue + ")"; 141 } 142}