001/* 002 * Copyright 2023 the original author or authors. 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.cuioss.test.valueobjects.objects; 017 018import static de.cuioss.tools.collect.CollectionLiterals.immutableList; 019import static java.util.Objects.requireNonNull; 020 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.HashSet; 025import java.util.List; 026import java.util.Map; 027import java.util.Set; 028import java.util.SortedSet; 029 030import de.cuioss.test.valueobjects.property.PropertyMetadata; 031import de.cuioss.test.valueobjects.property.PropertySupport; 032import de.cuioss.tools.collect.MapBuilder; 033import de.cuioss.tools.string.Joiner; 034import lombok.EqualsAndHashCode; 035import lombok.Getter; 036 037/** 038 * Aggregates all information necessary to dynamically create Objects. In 039 * addition it makes some sanity checks. It provides some convenience methods 040 * for accessing certain views on the properties. 041 * 042 * @author Oliver Wolff 043 */ 044@EqualsAndHashCode(of = "allProperties") 045public class RuntimeProperties { 046 047 /** 048 * All {@link PropertyMetadata} contained by this {@link RuntimeProperties}. May 049 * be empty 050 */ 051 @Getter 052 private final List<PropertyMetadata> allProperties; 053 054 /** 055 * All {@link PropertyMetadata} contained by this {@link RuntimeProperties} that 056 * are required: {@link PropertyMetadata#isRequired()}. May be an empty list. 057 */ 058 @Getter 059 private final List<PropertyMetadata> requiredProperties; 060 061 /** 062 * All {@link PropertyMetadata} contained by this {@link RuntimeProperties} that 063 * are <em>NOT</em> {@link PropertyMetadata#isRequired()}. May be an empty list. 064 */ 065 @Getter 066 private final List<PropertyMetadata> additionalProperties; 067 068 /** 069 * All {@link PropertyMetadata} contained by this {@link RuntimeProperties} that 070 * provide a {@link PropertyMetadata#isDefaultValue()}. May be an empty list. 071 */ 072 @Getter 073 private final List<PropertyMetadata> defaultProperties; 074 075 /** 076 * All {@link PropertyMetadata} contained by this {@link RuntimeProperties} 077 * where the properties can be written. May be an empty list. 078 */ 079 @Getter 080 private final List<PropertyMetadata> writableProperties; 081 082 /** 083 * Constructor. 084 * 085 * @param properties may be null 086 */ 087 public RuntimeProperties(final List<? extends PropertyMetadata> properties) { 088 if (null == properties) { 089 allProperties = Collections.emptyList(); 090 } else { 091 allProperties = immutableList(properties); 092 } 093 requiredProperties = allProperties.stream().filter(PropertyMetadata::isRequired).toList(); 094 095 additionalProperties = allProperties.stream().filter(metadata -> !metadata.isRequired()).toList(); 096 097 defaultProperties = allProperties.stream().filter(PropertyMetadata::isDefaultValue).toList(); 098 099 writableProperties = allProperties.stream().filter(metadata -> metadata.getPropertyReadWrite().isWriteable()) 100 .toList(); 101 } 102 103 /** 104 * @param properties 105 */ 106 public RuntimeProperties(final SortedSet<PropertyMetadata> properties) { 107 this(immutableList(properties)); 108 } 109 110 /** 111 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 112 * of the given {@link Collection} 113 * 114 * @param propertyMetadata if null or empty an empty list will be returned 115 * @param generateTestValue boolean indicating whether to call 116 * {@link PropertySupport#generateTestValue()} on each 117 * created element 118 * @return the newly created mutable {@link List} 119 */ 120 public static List<PropertySupport> mapToPropertySupport(final Collection<PropertyMetadata> propertyMetadata, 121 final boolean generateTestValue) { 122 final List<PropertySupport> list = new ArrayList<>(); 123 if (null == propertyMetadata || propertyMetadata.isEmpty()) { 124 return list; 125 } 126 propertyMetadata.forEach(p -> list.add(new PropertySupport(p))); 127 if (generateTestValue) { 128 list.forEach(PropertySupport::generateTestValue); 129 } 130 return list; 131 } 132 133 /** 134 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 135 * out of {@link #getAllProperties()} 136 * 137 * @param generateTestValue boolean indicating whether to call 138 * {@link PropertySupport#generateTestValue()} on each 139 * created element 140 * @return the newly created mutable {@link List} 141 */ 142 public List<PropertySupport> getAllAsPropertySupport(final boolean generateTestValue) { 143 return mapToPropertySupport(getAllProperties(), generateTestValue); 144 } 145 146 /** 147 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 148 * out of {@link #getAllProperties()} but filtered according to the given names. 149 * 150 * @param generateTestValue boolean indicating whether to call 151 * {@link PropertySupport#generateTestValue()} on each 152 * created element 153 * @param filter containing the names to be filtered, must not be 154 * null 155 * @return the newly created mutable {@link List} 156 */ 157 public List<PropertySupport> getAllAsPropertySupport(final boolean generateTestValue, 158 final Collection<String> filter) { 159 requireNonNull(filter); 160 return getAllAsPropertySupport(generateTestValue).stream().filter(s -> filter.contains(s.getName())).toList(); 161 } 162 163 /** 164 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 165 * out of {@link #getRequiredProperties()} 166 * 167 * @param generateTestValue boolean indicating whether to call 168 * {@link PropertySupport#generateTestValue()} on each 169 * created element 170 * @return the newly created mutable {@link List} 171 */ 172 public List<PropertySupport> getRequiredAsPropertySupport(final boolean generateTestValue) { 173 return mapToPropertySupport(getRequiredProperties(), generateTestValue); 174 } 175 176 /** 177 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 178 * out of {@link #getRequiredProperties()} but filtered according to the given 179 * names. 180 * 181 * @param generateTestValue boolean indicating whether to call 182 * {@link PropertySupport#generateTestValue()} on each 183 * created element 184 * @param filter containing the names to be filtered, must not be 185 * null 186 * @return the newly created mutable {@link List} 187 */ 188 public List<PropertySupport> getRequiredAsPropertySupport(final boolean generateTestValue, 189 final Collection<String> filter) { 190 requireNonNull(filter); 191 return getRequiredAsPropertySupport(generateTestValue).stream().filter(s -> filter.contains(s.getName())) 192 .toList(); 193 } 194 195 /** 196 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 197 * out of {@link #getDefaultProperties()} 198 * 199 * @param generateTestValue boolean indicating whether to call 200 * {@link PropertySupport#generateTestValue()} on each 201 * created element 202 * @return the newly created mutable {@link List} 203 */ 204 public List<PropertySupport> getDefaultAsPropertySupport(final boolean generateTestValue) { 205 return mapToPropertySupport(getDefaultProperties(), generateTestValue); 206 } 207 208 /** 209 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 210 * out of {@link #getDefaultProperties()} but filtered according to the given 211 * names. 212 * 213 * @param generateTestValue boolean indicating whether to call 214 * {@link PropertySupport#generateTestValue()} on each 215 * created element 216 * @param filter containing the names to be filtered, must not be 217 * null 218 * @return the newly created mutable {@link List} 219 */ 220 public List<PropertySupport> getDefaultAsPropertySupport(final boolean generateTestValue, 221 final Collection<String> filter) { 222 requireNonNull(filter); 223 return getDefaultAsPropertySupport(generateTestValue).stream().filter(s -> filter.contains(s.getName())) 224 .toList(); 225 } 226 227 /** 228 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 229 * out of {@link #getAdditionalProperties()} 230 * 231 * @param generateTestValue boolean indicating whether to call 232 * {@link PropertySupport#generateTestValue()} on each 233 * created element 234 * @return the newly created mutable {@link List} 235 */ 236 public List<PropertySupport> getAdditionalAsPropertySupport(final boolean generateTestValue) { 237 return mapToPropertySupport(getAdditionalProperties(), generateTestValue); 238 } 239 240 /** 241 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 242 * out of {@link #getAdditionalProperties()} 243 * 244 * @param generateTestValue boolean indicating whether to call 245 * {@link PropertySupport#generateTestValue()} on each 246 * created element 247 * @param filter containing the names to be filtered, must not be 248 * null 249 * @return the newly created mutable {@link List} 250 */ 251 public List<PropertySupport> getAdditionalAsPropertySupport(final boolean generateTestValue, 252 final Collection<String> filter) { 253 requireNonNull(filter); 254 return getAdditionalAsPropertySupport(generateTestValue).stream().filter(s -> filter.contains(s.getName())) 255 .toList(); 256 } 257 258 /** 259 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 260 * out of {@link #getWritableProperties()} 261 * 262 * @param generateTestValue boolean indicating whether to call 263 * {@link PropertySupport#generateTestValue()} on each 264 * created element 265 * @return the newly created mutable {@link List} 266 */ 267 public List<PropertySupport> getWritableAsPropertySupport(final boolean generateTestValue) { 268 return mapToPropertySupport(getWritableProperties(), generateTestValue); 269 } 270 271 /** 272 * Creates a list of {@link PropertySupport} for each {@link PropertyMetadata} 273 * out of {@link #getWritableProperties()} 274 * 275 * @param generateTestValue boolean indicating whether to call 276 * {@link PropertySupport#generateTestValue()} on each 277 * created element 278 * @param filter containing the names to be filtered, must not be 279 * null 280 * @return the newly created mutable {@link List} 281 */ 282 public List<PropertySupport> getWritableAsPropertySupport(final boolean generateTestValue, 283 final Collection<String> filter) { 284 requireNonNull(filter); 285 return getWritableAsPropertySupport(generateTestValue).stream().filter(s -> filter.contains(s.getName())) 286 .toList(); 287 } 288 289 /** 290 * @param generateTestValue boolean indicating whether to call 291 * {@link PropertySupport#generateTestValue()} on each 292 * created element 293 * @return a map view on all {@link PropertyMetadata} as {@link PropertySupport} 294 * with the property names as key 295 */ 296 public Map<String, PropertySupport> asMapView(final boolean generateTestValue) { 297 var builder = new MapBuilder<String, PropertySupport>(); 298 getAllAsPropertySupport(generateTestValue).forEach(p -> builder.put(p.getName(), p)); 299 return builder.toImmutableMap(); 300 } 301 302 /** 303 * Extracts the names of a given {@link Collection} of {@link PropertyMetadata} 304 * 305 * @param metadata if it is null or empty an empty {@link Set} will be returned 306 * @return a set of the extracted names. 307 */ 308 public static final Set<String> extractNames(final Collection<PropertyMetadata> metadata) { 309 if (null == metadata || metadata.isEmpty()) { 310 return Collections.emptySet(); 311 } 312 final Set<String> builder = new HashSet<>(); 313 metadata.forEach(m -> builder.add(m.getName())); 314 return builder; 315 } 316 317 @Override 318 public String toString() { 319 final var builder = new StringBuilder(getClass().getName()); 320 builder.append("\nRequired properties: ").append(getPropertyNames(requiredProperties)); 321 builder.append("\nAdditional properties: ").append(getPropertyNames(additionalProperties)); 322 builder.append("\nDefault valued properties: ").append(getPropertyNames(defaultProperties)); 323 builder.append("\nWritable properties: ").append(getPropertyNames(writableProperties)); 324 return builder.toString(); 325 } 326 327 private static String getPropertyNames(final List<PropertyMetadata> properties) { 328 if (null == properties || properties.isEmpty()) { 329 return "-"; 330 } 331 final List<String> names = new ArrayList<>(); 332 properties.forEach(p -> names.add(p.getName())); 333 return Joiner.on(", ").join(names); 334 } 335}