001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * docs/licenses/cddl.txt 011 * or http://www.opensource.org/licenses/cddl1.php. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * docs/licenses/cddl.txt. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2015-2021 Ping Identity Corporation 026 */ 027 028package com.unboundid.directory.sdk.broker.types; 029 030import com.unboundid.util.NotExtensible; 031 032import java.util.ArrayList; 033import java.util.Arrays; 034import java.util.Collection; 035import java.util.Collections; 036import java.util.LinkedList; 037 038 039 040/** 041 * An attribute in a Store Adapter's native schema. Use 042 * StoreAttributeDefinition.Builder to create instances of this class. 043 */ 044@NotExtensible() 045public final class StoreAttributeDefinition 046{ 047 /** 048 * An enumeration of the data types for values. 049 */ 050 public enum Type 051 { 052 /** 053 * String datatype. 054 */ 055 STRING("string"), 056 057 /** 058 * Boolean datatype. 059 */ 060 BOOLEAN("boolean"), 061 062 /** 063 * Decimal datatype. 064 */ 065 DECIMAL("decimal"), 066 067 /** 068 * Integer datatype. 069 */ 070 INTEGER("integer"), 071 072 /** 073 * Datetime datatype. 074 */ 075 DATETIME("datetime"), 076 077 /** 078 * Binary datatype. 079 */ 080 BINARY("binary"), 081 082 /** 083 * Reference datatype. 084 */ 085 REFERENCE("reference"), 086 087 /** 088 * Complex datatype. 089 */ 090 COMPLEX("complex"); 091 092 private String name; 093 094 /** 095 * Constructs an attribute data type object. 096 * @param name the name of the data type. 097 */ 098 Type(final String name) 099 { 100 this.name = name; 101 } 102 103 /** 104 * Gets the name of the type. 105 * 106 * @return the name of the type. 107 */ 108 public String getName() 109 { 110 return name; 111 } 112 113 /** 114 * Gets the Type matching the given name. Throws a runtime 115 * exception if the Type cannot be found because an invalid 116 * name was given. 117 * 118 * @param name the name of the type. 119 * @return the type matching the given name. 120 */ 121 public static Type fromName(final String name) 122 { 123 for(Type type : Type.values()) 124 { 125 if(type.getName().equals(name)) 126 { 127 return type; 128 } 129 } 130 131 throw new RuntimeException("Unknown StoreAttributeDefinition datatype"); 132 } 133 } 134 135 private final String name; 136 private final Type type; 137 private final String description; 138 private final Collection<StoreAttributeDefinition> subAttributes; 139 private final boolean multiValued; 140 141 /** 142 * Builder class to build an instance of StoreAttributeDefinition. 143 */ 144 public static class Builder 145 { 146 /** 147 * The name of the attribute. 148 */ 149 private String name; 150 151 /** 152 * The type of the attribute. For the possible values, see: 153 * {@link StoreAttributeDefinition.Type} 154 */ 155 private Type type; 156 157 /** 158 * The sub-attributes of a complex attribute. 159 */ 160 private Collection<StoreAttributeDefinition> subAttributes; 161 162 /** 163 * A boolean value indicating whether or not this attribute can have 164 * multiple values. 165 */ 166 private boolean multiValued; 167 168 /** 169 * The description of this attribute. 170 */ 171 private String description; 172 173 /** 174 * Create a new builder. 175 */ 176 public Builder() 177 { 178 type = Type.STRING; 179 } 180 181 /** 182 * Sets the attribute name. 183 * 184 * @param name the attribute name. 185 * @return this 186 */ 187 public Builder setName(final String name) 188 { 189 this.name = name; 190 return this; 191 } 192 193 /** 194 * Sets the type of the attribute. 195 * 196 * @param type the type of the attribute. 197 * @return this. 198 */ 199 public Builder setType(final Type type) 200 { 201 this.type = type; 202 return this; 203 } 204 205 /** 206 * Adds sub-attributes for a complex datatype attribute. 207 * 208 * @param subAttributes The sub-attributes of the attribute. 209 * @return this. 210 */ 211 public Builder addSubAttributes( 212 final StoreAttributeDefinition ... subAttributes) 213 { 214 if (subAttributes != null && subAttributes.length > 0) 215 { 216 if (this.subAttributes == null) 217 { 218 this.subAttributes = new LinkedList<StoreAttributeDefinition>(); 219 } 220 this.subAttributes.addAll(Arrays.asList(subAttributes)); 221 } 222 return this; 223 } 224 225 /** 226 * Sets a boolean indicating if the attribute is multi-valued. 227 * 228 * @param multiValued a boolean indicating if the attribute is multi-valued. 229 * @return this. 230 */ 231 public Builder setMultiValued(final boolean multiValued) 232 { 233 this.multiValued = multiValued; 234 return this; 235 } 236 237 /** 238 * Sets the description of the attribute. 239 * 240 * @param description the description of the attribute. 241 * @return this. 242 */ 243 public Builder setDescription(final String description) 244 { 245 this.description = description; 246 return this; 247 } 248 249 /** 250 * Clears all values in this builder, so that it can be reused. 251 * 252 * @return this. 253 */ 254 public Builder clear() 255 { 256 this.name = null; 257 this.type = Type.STRING; 258 this.subAttributes = null; 259 this.multiValued = false; 260 this.description = null; 261 return this; 262 } 263 264 /** 265 * Builds a new StoreAttributeDefinition. 266 * 267 * @return a new StoreAttributeDefinition. 268 */ 269 public StoreAttributeDefinition build() 270 { 271 return new StoreAttributeDefinition( 272 name, 273 type, 274 subAttributes, 275 multiValued, 276 description); 277 } 278 } 279 280 /** 281 * Create a new Attribute Definition. 282 * 283 * @param name The name of the attribute. 284 * @param type The attribute data type. 285 * @param subAttributes The sub-attributes of the attribute. 286 * @param multiValued A boolean indicating if the attribute is multi-valued. 287 * @param description The description of this attribute. 288 */ 289 private StoreAttributeDefinition( 290 final String name, 291 final Type type, 292 final Collection<StoreAttributeDefinition> subAttributes, 293 final boolean multiValued, 294 final String description) 295 { 296 this.name = name; 297 this.type = type; 298 this.subAttributes = subAttributes == null ? 299 null : Collections.unmodifiableList( 300 new ArrayList<StoreAttributeDefinition>(subAttributes)); 301 this.multiValued = multiValued; 302 this.description = description; 303 } 304 305 /** 306 * Determines if the attribute allows multiple values. 307 * 308 * @return true if the attribute is multivalued, or false if it is not. 309 */ 310 public boolean isMultiValued() 311 { 312 return multiValued; 313 } 314 315 /** 316 * Gets the type of the value for this attribute. 317 * 318 * @return type of the value for this attribute. 319 */ 320 public Type getType() 321 { 322 return type; 323 } 324 325 /** 326 * Gets the name of the attribute. 327 * 328 * @return the name of the attribute. 329 */ 330 public String getName() 331 { 332 return name; 333 } 334 335 /** 336 * Gets the description of the attribute. 337 * 338 * @return the description of the attribute. 339 */ 340 public String getDescription() 341 { 342 return description; 343 } 344 345 /** 346 * Gets the sub-attributes for a complex attribute. 347 * 348 * @return the sub-attributes for a complex attribute. 349 */ 350 public Collection<StoreAttributeDefinition> getSubAttributes() 351 { 352 return subAttributes; 353 } 354 355 /** 356 * Gets a string representation of the attribute. 357 * 358 * @return a string representation of the attribute. 359 */ 360 @Override 361 public String toString() 362 { 363 return toIndentedString(""); 364 } 365 366 /** 367 * Called by toString. This is used to format the output of the object 368 * a little to help readability. 369 * 370 * @param indent the string to use for each indent increment. For example, 371 * one might use " " for a 2 space indent. 372 * @return a string representation of this attribute. 373 */ 374 private String toIndentedString(final String indent) 375 { 376 StringBuilder builder = new StringBuilder(); 377 builder.append(indent); 378 builder.append("Name: "); 379 builder.append(getName()); 380 builder.append(" Description: "); 381 builder.append(getDescription()); 382 builder.append(" isReadOnly: "); 383 builder.append(System.lineSeparator()); 384 if(getSubAttributes() != null) 385 { 386 for (StoreAttributeDefinition a : getSubAttributes()) 387 { 388 builder.append(a.toIndentedString(indent + " ")); 389 } 390 } 391 return builder.toString(); 392 } 393 394 /** 395 * {@inheritDoc} 396 */ 397 @Override 398 public boolean equals(final Object o) 399 { 400 if (this == o) 401 { 402 return true; 403 } 404 if (o == null || getClass() != o.getClass()) 405 { 406 return false; 407 } 408 409 StoreAttributeDefinition that = (StoreAttributeDefinition) o; 410 411 if (multiValued != that.multiValued) 412 { 413 return false; 414 } 415 if (description != null ? !description.equals(that.description) : 416 that.description != null) 417 { 418 return false; 419 } 420 if (name != null ? !name.equals(that.name) : that.name != null) 421 { 422 return false; 423 } 424 if (subAttributes != null ? !subAttributes.equals(that.subAttributes) : 425 that.subAttributes != null) 426 { 427 return false; 428 } 429 if (type != null ? !type.equals(that.type) : that.type != null) 430 { 431 return false; 432 } 433 434 return true; 435 } 436 437 /** 438 * {@inheritDoc} 439 */ 440 @Override 441 public int hashCode() 442 { 443 int result = name != null ? name.hashCode() : 0; 444 result = 31 * result + (type != null ? type.hashCode() : 0); 445 result = 31 * result + (subAttributes != null ? 446 subAttributes.hashCode() : 0); 447 result = 31 * result + (multiValued ? 1 : 0); 448 result = 31 * result + (description != null ? description.hashCode() : 0); 449 return result; 450 } 451}