blob: fb6583c9c28143ce7f19436eaabdfd949319f427 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2021 Boeing
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Boeing - initial API and implementation
**********************************************************************/
package org.eclipse.osee.mim.internal;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.osee.framework.core.data.ArtifactId;
import org.eclipse.osee.framework.core.data.ArtifactToken;
import org.eclipse.osee.framework.core.data.ArtifactTypeToken;
import org.eclipse.osee.framework.core.data.AttributeTypeToken;
import org.eclipse.osee.framework.core.data.BranchId;
import org.eclipse.osee.framework.core.data.RelationTypeToken;
import org.eclipse.osee.framework.core.data.UserId;
import org.eclipse.osee.framework.core.enums.SystemUser;
import org.eclipse.osee.framework.jdk.core.result.XResultData;
import org.eclipse.osee.framework.jdk.core.type.NamedIdBase;
import org.eclipse.osee.framework.jdk.core.util.Lib;
import org.eclipse.osee.mim.ArtifactAccessor;
import org.eclipse.osee.mim.ArtifactInserter;
import org.eclipse.osee.mim.annotations.OseeArtifactAttribute;
import org.eclipse.osee.mim.annotations.OseeArtifactRequiredAttribute;
import org.eclipse.osee.orcs.OrcsApi;
import org.eclipse.osee.orcs.transaction.TransactionBuilder;
/**
* @author Luciano T. Vaglienti
* @param <T> Class to use for storing/presenting artifact information
*/
public class ArtifactInserterImpl<T> implements ArtifactInserter<T> {
private final OrcsApi orcsApi;
private ArtifactTypeToken artifactType;
private String objectTypeToInsert;
private final ArtifactAccessor<T> accessor;
ArtifactToken folder;
public ArtifactInserterImpl(ArtifactTypeToken artifactType, OrcsApi orcsApi, String objectTypeToInsert, ArtifactAccessor<T> accessor, ArtifactToken folder) {
this.setArtifactType(artifactType);
this.setObjectTypeToInsert(objectTypeToInsert);
this.orcsApi = orcsApi;
this.accessor = accessor;
this.folder = folder;
}
@Override
public XResultData addArtifact(T newArtifact, UserId account, BranchId branch) {
XResultData results = new XResultData();
try {
UserId user = account;
if (user == null) {
user = SystemUser.OseeSystem;
}
TransactionBuilder tx =
orcsApi.getTransactionFactory().createTransaction(branch, user, "Create " + this.getObjectTypeToInsert());
if (createAndValidateNewArtifact(newArtifact, branch, tx, results)) {
tx.commit();
}
} catch (Exception ex) {
results.error(Lib.exceptionToString(ex));
}
return results;
}
/**
* @return the artifactType
*/
public ArtifactTypeToken getArtifactType() {
return artifactType;
}
/**
* @param artifactType the artifactType to set
*/
public void setArtifactType(ArtifactTypeToken artifactType) {
this.artifactType = artifactType;
}
/**
* @return the objectTypeToInsert
*/
public String getObjectTypeToInsert() {
return objectTypeToInsert;
}
/**
* @param objectTypeToInsert the objectTypeToInsert to set
*/
public void setObjectTypeToInsert(String objectTypeToInsert) {
this.objectTypeToInsert = objectTypeToInsert;
}
private boolean createAndValidateNewArtifact(T newArtifact, BranchId branch, TransactionBuilder tx, XResultData results) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
ArtifactToken defArt = ArtifactToken.SENTINEL;
T foundArtifact = accessor.get(tx.getBranch(),
ArtifactId.valueOf((String) newArtifact.getClass().getMethod("getIdString").invoke(newArtifact)),
(Class<T>) newArtifact.getClass());
if (!this.validateFieldsExists(newArtifact).isEmpty()) {
results.error(this.validateFieldsExists(newArtifact));
return false;
}
if ((boolean) foundArtifact.getClass().getMethod("isValid").invoke(foundArtifact)) {
results.error(newArtifact.getClass().getCanonicalName() + " already exists.");
return false;
}
ArtifactToken writeFolder = tx.getWriteable(folder);
if (writeFolder.isInvalid()) {
writeFolder = orcsApi.getQueryFactory().fromBranch(branch).andId(folder).asArtifactOrSentinel();
}
if (writeFolder.isInvalid()) {
results.error("Folder cannot be null");
return false;
}
defArt = tx.createArtifact(writeFolder, artifactType,
(String) newArtifact.getClass().getMethod("getName").invoke(newArtifact));
results.setTitle("Add " + this.objectTypeToInsert + " " + defArt.getIdString());
List<String> idList = new LinkedList<String>();
idList.add(defArt.getIdString());
results.setIds(idList);
for (Field field : getAllFields(new LinkedList<Field>(), newArtifact.getClass())) {
field.setAccessible(true);
if (field.isAnnotationPresent(OseeArtifactAttribute.class)) {
Method getter = getGetter(newArtifact.getClass(), field.getName());
if (getter != null && getter.invoke(newArtifact) != null) {
tx.setSoleAttributeValue(defArt,
AttributeTypeToken.valueOf(
String.valueOf(field.getDeclaredAnnotation(OseeArtifactAttribute.class).attributeId())),
getter.invoke(newArtifact));
} else if (field.get(newArtifact) != null) {
tx.setSoleAttributeValue(defArt,
AttributeTypeToken.valueOf(
String.valueOf(field.getDeclaredAnnotation(OseeArtifactAttribute.class).attributeId())),
field.get(newArtifact));
}
}
}
return true;
}
private String validateFieldsExists(T newArtifact) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
String results = "";
for (Field field : getAllFields(new LinkedList<Field>(), newArtifact.getClass())) {
field.setAccessible(true);
if (field.isAnnotationPresent(OseeArtifactRequiredAttribute.class) && field.isAnnotationPresent(
OseeArtifactAttribute.class)) {
if (getGetter(newArtifact.getClass(),
field.getName()) != null && (getGetter(newArtifact.getClass(), field.getName()).invoke(
newArtifact) == null || getGetter(newArtifact.getClass(), field.getName()).invoke(newArtifact).equals(
""))) {
results = field.getName() + " must be set to a value";
}
}
}
return results;
}
@Override
public XResultData relateArtifact(ArtifactId artifactToRelate, ArtifactId artifactToRelateTo, RelationTypeToken relation, BranchId branch, UserId account) {
XResultData results = new XResultData();
try {
UserId user = account;
if (user == null) {
user = SystemUser.OseeSystem;
}
TransactionBuilder tx =
orcsApi.getTransactionFactory().createTransaction(branch, user, "Relate " + this.getObjectTypeToInsert());
tx.relate(artifactToRelateTo, relation, artifactToRelate);
tx.commit();
} catch (Exception ex) {
results.error(Lib.exceptionToString(ex));
}
return results;
}
@Override
public XResultData replaceArtifact(T newArtifact, UserId account, BranchId branch) {
XResultData results = new XResultData();
try {
UserId user = account;
if (user == null) {
user = SystemUser.OseeSystem;
}
TransactionBuilder tx =
orcsApi.getTransactionFactory().createTransaction(branch, user, "Replace " + this.getObjectTypeToInsert());
if (this.replaceExistingArtifact(newArtifact, branch, tx, results)) {
tx.commit();
}
} catch (Exception ex) {
results.error(Lib.exceptionToString(ex));
}
return results;
}
@Override
public XResultData patchArtifact(T newArtifact, UserId account, BranchId branch) {
XResultData results = new XResultData();
try {
UserId user = account;
if (user == null) {
user = SystemUser.OseeSystem;
}
TransactionBuilder tx =
orcsApi.getTransactionFactory().createTransaction(branch, user, "Replace " + this.getObjectTypeToInsert());
if (this.partialUpdateArtifact(newArtifact, branch, tx, results)) {
tx.commit();
}
} catch (Exception ex) {
results.error(Lib.exceptionToString(ex));
}
return results;
}
@Override
public XResultData unrelateArtifact(ArtifactId artifactToUnRelate, ArtifactId artifactToUnRelateFrom, RelationTypeToken relation, BranchId branch, UserId account) {
XResultData results = new XResultData();
try {
UserId user = account;
if (user == null) {
user = SystemUser.OseeSystem;
}
TransactionBuilder tx =
orcsApi.getTransactionFactory().createTransaction(branch, user, "Unrelate " + this.getObjectTypeToInsert());
tx.unrelate(artifactToUnRelateFrom, relation, artifactToUnRelate);
tx.commit();
} catch (Exception ex) {
results.error(Lib.exceptionToString(ex));
}
return results;
}
@Override
public XResultData removeArtifact(ArtifactId artifactToRemove, UserId account, BranchId branch) {
XResultData results = new XResultData();
try {
UserId user = account;
if (user == null) {
user = SystemUser.OseeSystem;
}
TransactionBuilder tx = orcsApi.getTransactionFactory().createTransaction(branch, user, "Delete Artifact");
tx.deleteArtifact(orcsApi.getQueryFactory().fromBranch(branch).andIsOfType(artifactType).andId(
artifactToRemove).asArtifact());
tx.commit();
} catch (Exception ex) {
results.error(Lib.exceptionToString(ex));
}
return results;
}
private boolean replaceExistingArtifact(T newArtifact, BranchId branch, TransactionBuilder tx, XResultData results) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
ArtifactToken defArt = ArtifactToken.SENTINEL;
T foundArtifact = accessor.get(tx.getBranch(),
ArtifactId.valueOf((String) newArtifact.getClass().getMethod("getIdString").invoke(newArtifact)),
(Class<T>) newArtifact.getClass());
if (!this.checkIfIdExists(newArtifact)) {
results.error("Artifact must contain an id");
}
if (!this.validateFieldsExists(newArtifact).isEmpty()) {
results.error(this.validateFieldsExists(newArtifact));
return false;
}
ArtifactToken writeFolder = tx.getWriteable(folder);
if (writeFolder.isInvalid()) {
writeFolder = orcsApi.getQueryFactory().fromBranch(branch).andId(folder).asArtifactOrSentinel();
}
if (writeFolder.isInvalid()) {
results.error("Folder cannot be null");
return false;
}
defArt = orcsApi.getQueryFactory().fromBranch(tx.getBranch()).andId(ArtifactId.valueOf(
(String) foundArtifact.getClass().getMethod("getIdString").invoke(foundArtifact))).asArtifactOrSentinel();
results.setTitle("Replace " + this.objectTypeToInsert + " " + defArt.getIdString());
List<String> idList = new LinkedList<String>();
idList.add(defArt.getIdString());
results.setIds(idList);
for (Field field : getAllFields(new LinkedList<Field>(), newArtifact.getClass())) {
field.setAccessible(true);
if (field.isAnnotationPresent(OseeArtifactAttribute.class)) {
Method getter = getGetter(newArtifact.getClass(), field.getName());
if (getter != null && getter.invoke(newArtifact) != null) {
tx.setSoleAttributeValue(defArt,
AttributeTypeToken.valueOf(
String.valueOf(field.getDeclaredAnnotation(OseeArtifactAttribute.class).attributeId())),
getter.invoke(newArtifact));
}
}
}
return true;
}
private boolean partialUpdateArtifact(T newArtifact, BranchId branch, TransactionBuilder tx, XResultData results) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
ArtifactToken defArt = ArtifactToken.SENTINEL;
T foundArtifact = accessor.get(tx.getBranch(),
ArtifactId.valueOf((String) newArtifact.getClass().getMethod("getIdString").invoke(newArtifact)),
(Class<T>) newArtifact.getClass());
if (!this.checkIfIdExists(newArtifact)) {
results.error("Artifact must contain an id");
}
ArtifactToken writeFolder = tx.getWriteable(folder);
if (writeFolder.isInvalid()) {
writeFolder = orcsApi.getQueryFactory().fromBranch(branch).andId(folder).asArtifactOrSentinel();
}
if (writeFolder.isInvalid()) {
results.error("Folder cannot be null");
return false;
}
defArt = orcsApi.getQueryFactory().fromBranch(tx.getBranch()).andId(ArtifactId.valueOf(
(String) foundArtifact.getClass().getMethod("getIdString").invoke(foundArtifact))).asArtifactOrSentinel();
results.setTitle("Edit " + this.objectTypeToInsert + " " + defArt.getIdString());
List<String> idList = new LinkedList<String>();
idList.add(defArt.getIdString());
results.setIds(idList);
for (Field field : getAllFields(new LinkedList<Field>(), newArtifact.getClass())) {
field.setAccessible(true);
if (field.isAnnotationPresent(OseeArtifactAttribute.class)) {
Method getter = getGetter(newArtifact.getClass(), field.getName());
if (getter != null && getter.invoke(newArtifact) != null && getter.invoke(newArtifact) != "") {
tx.setSoleAttributeValue(defArt,
AttributeTypeToken.valueOf(
String.valueOf(field.getDeclaredAnnotation(OseeArtifactAttribute.class).attributeId())),
getter.invoke(newArtifact));
}
}
}
return true;
}
private Method getGetter(Class<?> type, String name) {
for (Method method : type.getMethods()) {
if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 && !void.class.equals(
method.getReturnType())) {
//is a getter
if (method.getName().endsWith(name)) {
return method;
}
}
}
return null;
}
private boolean checkIfIdExists(T newArtifact) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Long Id = (Long) getGetter(getNamedIdBase(newArtifact.getClass()), "Id").invoke(newArtifact);
if (Id == null || Id <= 0L) {
return false;
}
return true;
}
Class<?> getNamedIdBase(Class<?> type) {
if (type.getSuperclass() != null) {
if (type.getSuperclass() == NamedIdBase.class) {
return type.getSuperclass();
}
return getNamedIdBase(type.getSuperclass());
}
return null;
}
List<Field> getAllFields(List<Field> fields, Class<?> type) {
fields.addAll(Arrays.asList(type.getDeclaredFields()));
if (type.getSuperclass() != null) {
getAllFields(fields, type.getSuperclass());
}
return fields;
}
}