| /******************************************************************************** |
| * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation |
| * |
| * See the NOTICE file(s) distributed with this work for additional |
| * information regarding copyright ownership. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| ********************************************************************************/ |
| |
| package org.eclipse.mdm.api.dflt.model; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Optional; |
| import java.util.function.Predicate; |
| import java.util.stream.Collectors; |
| |
| import org.eclipse.mdm.api.base.adapter.Core; |
| import org.eclipse.mdm.api.base.model.BaseEntity; |
| import org.eclipse.mdm.api.base.model.ContextComponent; |
| import org.eclipse.mdm.api.base.model.ContextRoot; |
| import org.eclipse.mdm.api.base.model.Deletable; |
| import org.eclipse.mdm.api.base.model.Sortable; |
| import org.eclipse.mdm.api.base.model.TestStep; |
| import org.eclipse.mdm.api.base.model.Value; |
| |
| /** |
| * Implementation of the template component entity type. A template attribute |
| * adds meta data to a {@link CatalogComponent} it is associated with. It always |
| * belongs to a template root or another template component. Its name has to be |
| * unique within all template components belonging to the same |
| * {@link TemplateRoot}. A template component may define {@link TemplateSensor}s |
| * where each extends a {@link CatalogSensor} provided by the associated {@code |
| * CatalogComponent}. It may define {@link TemplateAttribute}s where each |
| * uniquely extends a {@link CatalogAttribute} provided by the associated |
| * {@code CatalogComponent}. |
| * |
| * @since 1.0.0 |
| * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH |
| * @see CatalogComponent |
| * @see TemplateRoot |
| * @see TemplateAttribute |
| * @see TemplateSensor |
| */ |
| public class TemplateComponent extends BaseEntity implements Deletable, Sortable { |
| |
| // ====================================================================== |
| // Class variables |
| // ====================================================================== |
| |
| /** |
| * The optional flag {@code Predicate}. |
| */ |
| public static final Predicate<TemplateComponent> IS_OPTIONAL = TemplateComponent::isOptional; |
| |
| /** |
| * The mandatory flag {@code Predicate}. This is the inversion of |
| * {@link #IS_OPTIONAL} {@code Predicate}. |
| */ |
| public static final Predicate<TemplateComponent> IS_MANDATORY = IS_OPTIONAL.negate(); |
| |
| /** |
| * The default active flag {@code Predicate}. |
| */ |
| public static final Predicate<TemplateComponent> IS_DEFAULT_ACTIVE = TemplateComponent::isDefaultActive; |
| |
| /** |
| * The series constant flag {@code Predicate}. |
| */ |
| public static final Predicate<TemplateComponent> IS_SERIES_CONSTANT = TemplateComponent::isSeriesConstant; |
| |
| /** |
| * The series variable flag {@code Predicate}. This is the inversion of the |
| * {@link #IS_SERIES_CONSTANT} {@code Predicate}. |
| */ |
| public static final Predicate<TemplateComponent> IS_SERIES_VARIABLE = IS_SERIES_CONSTANT.negate(); |
| |
| /** |
| * The implicit create flag {@code Predicate}. This is an OR combination of |
| * {@link #IS_DEFAULT_ACTIVE} and {@link #IS_MANDATORY} {@code Predicate}s. |
| */ |
| public static final Predicate<TemplateComponent> IS_IMPLICIT_CREATE = IS_DEFAULT_ACTIVE.or(IS_MANDATORY); |
| |
| /** |
| * The 'TestStepSeriesVariable' attribute name. |
| */ |
| public static final String ATTR_SERIES_CONSTANT = "TestStepSeriesVariable"; |
| |
| /** |
| * The 'DefaultActive' attribute name. |
| */ |
| public static final String ATTR_DEFAULT_ACTIVE = "DefaultActive"; |
| |
| /** |
| * The 'Optional' attribute name. |
| */ |
| public static final String ATTR_OPTIONAL = "Optional"; |
| |
| // ====================================================================== |
| // Constructors |
| // ====================================================================== |
| |
| /** |
| * Constructor. |
| * |
| * @param core The {@link Core}. |
| */ |
| TemplateComponent(Core core) { |
| super(core); |
| } |
| |
| // ====================================================================== |
| // Public methods |
| // ====================================================================== |
| |
| /** |
| * Returns the optional flag of this template component. |
| * |
| * @return Returns {@code true} if it is allowed to omit a |
| * {@link ContextComponent} derived from this template component. |
| */ |
| public Boolean isOptional() { |
| return getValue(ATTR_OPTIONAL).extract(); |
| } |
| |
| /** |
| * Sets a new optional flag for this template component. |
| * |
| * @param optional The new optional flag. |
| */ |
| public void setOptional(Boolean optional) { |
| getValue(ATTR_OPTIONAL).set(optional); |
| } |
| |
| /** |
| * Returns the default active flag of this template component. |
| * |
| * @return Returns {@code true} if a {@link ContextComponent} has to be created |
| * automatically each time a new {@link ContextRoot} is derived from the |
| * {@link TemplateRoot} this template component belongs to. |
| */ |
| public Boolean isDefaultActive() { |
| return getValue(ATTR_DEFAULT_ACTIVE).extract(); |
| } |
| |
| /** |
| * Sets a new default active flag for this template component. |
| * |
| * @param defaultActive The new default active flag. |
| */ |
| public void setDefaultActive(Boolean defaultActive) { |
| getValue(ATTR_DEFAULT_ACTIVE).set(defaultActive); |
| } |
| |
| /** |
| * Returns the series constant flag of this template component. |
| * |
| * @return Returns {@code true} if the {@link ContextComponent}'s {@link Value}s |
| * across {@link TestStep} siblings contain the same values. |
| */ |
| public Boolean isSeriesConstant() { |
| return getValue(ATTR_SERIES_CONSTANT).extract(); |
| } |
| |
| /** |
| * Sets a new series constant flag for this template component. |
| * |
| * @param seriesConstant The new series constant flag. |
| */ |
| public void setSeriesConstant(Boolean seriesConstant) { |
| getValue(ATTR_SERIES_CONSTANT).set(seriesConstant); |
| } |
| |
| /** |
| * Returns the {@link CatalogComponent} this template component is associated |
| * with. |
| * |
| * @return The associated {@code CatalogComponent} is returned. |
| */ |
| public CatalogComponent getCatalogComponent() { |
| return getCore().getMutableStore().get(CatalogComponent.class); |
| } |
| |
| /** |
| * Returns the {@link TemplateRoot} this template component belongs to. |
| * |
| * @return The {@code TemplateRoot} is returned. |
| */ |
| public TemplateRoot getTemplateRoot() { |
| TemplateRoot templateRoot = getCore().getPermanentStore().get(TemplateRoot.class); |
| if (templateRoot == null) { |
| return getParentTemplateComponent() |
| .orElseThrow(() -> new IllegalStateException("Parent entity is unknown.")).getTemplateRoot(); |
| } |
| |
| return templateRoot; |
| } |
| |
| /** |
| * Returns the parent {@link TemplateComponent} of this template component. |
| * |
| * @return {@code Optional} is empty if this template component is an immediate |
| * child of the {@link TemplateRoot}. |
| * @see #getTemplateRoot() |
| */ |
| public Optional<TemplateComponent> getParentTemplateComponent() { |
| return Optional.ofNullable(getCore().getPermanentStore().get(TemplateComponent.class)); |
| } |
| |
| /** |
| * Returns the {@link TemplateAttribute} identified by given name. |
| * |
| * @param name The name of the {@code TemplateAttribute}. |
| * @return The {@code Optional} is empty if a {@code TemplateAttribute} with |
| * given name does not exist. |
| */ |
| public Optional<TemplateAttribute> getTemplateAttribute(String name) { |
| return getTemplateAttributes().stream().filter(ta -> ta.nameEquals(name)).findAny(); |
| } |
| |
| /** |
| * Returns all available {@link TemplateAttribute}s related to this template |
| * component. |
| * |
| * @return The returned {@code List} is unmodifiable. |
| */ |
| public List<TemplateAttribute> getTemplateAttributes() { |
| return getCore().getChildrenStore().get(TemplateAttribute.class); |
| } |
| |
| /** |
| * Removes the {@link TemplateAttribute} identified by given name. |
| * |
| * @param name Name of the {@code TemplateAttribute} that has to be removed. |
| * @return Returns {@code true} if the {@code TemplateAttribute} with given name |
| * has been removed. |
| */ |
| public boolean removeTemplateAttribute(String name) { |
| Optional<TemplateAttribute> templateAttribute = getTemplateAttribute(name); |
| if (templateAttribute.isPresent()) { |
| getCore().getChildrenStore().remove(templateAttribute.get()); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Returns the {@link TemplateComponent} identified by given name. |
| * |
| * <p> |
| * <b>NOTE:</b> The names of <u>all</u> template components belonging to the |
| * same {@link TemplateRoot} must have unique names (no matter they are |
| * immediate children or not). Therefore, if this template component does not |
| * have an immediate template component with the given name, this lookup request |
| * is recursively delegated to all of its child template components. |
| * |
| * @param name The name of the {@code TemplateComponent}. |
| * @return The {@code Optional} is empty if a {@code TemplateComponent} with |
| * given name does not exist (neither this template component nor one of |
| * its children has a template component with given name). |
| */ |
| public Optional<TemplateComponent> getTemplateComponent(String name) { |
| List<TemplateComponent> templateComponents = getTemplateComponents(); |
| Optional<TemplateComponent> templateComponent = templateComponents.stream().filter(tc -> tc.nameEquals(name)) |
| .findAny(); |
| if (templateComponent.isPresent()) { |
| return templateComponent; |
| } |
| |
| return templateComponents.stream().map(ct -> ct.getTemplateComponent(name)).filter(Optional::isPresent) |
| .map(Optional::get).findAny(); |
| } |
| |
| /** |
| * Returns all immediate {@link TemplateComponent}s related to this template |
| * component. |
| * |
| * @return The returned {@code List} is unmodifiable. |
| */ |
| public List<TemplateComponent> getTemplateComponents() { |
| return getCore().getChildrenStore().get(TemplateComponent.class); |
| } |
| |
| /** |
| * Removes the {@link TemplateComponent} identified by given name. |
| * |
| * <p> |
| * <b>NOTE:</b> The names of <u>all</u> template components belonging to the |
| * same {@link TemplateRoot} must have unique names (no matter they are |
| * immediate children or not). Therefore, if this template component does not |
| * have an immediate template component with the given name, this remove request |
| * is recursively delegated to all of its child template components. |
| * |
| * @param name Name of the {@code TemplateComponent} that has to be removed. |
| * @return Returns {@code true} if the {@code TemplateComponent} with given name |
| * has been removed. |
| */ |
| public boolean removeTemplateComponent(String name) { |
| Optional<TemplateComponent> templateComponent = getTemplateComponent(name); |
| if (templateComponent.isPresent()) { |
| Optional<TemplateComponent> parentTemplateComponent = templateComponent.get().getParentTemplateComponent(); |
| if (parentTemplateComponent.isPresent()) { |
| parentTemplateComponent.get().removeTemplateComponent(name); |
| } else { |
| getCore().getChildrenStore().remove(templateComponent.get()); |
| } |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Returns the {@link TemplateSensor} identified by given name. |
| * |
| * @param name The name of the {@code TemplateSensor}. |
| * @return The {@code Optional} is empty if a {@code TemplateSensor} with given |
| * name does not exist. |
| */ |
| public Optional<TemplateSensor> getTemplateSensor(String name) { |
| return getTemplateSensors().stream().filter(ts -> ts.nameEquals(name)).findAny(); |
| } |
| |
| /** |
| * Returns all available {@link TemplateSensor}s related to this template |
| * component. |
| * |
| * @return The returned {@code List} is unmodifiable. |
| */ |
| public List<TemplateSensor> getTemplateSensors() { |
| if (getCatalogComponent().getContextType().isTestEquipment()) { |
| return getCore().getChildrenStore().get(TemplateSensor.class); |
| } |
| |
| return Collections.emptyList(); |
| } |
| |
| /** |
| * Removes the {@link TemplateSensor} identified by given name. |
| * |
| * @param name Name of the {@code TemplateSensor} that has to be removed. |
| * @return Returns {@code true} if the {@code TemplateSensor} with given name |
| * has been removed. |
| */ |
| public boolean removeTemplateSensor(String name) { |
| Optional<TemplateSensor> templateSensor = getTemplateSensor(name); |
| if (templateSensor.isPresent()) { |
| getCore().getChildrenStore().remove(templateSensor.get()); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('('); |
| sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", "))); |
| |
| List<TemplateAttribute> templateAttributes = getTemplateAttributes(); |
| if (!templateAttributes.isEmpty()) { |
| sb.append(", TemplateAttributes = ").append(templateAttributes); |
| } |
| |
| List<TemplateSensor> templateSensors = getTemplateSensors(); |
| if (!templateSensors.isEmpty()) { |
| sb.append(", TemplateSensors = ").append(templateSensors); |
| } |
| |
| List<TemplateComponent> templateComponents = getTemplateComponents(); |
| if (!templateComponents.isEmpty()) { |
| sb.append(", TemplateComponents = ").append(templateComponents); |
| } |
| |
| return sb.append(')').toString(); |
| } |
| |
| /** |
| * Returns the {@link TemplateComponent} the given {@link ContextComponent} is |
| * derived from. |
| * |
| * @param contextComponent The {@code ContextComponent} whose {@code |
| * TemplateComponent} is requested. |
| * @return {@code Optional} is empty if the given {@code ContextComponent} is |
| * not derived from a template, which is data source specific. |
| */ |
| public static Optional<TemplateComponent> of(ContextComponent contextComponent) { |
| return Optional.ofNullable(getCore(contextComponent).getMutableStore().get(TemplateComponent.class)); |
| } |
| |
| } |