blob: bf451577ea48826943c60fddaf68c9d2bbe38f32 [file] [log] [blame]
/*
* Copyright (c) 2016 Gigatronik Ingolstadt GmbH
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.mdm.api.base.model;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.eclipse.mdm.api.base.core.ChildrenStore;
import org.eclipse.mdm.api.base.core.Core;
import org.eclipse.mdm.api.base.core.EntityStore;
/**
* Implementation of an abstract entity factory which creates new entities.
*
* @since 1.0.0
* @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
* @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
*/
public abstract class BaseEntityFactory {
// ======================================================================
// Public methods
// ======================================================================
/**
* Creates a new {@link Channel}. The name of the returned {@code Channel}
* is retrieved from given {@link Quantity}.
*
* @param measurement
* The parent {@link Measurement}.
* @param quantity
* The {@code Quantity} is used for default initialization.
* @return The created {@code Channel} is returned.
*/
public Channel createChannel(Measurement measurement, Quantity quantity) {
return createChannel(quantity.getDefaultChannelName(), measurement, quantity);
}
/**
* Creates a new {@link Channel}.
*
* @param name
* Name of the created {@code Channel}.
* @param measurement
* The parent {@link Measurement}.
* @param quantity
* The {@code Quantity} is used for default initialization.
* @return The created {@code Channel} is returned.
*/
public Channel createChannel(String name, Measurement measurement, Quantity quantity) {
Channel channel = new Channel(createCore(Channel.class));
// relations
getPermanentStore(channel).set(measurement);
getChildrenStore(measurement).add(channel);
getMutableStore(channel).set(quantity.getDefaultUnit());
getMutableStore(channel).set(quantity);
// properties
channel.setName(name);
channel.setDescription(quantity.getDescription());
channel.setInterpolation(Interpolation.NONE);
channel.setScalarType(quantity.getDefaultScalarType());
channel.setRank(quantity.getDefaultRank());
channel.setTypeSize(quantity.getDefaultTypeSize());
return channel;
}
/**
* Creates a new {@link ChannelGroup}.
*
* @param name
* Name of the created {@code ChannelGroup}.
* @param numberOfValues
* The number of values per each related {@link Channel}.
* @param measurement
* The parent {@link Measurement}.
* @return The created {@code ChannelGroup} is returned.
* @throws IllegalArgumentException
* Thrown if numberOfValues is negative.
*/
public ChannelGroup createChannelGroup(String name, int numberOfValues, Measurement measurement) {
if (numberOfValues < 0) {
throw new IllegalArgumentException("Number of values must be equal or greater than 0.");
}
ChannelGroup channelGroup = new ChannelGroup(createCore(ChannelGroup.class));
// relations
getPermanentStore(channelGroup).set(measurement);
getChildrenStore(measurement).add(channelGroup);
// properties
channelGroup.setName(name);
channelGroup.setNumberOfValues(Integer.valueOf(numberOfValues));
return channelGroup;
}
/**
* Creates a new {@link Measurement}.
*
* @param name
* Name of the created {@code Measurement}.
* @param testStep
* The parent {@link TestStep}.
* @param contextRoots
* {@link ContextRoot}s containing the descriptive data.
* @return The created {@code Measurement} is returned.
*/
public Measurement createMeasurement(String name, TestStep testStep, ContextRoot... contextRoots) {
Measurement measurement = new Measurement(createCore(Measurement.class));
// relations
getPermanentStore(measurement).set(testStep);
getChildrenStore(testStep).add(measurement);
for (ContextRoot contextRoot : contextRoots) {
getMutableStore(measurement).set(contextRoot, contextRoot.getContextType());
}
// properties
measurement.setName(name);
measurement.setDateCreated(LocalDateTime.now());
return measurement;
}
/**
* Creates a new {@link Parameter} with initialized with given value.
*
* @param name
* Name of the created {@code Parameter}.
* @param value
* The value of the created {@code Parameter}.
* @param unit
* An optionally related {@link Unit}.
* @param parameterSet
* The parent {@link ParameterSet}.
* @return The created {@code Parameter} is returned.
* @throws IllegalArgumentException
* Thrown if the {@code ParameterSet} already contains a
* {@code Parameter} with given name.
* @see Parameter#setObjectValue(Object, Unit)
*/
public Parameter createParameter(String name, Object value, Unit unit, ParameterSet parameterSet) {
if (parameterSet.getParameter(name).isPresent()) {
throw new IllegalArgumentException("Parameter with name '" + name + "' already exists.");
}
Parameter parameter = new Parameter(createCore(Parameter.class));
// relations
getPermanentStore(parameter).set(parameterSet);
getChildrenStore(parameterSet).add(parameter);
// properties
parameter.setName(name);
parameter.setObjectValue(value, unit);
return parameter;
}
/**
* Creates a new {@link ParameterSet} for given {@link Measurement}.
*
* @param name
* Name of the created {@code ParameterSet}.
* @param version
* Version of the created {@code ParameterSet}.
* @param measurement
* The owning {@code Measurement}.
* @return The created {@code ParameterSet} is returned.
*/
public ParameterSet createParameterSet(String name, String version, Measurement measurement) {
ParameterSet parameterSet = new ParameterSet(createCore(ParameterSet.class));
// relations
getPermanentStore(parameterSet).set(measurement);
getChildrenStore(measurement).add(parameterSet);
// properties
parameterSet.setName(name);
parameterSet.setVersion(version);
return parameterSet;
}
/**
* Creates a new {@link ParameterSet} for given {@link Channel}.
*
* @param name
* Name of the created {@code ParameterSet}.
* @param version
* Version of the created {@code ParameterSet}.
* @param channel
* The owning {@code Channel}.
* @return The created {@code ParameterSet} is returned.
*/
public ParameterSet createParameterSet(String name, String version, Channel channel) {
ParameterSet parameterSet = new ParameterSet(createCore(ParameterSet.class));
// relations
getPermanentStore(parameterSet).set(channel);
getChildrenStore(channel).add(parameterSet);
// properties
parameterSet.setName(name);
parameterSet.setVersion(version);
return parameterSet;
}
/**
* Creates a new {@link PhysicalDimension}.
*
* @param name
* Name of the created {@code PhysicalDimension}.
* @return The created {@code PhysicalDimension} is returned.
*/
public PhysicalDimension createPhysicalDimension(String name) {
PhysicalDimension physicalDimension = new PhysicalDimension(createCore(PhysicalDimension.class));
// properties
physicalDimension.setName(name);
physicalDimension.setLength(Integer.valueOf(0));
physicalDimension.setMass(Integer.valueOf(0));
physicalDimension.setTime(Integer.valueOf(0));
physicalDimension.setTemperature(Integer.valueOf(0));
physicalDimension.setCurrent(Integer.valueOf(0));
physicalDimension.setMolarAmount(Integer.valueOf(0));
physicalDimension.setLuminousIntensity(Integer.valueOf(0));
physicalDimension.setAngle(Integer.valueOf(0));
return physicalDimension;
}
/**
* Creates a new {@link Quantity}.
*
* @param name
* Name of the created {@code Quantity}.
* @param defaultUnit
* The default {@link Unit}.
* @return The created {@code Quantity} is returned.
*/
public Quantity createQuantity(String name, Unit defaultUnit) {
Quantity quantity = new Quantity(createCore(Quantity.class));
// relations
getMutableStore(quantity).set(defaultUnit);
// properties
quantity.setName(name);
quantity.setDateCreated(LocalDateTime.now());
quantity.setDefaultRank(Integer.valueOf(1));
quantity.setDefaultDimension(new int[] { 0 });
quantity.setDefaultTypeSize(Integer.valueOf(1));
quantity.setDefaultChannelName(name);
quantity.setDefaultScalarType(ScalarType.FLOAT);
quantity.getValue("Version").set("1");
quantity.getValue("ValidFlag").set(VersionState.VALID);
return quantity;
}
/**
* Creates a new {@link Test} with a reference to the logged in
* {@link User}, if there is one.
*
* @param name
* Name of the created {@code Test}.
* @return The created {@code Test} is returned.
*/
public Test createTest(String name) {
Test test = new Test(createCore(Test.class));
// relations
Optional<User> responsiblePerson = getLoggedInUser();
if (responsiblePerson.isPresent()) {
// may be null if user entities are not available
getMutableStore(test).set(responsiblePerson.get());
}
// properties
test.setName(name);
test.setDateCreated(LocalDateTime.now());
return test;
}
/**
* Creates a new {@link TestStep}.
*
* @param name
* Name of the created {@code TestStep}.
* @param test
* The parent {@link Test}.
* @return The created {@code TestStep} is returned.
*/
public TestStep createTestStep(String name, Test test) {
TestStep testStep = new TestStep(createCore(TestStep.class));
// relations
getPermanentStore(testStep).set(test);
getChildrenStore(test).add(testStep);
// properties
testStep.setName(name);
testStep.setDateCreated(LocalDateTime.now());
testStep.setOptional(Boolean.TRUE);
if (test.getID() != null && test.getID().length() > 0) {
// highest sort index in use will be queried before written
testStep.setSortIndex(Integer.valueOf(-1));
} else {
testStep.setSortIndex(nextIndex(getChildrenStore(test).get(TestStep.class)));
}
return testStep;
}
/**
* Creates a new {@link Unit}.
*
* @param name
* Name of the created {@code Unit}.
* @param physicalDimension
* The {@link PhysicalDimension}.
* @return The created {@code Unit} is returned.
*/
public Unit createUnit(String name, PhysicalDimension physicalDimension) {
Unit unit = new Unit(createCore(Unit.class));
// relations
getMutableStore(unit).set(physicalDimension);
// properties
unit.setName(name);
unit.setOffset(Double.valueOf(0D));
unit.setFactor(Double.valueOf(1D));
return unit;
}
/**
* Creates a new {@link User}.
*
* @param name
* Name of the created {@code User}.
* @param givenName
* Given name of the created {@code User}.
* @param surname
* Surname of the created {@code User}.
* @return The created {@code User} is returned.
*/
public User createUser(String name, String givenName, String surname) {
User user = new User(createCore(User.class));
// properties
user.setName(name);
user.setGivenName(givenName);
user.setSurname(surname);
return user;
}
// ======================================================================
// Protected methods
// ======================================================================
/**
* Creates a new {@link ContextRoot}.
*
* @param name
* Name of the created {@code ContextRoot}.
* @param contextType
* {@link ContextType} of the created {@code ContextRoot}.
* @return The created {@code ContextRoot} is returned.
*/
protected ContextRoot createContextRoot(String name, ContextType contextType) {
ContextRoot contextRoot = new ContextRoot(createCore(ContextRoot.class, contextType));
// properties
contextRoot.setName(name);
contextRoot.setVersion(String.valueOf(0));
return contextRoot;
}
/**
* Creates a new {@link ContextComponent}.
*
* @param name
* Name of the created {@code ContextComponent}.
* @param contextRoot
* The parent {@link ContextRoot}.
* @return The created {@code ContextComponent} is returned.
*/
protected ContextComponent createContextComponent(String name, ContextRoot contextRoot) {
ContextComponent contextComponent = new ContextComponent(createCore(name, ContextComponent.class));
// relations
getPermanentStore(contextComponent).set(contextRoot);
getChildrenStore(contextRoot).add(contextComponent);
// properties
contextComponent.setName(name);
return contextComponent;
}
/**
* Creates a new {@link ContextSensor}.
*
* @param name
* Name of the created {@code ContextSensor}.
* @param contextComponent
* The parent {@link ContextComponent}.
* @return The created {@code ContextSensor} is returned.
*/
protected ContextSensor createContextSensor(String name, ContextComponent contextComponent) {
ContextSensor contextSensor = new ContextSensor(createCore(name, ContextSensor.class));
// relations
getPermanentStore(contextSensor).set(contextComponent);
getChildrenStore(contextComponent).add(contextSensor);
// properties
contextSensor.setName(name);
return contextSensor;
}
/**
* Returns the next usable sort index for given {@code List} of
* {@link Sortable}s.
*
* @param sortables
* The {@code Sortable} whose max sort index will be searched.
* @return {@code 1} is returned if given {@code List} is empty, otherwise
* the max sort index increased by 1 is returned.
*/
protected static final Integer nextIndex(List<? extends Sortable> sortables) {
Optional<Integer> maxIndex = sortables.stream().max(Sortable.COMPARATOR).map(Sortable::getSortIndex);
return Integer.valueOf(maxIndex.isPresent() ? maxIndex.get().intValue() + 1 : 1);
}
/**
* Returns the {@link ChildrenStore} for given {@link BaseEntity}.
*
* @param entity
* The {@code BaseEntity} whose {@code ChildrenStore} will be
* returned.
* @return The {@code ChildrenStore} is returned.
*/
protected static final ChildrenStore getChildrenStore(BaseEntity entity) {
return getCore(entity).getChildrenStore();
}
/**
* Returns the mutable {@link EntityStore} for given {@link BaseEntity}.
*
* @param entity
* The {@code BaseEntity} whose {@code ChildrenStore} will be
* returned.
* @return The mutable {@code EntityStore} is returned.
*/
protected static final EntityStore getMutableStore(BaseEntity entity) {
return getCore(entity).getMutableStore();
}
/**
* Returns the permanent {@link EntityStore} for given {@link BaseEntity}.
*
* @param entity
* The {@code BaseEntity} whose {@code ChildrenStore} will be
* returned.
* @return The permanent {@code EntityStore} is returned.
*/
protected static final EntityStore getPermanentStore(BaseEntity entity) {
return getCore(entity).getPermanentStore();
}
/**
* Returns {@link Core} of given {@link Entity}. Uses protected method from
* BaseEntity, which is accessible here as BaseEntity resides in the same
* package as BaseEntityFactory. By declaring this method protected, the
* Core-related functionality is hidden from other classes since the only
* classes which can access them (outside this package) are derivatives of
* BaseEntityFactory, and it is through such derivatives that a BaseEntity's
* Core should be accessed elsewhere if needed.
*
* @param entity
* The {@code BaseEntity} whose {@code Core} is required.
* @return The {@code Core} is returned.
*/
protected static final Core getCore(BaseEntity entity) {
return entity.getCore();
}
/**
* Create an instance of {@link BaseEntity} (or derivative) with core as the
* instance's {@link Core}. By declaring this method protected, the Core-related
* functionality is hidden from other classes since the only classes which can
* access them (outside this package) are derivatives of BaseEntityFactory, and
* it is through such derivatives that a BaseEntity's Core should be accessed
* elsewhere if needed.
*
* @param clazz
* The class to instantiate, must extend {@link BaseEntity}.
* @param core
* The {@link Core} to use for the newly created instance.
* @return The newly created instance.
*/
protected static final <T extends BaseEntity> T createBaseEntity(Class<T> clazz, Core core) {
Constructor<T> constructor = null;
boolean isAccessible = false;
try {
constructor = clazz.getDeclaredConstructor(Core.class);
isAccessible = constructor.isAccessible();
constructor.setAccessible(true);
return constructor.newInstance(core);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException
| InstantiationException exc) {
throw new IllegalStateException(exc.getMessage(), exc);
} finally {
if (null != constructor) {
constructor.setAccessible(isAccessible);
}
}
}
/**
* Returns the {@link User} which is bound to the current session.
*
* @return {@code Optional} is empty if {@code User} entities do not exist.
*/
protected abstract Optional<User> getLoggedInUser();
/**
* Returns a new {@link Core} for given entity class.
*
* @param <T>
* The entity class type.
* @param entityClass
* The entity class.
* @return A new {@code Core} instance is returned.
*/
protected abstract <T extends Entity> Core createCore(Class<T> entityClass);
/**
* Returns a new {@link Core} for given entity class and
* {@link ContextType}.
*
* @param <T>
* The entity class type.
* @param entityClass
* The entity class.
* @param contextType
* The {@code ContextType}.
* @return A new {@code Core} instance is returned.
*/
protected abstract <T extends Entity> Core createCore(Class<T> entityClass, ContextType contextType);
/**
* Returns a new {@link Core} for given entity class and type name.
*
* @param <T>
* The entity class type.
* @param name
* Name of the entity type.
* @param entityClass
* The entity class.
* @return A new {@code Core} instance is returned.
*/
protected abstract <T extends Entity> Core createCore(String name, Class<T> entityClass);
}