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.subject; 018 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024 025/** 026 * Subject data set for a specific configuration of properties. 027 * 028 * <p>Segments are immutable, so any changes will produce a new object.</p> 029 * 030 * @since 2.0.0 031 */ 032public interface Segment { 033 034 int PERMISSION_UNSET = 0; 035 036 /** 037 * Get options registered in a single context set. 038 * 039 * @return the options, as an immutable map 040 * @since 2.0.0 041 */ 042 Map<String, String> options(); 043 044 /** 045 * Return a new segment with updated option information. 046 * 047 * @param key the key of the option to set. Must be unique. 048 * @param value the value to set attached to the key 049 * @return an updated segment 050 * @since 2.0.0 051 */ 052 Segment withOption(final String key, final String value); 053 054 /** 055 * Return a new segment with an option removed, if it is present 056 * 057 * @param key the key of the option to remove 058 * @return an updated segment, or the same segment if no such option was present 059 * @since 2.0.0 060 */ 061 Segment withoutOption(final String key); 062 063 /** 064 * Return a new segment with an entirely new set of options 065 * 066 * @param values the options to set 067 * @return an updated segment 068 * @since 2.0.0 069 */ 070 Segment withOptions(final Map<String, String> values); 071 072 /** 073 * Return a new segment with all options unset. 074 * 075 * @return a new segment with no options information. 076 * @since 2.0.0 077 */ 078 default Segment withoutOptions() { 079 return withOptions(Collections.emptyMap()); 080 } 081 082 /** 083 * Get permissions data for a single context in this subject. 084 * 085 * @return an immutable map from permission to value 086 * @since 2.0.0 087 */ 088 Map<String, Integer> permissions(); 089 090 /** 091 * Set a single permission to a specific value. 092 * 093 * <p>Values greater than zero evaluate to true, values less than zero evaluate to false, 094 * and equal to zero will unset the permission. Higher absolute values carry more weight.</p> 095 * 096 * @param permission the permission to set 097 * @param value the value. Zero to unset. 098 * @return an updated segment 099 * @since 2.0.0 100 */ 101 Segment withPermission(final String permission, final int value); 102 103 /** 104 * Set all permissions. 105 * 106 * @param values a map from permissions to their values 107 * @return an updated segment object 108 * @since 2.0.0 109 */ 110 Segment withPermissions(Map<String, Integer> values); 111 112 /** 113 * Return a new segment with all permissions unset. 114 * 115 * @return the updated segment 116 * @since 2.0.0 117 */ 118 Segment withoutPermissions(); 119 120 /** 121 * Get parents in this segment 122 * 123 * @return an immutable list of parents 124 * @since 2.0.0 125 */ 126 List<? extends SubjectRef<?>> parents(); 127 128 /** 129 * Update a segment with an added parent. 130 * 131 * <p>This parent will be added at the beginning of the list of parents, meaning it will have 132 * higher priority than any existing parents.</p> 133 * 134 * @param type the type of the parent subject being added 135 * @param identifier the identifier of the parent subject being added 136 * @return an updated segment 137 * @since 2.0.0 138 */ 139 default <I> Segment plusParent(SubjectType<I> type, I identifier) { 140 return this.plusParent(SubjectRef.subject(type, identifier)); 141 } 142 143 /** 144 * Update a new segment with an added parent. 145 * 146 * <p>This parent will be added at the end of the list of parents, meaning it will have lower 147 * priority than any existing parents.</p> 148 * 149 * @param subject a reference to the subject that should be added as parent. 150 * @param <I> identifier type 151 * @return an updated segment 152 * @since 2.0.0 153 */ 154 <I> Segment plusParent(SubjectRef<I> subject); 155 156 /** 157 * Update a new segment to remove the passed parent. 158 * 159 * @param type the type of the parent subject being removed 160 * @param identifier the identifier of the parent subject being removed 161 * @return an updated segment 162 * @since 2.0.0 163 */ 164 default <I> Segment minusParent(SubjectType<I> type, I identifier) { 165 return this.minusParent(SubjectRef.subject(type, identifier)); 166 } 167 168 /** 169 * Remove a single parent subject in this segment. 170 * 171 * @param subject a reference to the subject that should be added as parent. 172 * @param <I> identifier type 173 * @return an updated segment 174 * @since 2.0.0 175 */ 176 <I> Segment minusParent(final SubjectRef<I> subject); 177 178 /** 179 * Update a new segment with the provided {@code parents}. 180 * 181 * @param parents the parents that will be written 182 * @return an updated segment 183 * @since 2.0.0 184 */ 185 Segment withParents(List<SubjectRef<?>> parents); 186 187 /** 188 * Remove all parents from this segment. 189 * 190 * @return an updated segment 191 * @since 2.0.0 192 */ 193 Segment withoutParents(); 194 195 /** 196 * Get the fallback permissions value for this segment. 197 * 198 * This is the value that will be returned for permissions that do not match anything 199 * more specific. 200 * 201 * @return the default value in the given context set, or 0 if none is set. 202 * @since 2.0.0 203 */ 204 int fallbackPermission(); 205 206 /** 207 * Update a new segment with a new fallback permission. 208 * 209 * @param defaultValue the default value to apply. A default value of 0 is equivalent to unset 210 * @return an updated segment 211 * @since 2.0.0 212 */ 213 Segment withFallbackPermission(int defaultValue); 214 215 /** 216 * Return a new segment with no data set. 217 * 218 * @return the cleared segment 219 * @since 2.0.0 220 */ 221 Segment cleared(); 222 223 /** 224 * Return {@code true} if this segment has no set data. 225 * 226 * @return if this sement is empty 227 * @since 2.0.0 228 */ 229 boolean empty(); 230 231 /** 232 * Add all data from the segment {@code other} to this one. 233 * 234 * @param other the source segment 235 * @return an updated segment 236 * @since 2.0.0 237 */ 238 default Segment mergeFrom(final Segment other) { 239 if (other.empty()) { 240 return this; 241 } else if (this.empty()) { 242 return other; 243 } 244 245 Segment output = this; 246 final Map<String, Integer> permissions = other.permissions(); 247 final Map<String, String> options = other.options(); 248 final List<? extends SubjectRef<?>> parents = other.parents(); 249 250 if (!permissions.isEmpty()) { 251 final Map<String, Integer> newPermissions = new HashMap<>(output.permissions()); 252 newPermissions.putAll(permissions); 253 output = output.withPermissions(newPermissions); 254 } 255 256 if (!options.isEmpty()) { 257 final Map<String, String> newOptions = new HashMap<>(output.options()); 258 newOptions.putAll(options); 259 output = output.withOptions(newOptions); 260 } 261 262 if (!parents.isEmpty()) { 263 final List<SubjectRef<?>> newParents = new ArrayList<>(output.parents()); 264 newParents.addAll(parents); 265 output = output.withParents(newParents); 266 } 267 268 return output; 269 } 270}