All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.mmm.property.builder.PropertyBuilder Maven / Gradle / Ivy

/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0
 * http://www.apache.org/licenses/LICENSE-2.0 */
package io.github.mmm.property.builder;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import io.github.mmm.base.metainfo.MetaInfo;
import io.github.mmm.property.AttributeReadOnly;
import io.github.mmm.property.Property;
import io.github.mmm.property.PropertyMetadata;
import io.github.mmm.property.builder.container.ListPropertyBuilder;
import io.github.mmm.property.builder.container.MapPropertyBuilder;
import io.github.mmm.property.builder.container.SetPropertyBuilder;
import io.github.mmm.property.object.SimpleProperty;
import io.github.mmm.validation.Validator;
import io.github.mmm.validation.main.ObjectValidatorBuilder;

/**
 * Abstract base class for a {@link io.github.mmm.base.lang.Builder} to create instances of a particular type of
 * {@link Property}. 
* As a {@link Property} typically has only one single required parameter that is also the most specific parameter, it * is provided to the {@link #build(String) build-method}. Therefore {@link ProcessBuilder} does not implement * {@link io.github.mmm.base.lang.Builder} and does not follow the default builder-pattern providing a non-arg * {@link io.github.mmm.base.lang.Builder#build() build()} method.
* For a specific {@link Property} type the builder should carry the same name with the suffix {@code Builder}. Example: * {@link io.github.mmm.property.booleans.BooleanProperty} is build by * {@link io.github.mmm.property.builder.lang.BooleanPropertyBuilder}. * * @param type of the {@link Property#get() property value}. * @param

type of the {@link Property} to build. * @param type of the {@link ObjectValidatorBuilder validator builder} for {@link #withValidator()}. * @param type of this {@link PropertyBuilder} itself. * * @since 1.0.0 */ public abstract class PropertyBuilder, B extends ObjectValidatorBuilder, ?>, SELF extends PropertyBuilder> { /** @see #getLock() */ protected final AttributeReadOnly lock; private Consumer registry; private Function factory; private B validatorBuilder; /** @see #valueExpression(Supplier) */ protected Supplier expression; /** @see #value(Object) */ protected V value; private Map metadataMap; /** * The constructor. * * @param lock the {@link #getLock() lock}. */ public PropertyBuilder(AttributeReadOnly lock) { super(); this.lock = lock; } /** * @return this object itself ({@code this}) for fluent API calls. */ @SuppressWarnings("unchecked") protected SELF self() { return (SELF) this; } /** * @return the {@link PropertyMetadata#getLock() lock}. */ public AttributeReadOnly getLock() { return this.lock; } /** * @param consumer the {@link Consumer} {@link Consumer#accept(Object) receiving} the {@link Property} when * {@link #build(String) build}. * @return this builder itself ({@code this}) for fluent API calls. */ public SELF registry(Consumer consumer) { if (this.registry != null) { throw new IllegalStateException("Registry consumer already set!"); } this.registry = consumer; return self(); } /** * @param function the {@link Function} optionally {@link Function#apply(Object) providing} the {@link Property} to * {@link #build(String) build}. If it returns a result other than {@code null} this will be used instead and * the actual building is entirely replaced. This is a very specific feature provided for internal usage (to * receive read-only view of already existing property). * @return this builder itself ({@code this}) for fluent API calls. */ public SELF factory(Function function) { if (this.factory != null) { throw new IllegalStateException("Factory function already set!"); } this.factory = function; return self(); } /** * @param propertyValueExpression the {@link io.github.mmm.property.PropertyMetadata#getExpression() property value * expression}. * @return this builder itself ({@code this}) for fluent API calls. */ public SELF valueExpression(Supplier propertyValueExpression) { this.expression = propertyValueExpression; return self(); } /** * @param initialValue the {@link Property#get() initial value} of the {@link Property} to build. * @return this builder itself ({@code this}) for fluent API calls. */ public SELF value(V initialValue) { this.value = initialValue; return self(); } /** * @param metaKey the {@link io.github.mmm.base.metainfo.MetaInfo#get(String) meta-info key}. * @param metaValue the {@link io.github.mmm.base.metainfo.MetaInfo#get(String) meta-info value}. * @return this builder itself ({@code this}) for fluent API calls. */ public SELF metaInfo(String metaKey, String metaValue) { if (this.metadataMap == null) { this.metadataMap = new HashMap<>(); } this.metadataMap.put(metaKey, metaValue); return self(); } /** * @return the {@link ObjectValidatorBuilder} corresponding to this type of builder. */ protected abstract B createValidatorBuilder(); /** * @return a sub-builder for the {@link PropertyMetadata#getValidator() validator} of the {@link Property} to build. * Use the {@link ObjectValidatorBuilder#and() and()} method to return from the sub-builder to this property * builder when the validator is configured. */ public B withValidator() { if (this.validatorBuilder == null) { this.validatorBuilder = createValidatorBuilder(); } return this.validatorBuilder; } /** * @param name the {@link Property#getName() property name} of the {@link Property} to build. * @return the {@link Property} to build. */ public final P build(String name) { return build(name, false); } /** * @param name the {@link Property#getName() property name} of the {@link Property} to build. * @param ignoreExtensions - {@code true} to ignore a potential {@link #registry(Consumer)} and * {@link #factory(Function)}, {@code false} otherwise. * @return the {@link Property} to build. */ protected final P build(String name, boolean ignoreExtensions) { P property = null; if ((this.factory != null) && !ignoreExtensions) { property = this.factory.apply(name); } if (property == null) { property = build(name, newMetadata()); if (this.value != null) { property.set(this.value); } } if ((this.registry != null) && !ignoreExtensions) { this.registry.accept(property); } return property; } private PropertyMetadata newMetadata() { Validator validator = null; if (this.validatorBuilder != null) { validator = this.validatorBuilder.build(); } return PropertyMetadata.of(this.lock, validator, null, MetaInfo.empty().with(this.metadataMap)); } /** * @param name the {@link Property#getName() property name} of the {@link Property} to build. * @param newMetadata the {@link PropertyMetadata}. * @return the {@link Property} to {@link #build(String) build}. */ protected abstract P build(String name, PropertyMetadata newMetadata); /** * @return a {@link ListPropertyBuilder} using {@link #build(String) this property configuration} for its elements. */ public ListPropertyBuilder asList() { return builder(new ListPropertyBuilder<>(this.lock, build("ListItem", true))); } /** * @return a {@link SetPropertyBuilder} using {@link #build(String) this property configuration} for its elements. */ public SetPropertyBuilder asSet() { return builder(new SetPropertyBuilder<>(this.lock, build("SetItem", true))); } /** * @return a {@link MapPropertyBuilder} using {@link #build(String) this property configuration} for its values and * {@link String} as keys. */ public MapPropertyBuilder asMap() { return builder(new MapPropertyBuilder<>(this.lock, build("MapItem", true))); } /** * @param type of the {@link PropertyBuilder}. * @param builder the {@link PropertyBuilder}. * @return the configured {@code builder}. */ @SuppressWarnings({ "unchecked", "rawtypes" }) protected > T builder(T builder) { if (this.registry != null) { builder.registry((Consumer) this.registry); } if (this.factory != null) { builder.factory((Function) this.factory); } return builder; } /** * @param type of the {@link Map#containsKey(Object) keys}. * @param keyProperty the {@link io.github.mmm.property.container.map.MapProperty#getKeyProperty() key property}. * @return a {@link MapPropertyBuilder} using {@link #build(String) this property configuration} for its values and * {@link String} as keys. */ public MapPropertyBuilder asMap(SimpleProperty keyProperty) { return new MapPropertyBuilder<>(this.lock, keyProperty, build("Value")); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy