| /******************************************************************************* |
| * Copyright (c) 2004, 2007 Boeing. |
| * 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 |
| * |
| * Contributors: |
| * Boeing - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osee.framework.skynet.core.artifact; |
| |
| import static org.eclipse.osee.framework.core.enums.CoreRelationTypes.Default_Hierarchical__Child; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.logging.Level; |
| import java.util.regex.Pattern; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.osee.framework.core.data.IArtifactToken; |
| import org.eclipse.osee.framework.core.data.IArtifactType; |
| import org.eclipse.osee.framework.core.data.IAttributeType; |
| import org.eclipse.osee.framework.core.data.IOseeBranch; |
| import org.eclipse.osee.framework.core.data.IRelationSorterId; |
| import org.eclipse.osee.framework.core.data.IRelationType; |
| import org.eclipse.osee.framework.core.data.IRelationTypeSide; |
| import org.eclipse.osee.framework.core.data.NamedIdentity; |
| import org.eclipse.osee.framework.core.enums.CoreAttributeTypes; |
| import org.eclipse.osee.framework.core.enums.CoreRelationTypes; |
| import org.eclipse.osee.framework.core.enums.DeletionFlag; |
| import org.eclipse.osee.framework.core.enums.EditState; |
| import org.eclipse.osee.framework.core.enums.LoadLevel; |
| import org.eclipse.osee.framework.core.enums.ModificationType; |
| import org.eclipse.osee.framework.core.enums.RelationOrderBaseTypes; |
| import org.eclipse.osee.framework.core.enums.RelationSide; |
| import org.eclipse.osee.framework.core.enums.SystemUser; |
| import org.eclipse.osee.framework.core.exception.ArtifactDoesNotExist; |
| import org.eclipse.osee.framework.core.exception.AttributeDoesNotExist; |
| import org.eclipse.osee.framework.core.exception.MultipleArtifactsExist; |
| import org.eclipse.osee.framework.core.exception.MultipleAttributesExist; |
| import org.eclipse.osee.framework.core.exception.OseeArgumentException; |
| import org.eclipse.osee.framework.core.exception.OseeCoreException; |
| import org.eclipse.osee.framework.core.exception.OseeDataStoreException; |
| import org.eclipse.osee.framework.core.exception.OseeExceptions; |
| import org.eclipse.osee.framework.core.exception.OseeStateException; |
| import org.eclipse.osee.framework.core.model.Branch; |
| import org.eclipse.osee.framework.core.model.RelationTypeSide; |
| import org.eclipse.osee.framework.core.model.TransactionRecord; |
| import org.eclipse.osee.framework.core.model.event.DefaultBasicGuidArtifact; |
| import org.eclipse.osee.framework.core.model.event.DefaultBasicGuidRelationReorder; |
| import org.eclipse.osee.framework.core.model.event.IBasicGuidArtifact; |
| import org.eclipse.osee.framework.core.model.type.ArtifactType; |
| import org.eclipse.osee.framework.core.model.type.AttributeType; |
| import org.eclipse.osee.framework.core.model.type.RelationType; |
| import org.eclipse.osee.framework.core.operation.Operations; |
| import org.eclipse.osee.framework.jdk.core.type.HashCollection; |
| import org.eclipse.osee.framework.jdk.core.type.Pair; |
| import org.eclipse.osee.framework.jdk.core.util.Collections; |
| import org.eclipse.osee.framework.jdk.core.util.GUID; |
| import org.eclipse.osee.framework.jdk.core.util.Lib; |
| import org.eclipse.osee.framework.jdk.core.util.Strings; |
| import org.eclipse.osee.framework.logging.OseeLog; |
| import org.eclipse.osee.framework.messaging.event.res.AttributeEventModificationType; |
| import org.eclipse.osee.framework.skynet.core.AccessPolicy; |
| import org.eclipse.osee.framework.skynet.core.OseeSystemArtifacts; |
| import org.eclipse.osee.framework.skynet.core.User; |
| import org.eclipse.osee.framework.skynet.core.UserManager; |
| import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; |
| import org.eclipse.osee.framework.skynet.core.attribute.AttributeTypeManager; |
| import org.eclipse.osee.framework.skynet.core.event.model.AttributeChange; |
| import org.eclipse.osee.framework.skynet.core.internal.Activator; |
| import org.eclipse.osee.framework.skynet.core.internal.ServiceUtil; |
| import org.eclipse.osee.framework.skynet.core.relation.RelationLink; |
| import org.eclipse.osee.framework.skynet.core.relation.RelationManager; |
| import org.eclipse.osee.framework.skynet.core.relation.RelationTypeManager; |
| import org.eclipse.osee.framework.skynet.core.relation.RelationTypeSideSorter; |
| import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; |
| import org.eclipse.osee.framework.skynet.core.transaction.TransactionManager; |
| import org.eclipse.osee.framework.skynet.core.types.IArtifact; |
| |
| /** |
| * {@link ArtifactTest} |
| */ |
| |
| public class Artifact extends NamedIdentity<String> implements IArtifact, IAdaptable, IBasicGuidArtifact { |
| public static final String UNNAMED = "Unnamed"; |
| public static final String BEFORE_GUID_STRING = "/BeforeGUID/PrePend"; |
| public static final String AFTER_GUID_STRING = "/AfterGUID"; |
| public static final int TRANSACTION_SENTINEL = -1; |
| |
| private final HashCollection<IAttributeType, Attribute<?>> attributes = |
| new HashCollection<IAttributeType, Attribute<?>>(false, LinkedList.class, 12); |
| private final Set<DefaultBasicGuidRelationReorder> relationOrderRecords = |
| new HashSet<DefaultBasicGuidRelationReorder>(); |
| private final IOseeBranch branch; |
| private final String humanReadableId; |
| private ArtifactType artifactType; |
| private final ArtifactFactory parentFactory; |
| private int transactionId = TRANSACTION_SENTINEL; |
| private int artId; |
| private int gammaId; |
| private boolean linksLoaded; |
| private boolean historical; |
| private ModificationType modType; |
| private ModificationType lastValidModType; |
| private EditState objectEditState; |
| |
| public Artifact(ArtifactFactory parentFactory, String guid, String humanReadableId, IOseeBranch branch, IArtifactType artifactType) throws OseeCoreException { |
| super(GUID.checkOrCreate(guid), ""); |
| objectEditState = EditState.NO_CHANGE; |
| modType = ModificationType.NEW; |
| |
| this.humanReadableId = humanReadableId; |
| this.parentFactory = parentFactory; |
| this.branch = branch; |
| this.artifactType = ArtifactTypeManager.getType(artifactType); |
| } |
| |
| public final boolean isInDb() { |
| return transactionId != TRANSACTION_SENTINEL; |
| } |
| |
| /** |
| * A historical artifact always corresponds to a fixed revision of an artifact |
| * |
| * @return whether this artifact represents a fixed revision |
| */ |
| public final boolean isHistorical() { |
| return historical; |
| } |
| |
| /** |
| * All the artifacts related to this artifact by relations of type relationType are returned in a list order based on |
| * the stored relation order use getRelatedArtifacts(Artifact artifact, IRelationEnumeration relationEnum) instead |
| * (or similar variant) |
| */ |
| @Deprecated |
| public final List<? extends IArtifact> getRelatedArtifacts(RelationType relationType) throws OseeCoreException { |
| return RelationManager.getRelatedArtifacts(this, new RelationTypeSide(relationType, RelationSide.SIDE_B)); |
| } |
| |
| @Override |
| public final List<? extends IArtifact> getRelatedArtifacts(RelationTypeSide relationTypeSide) throws OseeCoreException { |
| return RelationManager.getRelatedArtifacts(this, relationTypeSide); |
| } |
| |
| public final List<Artifact> getRelatedArtifactsUnSorted(IRelationTypeSide relationEnum) throws OseeCoreException { |
| return RelationManager.getRelatedArtifactsUnSorted(this, relationEnum); |
| } |
| |
| public final List<Artifact> getRelatedArtifacts(IRelationTypeSide relationEnum) throws OseeCoreException { |
| return RelationManager.getRelatedArtifacts(this, relationEnum); |
| } |
| |
| public final List<Artifact> getRelatedArtifacts(IRelationTypeSide relationEnum, DeletionFlag deletionFlag) throws OseeCoreException { |
| return RelationManager.getRelatedArtifacts(this, relationEnum, deletionFlag); |
| } |
| |
| public final String getRelationRationale(Artifact artifact, IRelationTypeSide relationTypeSide) throws OseeCoreException { |
| Pair<Artifact, Artifact> sides = determineArtifactSides(artifact, relationTypeSide); |
| RelationLink link = RelationManager.getRelationLink(sides.getFirst(), sides.getSecond(), relationTypeSide); |
| return link.getRationale(); |
| } |
| |
| public final void setRelationRationale(Artifact artifact, IRelationTypeSide relationTypeSide, String rationale) throws OseeCoreException { |
| Pair<Artifact, Artifact> sides = determineArtifactSides(artifact, relationTypeSide); |
| RelationLink link = RelationManager.getRelationLink(sides.getFirst(), sides.getSecond(), relationTypeSide); |
| link.setRationale(rationale); |
| } |
| |
| private Pair<Artifact, Artifact> determineArtifactSides(Artifact artifact, IRelationTypeSide relationSide) { |
| boolean sideA = relationSide.getSide().isSideA(); |
| Artifact artifactA = sideA ? artifact : this; |
| Artifact artifactB = sideA ? this : artifact; |
| return new Pair<Artifact, Artifact>(artifactA, artifactB); |
| } |
| |
| /** |
| * Check if artifacts are related to each other by relation type |
| */ |
| public final boolean isRelated(IRelationTypeSide relationEnum, Artifact other) throws OseeCoreException { |
| List<Artifact> relatedArtifacts = getRelatedArtifacts(relationEnum); |
| return relatedArtifacts.contains(other); |
| } |
| |
| /** |
| * Get the exactly one artifact related to this artifact by a relation of type relationType |
| */ |
| public final Artifact getRelatedArtifact(IRelationTypeSide relationEnum) throws OseeCoreException { |
| return RelationManager.getRelatedArtifact(this, relationEnum); |
| } |
| |
| public final int getRelatedArtifactsCount(IRelationTypeSide relationEnum) { |
| return RelationManager.getRelatedArtifactsCount(this, relationEnum, relationEnum.getSide()); |
| } |
| |
| public final <A extends Artifact> List<A> getRelatedArtifactsUnSorted(IRelationTypeSide side, Class<A> clazz) throws OseeCoreException { |
| return Collections.castAll(getRelatedArtifactsUnSorted(side)); |
| } |
| |
| public final <A extends Artifact> List<A> getRelatedArtifacts(IRelationTypeSide side, Class<A> clazz) throws OseeCoreException { |
| return Collections.castAll(getRelatedArtifacts(side)); |
| } |
| |
| @SuppressWarnings("unchecked") |
| public final <A extends Artifact> List<A> getRelatedArtifactsOfType(IRelationTypeSide side, Class<A> clazz) throws OseeCoreException { |
| List<A> objs = new ArrayList<A>(); |
| for (Artifact art : getRelatedArtifacts(side)) { |
| if (clazz.isInstance(art)) { |
| objs.add((A) art); |
| } |
| } |
| return objs; |
| } |
| |
| @Override |
| public final int getArtId() { |
| return artId; |
| } |
| |
| public final int getArtTypeId() { |
| return artifactType.getId(); |
| } |
| |
| @Override |
| public final IOseeBranch getBranch() { |
| return branch; |
| } |
| |
| public final Branch getFullBranch() throws OseeCoreException { |
| return BranchManager.getBranch(branch); |
| } |
| |
| public final String getArtifactTypeName() { |
| return artifactType.getName(); |
| } |
| |
| /** |
| * Determines if this artifact's type equals, or is a sub-type of, at least one of the given artifact types. |
| */ |
| public final boolean isOfType(IArtifactType... artifactTypes) { |
| return artifactType.inheritsFrom(artifactTypes); |
| } |
| |
| @Override |
| public String toString() { |
| return getName(); |
| } |
| |
| /* |
| * Provide easy way to display/report [hrid][name] |
| */ |
| public final String toStringWithId() { |
| return String.format("[%s][%s]", getHumanReadableId(), getName()); |
| } |
| |
| // TODO should not return null but currently application code expects it to |
| /** |
| * The method should be used when the caller expects this artifact to have exactly one parent. Otherwise use |
| * hasParent() to safely determine whether |
| */ |
| public final Artifact getParent() throws OseeCoreException { |
| Artifact toReturn = null; |
| List<Artifact> artifacts = getRelatedArtifactsUnSorted(CoreRelationTypes.Default_Hierarchical__Parent); |
| int parentCount = artifacts.size(); |
| if (parentCount == 1) { |
| toReturn = artifacts.iterator().next(); |
| } else if (parentCount > 1) { |
| throw new MultipleArtifactsExist("artifact [%s] has %d parents", humanReadableId, parentCount); |
| } |
| return toReturn; |
| } |
| |
| /** |
| * @return Returns a list of parents starting with this Artifact and ending with the same Artifact that is returned |
| * from getArtifactRoot(). |
| * @throws OseeCoreException |
| */ |
| public final List<Artifact> getAncestors() throws OseeCoreException { |
| List<Artifact> ancestors = new ArrayList<Artifact>(); |
| |
| for (Artifact parent = getParent(); parent != null; parent = parent.getParent()) { |
| ancestors.add(parent); |
| } |
| return ancestors; |
| } |
| |
| public final Attribute<?> getAttributeById(int attrId, boolean includeDeleted) throws OseeCoreException { |
| for (Attribute<?> attribute : getAttributes(includeDeleted)) { |
| if (attribute.getId() == attrId) { |
| return attribute; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @return whether this artifact has exactly one parent artifact related by a relation of type default hierarchical |
| * @throws MultipleArtifactsExist if this artifact has more than one parent |
| */ |
| public final boolean hasParent() throws OseeCoreException { |
| int parentCount = getRelatedArtifactsUnSorted(CoreRelationTypes.Default_Hierarchical__Parent).size(); |
| if (parentCount > 1) { |
| throw new MultipleArtifactsExist("artifact [%s] has %d parents", humanReadableId, parentCount); |
| } |
| return parentCount == 1; |
| } |
| |
| public final boolean isOrphan() throws OseeCoreException { |
| Artifact root = OseeSystemArtifacts.getDefaultHierarchyRootArtifact(getBranch()); |
| |
| if (root.equals(getArtifactRoot())) { |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| /** |
| * @return the highest level parent of this artifact which will equal to |
| * OseeSystemArtifacts.getDefaultHierarchyRootArtifact(artifact.getBranch()) except when this artifact is an orphan |
| */ |
| public final Artifact getArtifactRoot() throws OseeCoreException { |
| Artifact artifactRoot = null; |
| |
| for (Artifact parent = getParent(); parent != null; parent = parent.getParent()) { |
| artifactRoot = parent; |
| } |
| return artifactRoot; |
| } |
| |
| public final Artifact getChild(String descriptiveName) throws OseeCoreException { |
| for (Artifact artifact : getChildren()) { |
| if (artifact.getName().equals(descriptiveName)) { |
| return artifact; |
| } |
| } |
| throw new ArtifactDoesNotExist("artifact [%s] has no child with the name [%s]", this, descriptiveName); |
| } |
| |
| public final boolean hasChild(String descriptiveName) throws OseeCoreException { |
| for (Artifact artifact : getChildren()) { |
| if (artifact.getName().equals(descriptiveName)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @return set of the direct children of this artifact |
| */ |
| public final List<Artifact> getChildren() throws OseeCoreException { |
| return getRelatedArtifacts(Default_Hierarchical__Child); |
| } |
| |
| /** |
| * @return set of the direct children of this artifact |
| */ |
| public final List<Artifact> getChildren(DeletionFlag deletionFlag) throws OseeCoreException { |
| return getRelatedArtifacts(Default_Hierarchical__Child, deletionFlag); |
| } |
| |
| /** |
| * @return a list of artifacts ordered by a depth first traversal of this artifact's descendants |
| */ |
| public final List<Artifact> getDescendants() throws OseeCoreException { |
| List<Artifact> descendants = new LinkedList<Artifact>(); |
| getDescendants(descendants); |
| return descendants; |
| } |
| |
| private void getDescendants(Collection<Artifact> descendants) throws OseeCoreException { |
| for (Artifact child : getChildren()) { |
| descendants.add(child); |
| child.getDescendants(descendants); |
| } |
| } |
| |
| public final List<Artifact> getDescendantsWithArtTypes(Collection<ArtifactType> descendantTypes) throws OseeCoreException { |
| List<Artifact> descendants = new LinkedList<Artifact>(); |
| for (Artifact child : getChildren()) { |
| ArtifactType childArtType = child.getArtifactType(); |
| if (descendantTypes.contains(childArtType)) { |
| descendants.add(child); |
| } |
| child.getDescendants(descendants); |
| } |
| return descendants; |
| } |
| |
| public final void addChild(Artifact artifact) throws OseeCoreException { |
| addChild(RelationOrderBaseTypes.PREEXISTING, artifact); |
| } |
| |
| public final void addChild(IRelationSorterId sorterId, Artifact artifact) throws OseeCoreException { |
| addRelation(sorterId, Default_Hierarchical__Child, artifact); |
| } |
| |
| public final Artifact addNewChild(IRelationSorterId sorterId, IArtifactType artifactType, String name) throws OseeCoreException { |
| Artifact child = ArtifactTypeManager.addArtifact(artifactType, branch); |
| child.setName(name); |
| addChild(sorterId, child); |
| return child; |
| } |
| |
| /** |
| * Creates an instance of <code>Attribute</code> of the given attribute type. This method should not be called by |
| * applications. Use addAttribute() instead |
| */ |
| @SuppressWarnings("unchecked") |
| private <T> Attribute<T> createAttribute(IAttributeType attributeType) throws OseeCoreException { |
| Class<? extends Attribute<T>> attributeClass = |
| (Class<? extends Attribute<T>>) AttributeTypeManager.getAttributeBaseClass(attributeType); |
| Attribute<T> attribute = null; |
| try { |
| attribute = attributeClass.newInstance(); |
| attributes.put(attributeType, attribute); |
| } catch (InstantiationException ex) { |
| OseeExceptions.wrapAndThrow(ex); |
| } catch (IllegalAccessException ex) { |
| OseeExceptions.wrapAndThrow(ex); |
| } |
| return attribute; |
| } |
| |
| private <T> Attribute<T> initializeAttribute(IAttributeType attributeType, ModificationType modificationType, boolean markDirty, boolean setDefaultValue) throws OseeCoreException { |
| Attribute<T> attribute = createAttribute(attributeType); |
| attribute.internalInitialize(attributeType, this, modificationType, markDirty, setDefaultValue); |
| return attribute; |
| } |
| |
| public final <T> Attribute<T> internalInitializeAttribute(IAttributeType attributeType, int attributeId, int gammaId, ModificationType modificationType, boolean markDirty, Object... data) throws OseeCoreException { |
| Attribute<T> attribute = createAttribute(attributeType); |
| attribute.internalInitialize(attributeType, this, modificationType, attributeId, gammaId, markDirty, false); |
| attribute.getAttributeDataProvider().loadData(data); |
| return attribute; |
| } |
| |
| public final boolean isAttributeTypeValid(IAttributeType attributeType) throws OseeCoreException { |
| return getArtifactType().isValidAttributeType(attributeType, getFullBranch()); |
| } |
| |
| public final boolean isRelationTypeValid(IRelationType relationType) throws OseeCoreException { |
| return getValidRelationTypes().contains(relationType); |
| } |
| |
| public final Collection<RelationType> getValidRelationTypes() throws OseeCoreException { |
| return RelationTypeManager.getValidTypes(getArtifactType(), branch); |
| } |
| |
| /** |
| * The use of this method is discouraged since it directly returns Attributes. |
| */ |
| public final <T> List<Attribute<T>> getAttributes(IAttributeType attributeType, Object value) throws OseeCoreException { |
| List<Attribute<?>> filteredList = new ArrayList<Attribute<?>>(); |
| for (Attribute<?> attribute : getAttributes(attributeType)) { |
| if (attribute.getValue().equals(value)) { |
| filteredList.add(attribute); |
| } |
| } |
| return Collections.castAll(filteredList); |
| } |
| |
| /** |
| * The use of this method is discouraged since it directly returns Attributes. |
| * |
| * @return attributes All attributes including deleted and artifact deleted |
| */ |
| public final List<Attribute<?>> getAllAttributesIncludingHardDeleted() throws OseeCoreException { |
| return getAttributesByModificationType(ModificationType.getAllStates()); |
| } |
| |
| /** |
| * The use of this method is discouraged since it directly returns Attributes. |
| * |
| * @return attributes All attributes of the specified type name including deleted and artifact deleted |
| */ |
| public final List<Attribute<?>> getAllAttributesIncludingHardDeleted(IAttributeType attributeType) throws OseeCoreException { |
| return getAttributesByModificationType(attributeType, ModificationType.getAllStates()); |
| } |
| |
| /** |
| * The use of this method is discouraged since it directly returns Attributes. |
| */ |
| public final List<Attribute<?>> getAttributes() throws OseeCoreException { |
| return getAttributes(false); |
| } |
| |
| public final List<Attribute<?>> getAttributes(boolean includeDeleted) throws OseeCoreException { |
| List<Attribute<?>> attributes; |
| if (includeDeleted) { |
| attributes = getAttributesByModificationType(ModificationType.getAllCurrentModTypes()); |
| } else { |
| attributes = getAttributesByModificationType(ModificationType.getCurrentModTypes()); |
| } |
| return attributes; |
| } |
| |
| /** |
| * The use of this method is discouraged since it directly returns Attributes. |
| */ |
| @Deprecated |
| public final <T> List<Attribute<T>> getAttributes(IAttributeType attributeType) throws OseeCoreException { |
| return Collections.castAll(getAttributesByModificationType(attributeType, ModificationType.getCurrentModTypes())); |
| } |
| |
| private List<Attribute<?>> getAttributesByModificationType(Set<ModificationType> allowedModTypes) throws OseeCoreException { |
| ensureAttributesLoaded(); |
| return filterByModificationType(attributes.getValues(), allowedModTypes); |
| } |
| |
| private List<Attribute<?>> getAttributesByModificationType(IAttributeType attributeType, Set<ModificationType> allowedModTypes) throws OseeCoreException { |
| ensureAttributesLoaded(); |
| return filterByModificationType(attributes.getValues(attributeType), allowedModTypes); |
| } |
| |
| private List<Attribute<?>> filterByModificationType(Collection<Attribute<?>> attributes, Set<ModificationType> allowedModTypes) { |
| List<Attribute<?>> filteredList = new ArrayList<Attribute<?>>(); |
| if (allowedModTypes != null && !allowedModTypes.isEmpty() && attributes != null && !attributes.isEmpty()) { |
| for (Attribute<?> attribute : attributes) { |
| if (allowedModTypes.contains(attribute.getModificationType())) { |
| filteredList.add(attribute); |
| } |
| } |
| } |
| return filteredList; |
| } |
| |
| /** |
| * @return all attributes including deleted ones |
| */ |
| public final List<Attribute<?>> internalGetAttributes() { |
| return attributes.getValues(); |
| } |
| |
| /** |
| * Deletes all attributes of the given type, if any |
| */ |
| public final void deleteAttributes(IAttributeType attributeType) throws OseeCoreException { |
| for (Attribute<?> attribute : getAttributes(attributeType)) { |
| attribute.delete(); |
| } |
| } |
| |
| private void ensureAttributesLoaded() throws OseeCoreException { |
| if (!isAttributesLoaded() && isInDb()) { |
| ArtifactLoader.loadArtifactData(this, LoadLevel.ATTRIBUTE); |
| } |
| } |
| |
| public final boolean isAttributesLoaded() { |
| return !attributes.isEmpty(); |
| } |
| |
| public final Collection<IAttributeType> getAttributeTypes() throws OseeCoreException { |
| return getArtifactType().getAttributeTypes(getFullBranch()); |
| } |
| |
| public final <T> Attribute<T> getSoleAttribute(IAttributeType attributeType) throws OseeCoreException { |
| ensureAttributesLoaded(); |
| List<Attribute<T>> soleAttributes = getAttributes(attributeType); |
| if (soleAttributes.isEmpty()) { |
| return null; |
| } else if (soleAttributes.size() > 1) { |
| throw new MultipleAttributesExist(String.format( |
| "The attribute \'%s\' can have no more than one instance for sole attribute operations; guid \'%s\'", |
| attributeType, getGuid())); |
| } |
| return soleAttributes.iterator().next(); |
| } |
| |
| private <T> Attribute<T> getOrCreateSoleAttribute(IAttributeType attributeType) throws OseeCoreException { |
| if (!isAttributeTypeValid(attributeType)) { |
| throw new OseeArgumentException("The attribute type %s is not valid for artifacts of type [%s]", |
| attributeType, getArtifactTypeName()); |
| } |
| Attribute<T> attribute = getSoleAttribute(attributeType); |
| if (attribute == null) { |
| attribute = initializeAttribute(attributeType, ModificationType.NEW, true, true); |
| } |
| return attribute; |
| } |
| |
| /** |
| * Return he existing attribute value or the default value from a newly initialized attribute if none previously |
| * existed |
| */ |
| public final <T> T getOrInitializeSoleAttributeValue(IAttributeType attributeType) throws OseeCoreException { |
| Attribute<T> attribute = getOrCreateSoleAttribute(attributeType); |
| return attribute.getValue(); |
| } |
| |
| /** |
| * Return sole attribute value for given attribute type name. Will throw exceptions if "Sole" nature of attribute is |
| * invalid.<br> |
| * <br> |
| * Used for quick access to attribute value that should only have 0 or 1 instances of the attribute. |
| */ |
| public final <T> T getSoleAttributeValue(IAttributeType attributeType) throws OseeCoreException { |
| List<Attribute<T>> soleAttributes = getAttributes(attributeType); |
| if (soleAttributes.isEmpty()) { |
| if (!isAttributeTypeValid(attributeType)) { |
| throw new OseeArgumentException("The attribute type %s is not valid for artifacts of type [%s]", |
| attributeType, getArtifactTypeName()); |
| } |
| throw new AttributeDoesNotExist("Attribute of type [%s] could not be found on artifact [%s] on branch [%s]", |
| attributeType.getName(), getGuid(), getBranch().getGuid()); |
| } else if (soleAttributes.size() > 1) { |
| throw new MultipleAttributesExist( |
| "Attribute [%s] must have exactly one instance. It currently has %d for artifact [%s]", attributeType, |
| soleAttributes.size(), getGuid()); |
| } |
| return soleAttributes.iterator().next().getValue(); |
| } |
| |
| /** |
| * Return sole attribute string value for given attribute type name. Handles AttributeDoesNotExist case by returning |
| * defaultReturnValue.<br> |
| * <br> |
| * Used for display purposes where toString() of attribute is to be displayed. |
| * |
| * @param defaultReturnValue return value if attribute instance does not exist |
| * @throws MultipleAttributesExist if multiple attribute instances exist |
| */ |
| |
| public final String getSoleAttributeValueAsString(IAttributeType attributeType, String defaultReturnValue) throws OseeCoreException, MultipleAttributesExist { |
| |
| String toReturn = null; |
| Object value = getSoleAttributeValue(attributeType, defaultReturnValue); |
| if (value instanceof InputStream) { |
| InputStream inputStream = (InputStream) value; |
| try { |
| toReturn = Lib.inputStreamToString(inputStream); |
| } catch (IOException ex) { |
| OseeExceptions.wrapAndThrow(ex); |
| } finally { |
| try { |
| inputStream.close(); |
| } catch (IOException ex) { |
| OseeExceptions.wrapAndThrow(ex); |
| } |
| } |
| } else { |
| if (value != null) { |
| toReturn = value.toString(); |
| } |
| } |
| return toReturn; |
| } |
| |
| /** |
| * Return sole attribute value for given attribute type name Handles AttributeDoesNotExist case by returning |
| * defaultReturnValue.<br> |
| * <br> |
| * Used for purposes where attribute value of specified type is desired. |
| * |
| * @throws MultipleAttributesExist if multiple attribute instances exist |
| */ |
| public final <T> T getSoleAttributeValue(IAttributeType attributeType, T defaultReturnValue) throws OseeCoreException { |
| List<Attribute<T>> soleAttributes = getAttributes(attributeType); |
| if (soleAttributes.size() == 1) { |
| T value = soleAttributes.iterator().next().getValue(); |
| if (value == null) { |
| OseeLog.log( |
| Activator.class, |
| Level.SEVERE, |
| "Attribute \"" + attributeType + "\" has null value for Artifact " + getGuid() + " \"" + getName() + "\""); |
| return defaultReturnValue; |
| } |
| return value; |
| } else if (soleAttributes.size() > 1) { |
| throw new MultipleAttributesExist( |
| "Attribute [%s] must have exactly one instance. It currently has %d for artifact [%s]", attributeType, |
| soleAttributes.size(), getGuid()); |
| } else { |
| return defaultReturnValue; |
| } |
| } |
| |
| /** |
| * Delete attribute if exactly one exists. Does nothing if attribute does not exist and throw MultipleAttributesExist |
| * is more than one instance of the attribute type exsits for this artifact |
| */ |
| public final void deleteSoleAttribute(IAttributeType attributeType) throws OseeCoreException { |
| Attribute<?> attribute = getSoleAttribute(attributeType); |
| if (attribute != null) { |
| deleteAttribute(attribute); |
| } |
| } |
| |
| /** |
| * Deletes the first attribute found of the given type and value |
| */ |
| public final void deleteAttribute(IAttributeType attributeType, Object value) throws OseeCoreException { |
| for (Attribute<Object> attribute : getAttributes(attributeType)) { |
| if (attribute.getValue().equals(value)) { |
| deleteAttribute(attribute); |
| break; |
| } |
| } |
| } |
| |
| public final void deleteAttribute(int attributeId) throws OseeCoreException { |
| for (Attribute<?> attribute : getAttributes()) { |
| if (attribute.getId() == attributeId) { |
| deleteAttribute(attribute); |
| break; |
| } |
| } |
| } |
| |
| public final void deleteAttribute(Attribute<?> attribute) throws OseeCoreException { |
| if (attribute.isInDb()) { |
| attribute.delete(); |
| } else { |
| attributes.removeValue(attribute.getAttributeType(), attribute); |
| } |
| } |
| |
| /** |
| * Used on attribute types with no more than one instance. If the attribute exists, it's value is changed, otherwise |
| * a new attribute is added and its value set. |
| */ |
| public final <T> void setSoleAttributeValue(IAttributeType attributeType, T value) throws OseeCoreException { |
| getOrCreateSoleAttribute(attributeType).setValue(value); |
| } |
| |
| public final <T> void setSoleAttributeFromString(IAttributeType attributeType, String value) throws OseeCoreException { |
| getOrCreateSoleAttribute(attributeType).setFromString(value); |
| } |
| |
| public final void setSoleAttributeFromStream(IAttributeType attributeType, InputStream stream) throws OseeCoreException { |
| getOrCreateSoleAttribute(attributeType).setValueFromInputStream(stream); |
| } |
| |
| public final String getAttributesToStringSorted(IAttributeType attributeType) throws OseeCoreException { |
| return getAttributesToString(attributeType, true); |
| } |
| |
| /** |
| * @return comma delimited representation of all the attributes of the type attributeType in an unspecified order |
| */ |
| public final String getAttributesToString(IAttributeType attributeType) throws OseeCoreException { |
| return getAttributesToString(attributeType, false); |
| } |
| |
| /** |
| * @return comma delimited representation of all the attributes of the type attributeName |
| */ |
| public final String getAttributesToString(IAttributeType attributeType, boolean sorted) throws OseeCoreException { |
| List<String> strs = new ArrayList<String>(); |
| List<Attribute<Object>> attributes = getAttributes(attributeType); |
| if (sorted) { |
| java.util.Collections.sort(attributes); |
| } |
| |
| for (Attribute<?> attr : attributes) { |
| strs.add(String.valueOf(attr)); |
| } |
| return Collections.toString(", ", strs); |
| } |
| |
| /** |
| * @return comma separator representation unique values of the attributes of the type attributeName |
| */ |
| public final String getAttributesToStringUnique(IAttributeType attributeType, String separator) throws OseeCoreException { |
| Set<String> strs = new HashSet<String>(); |
| for (Attribute<?> attr : getAttributes(attributeType)) { |
| strs.add(String.valueOf(attr)); |
| } |
| return Collections.toString(separator, strs); |
| } |
| |
| /** |
| * Will add the single string value if it does not already exist. Will also cleanup if more than one exists with same |
| * value. Will not touch any other values. |
| */ |
| public void setSingletonAttributeValue(IAttributeType attributeType, String value) throws OseeCoreException { |
| List<Attribute<String>> attributes = getAttributes(CoreAttributeTypes.StaticId, value); |
| if (attributes.isEmpty()) { |
| addAttribute(attributeType, value); |
| } else if (attributes.size() > 1) { |
| // keep one of the attributes |
| for (int x = 1; x < attributes.size(); x++) { |
| Attribute<String> attr = attributes.get(x); |
| attr.delete(); |
| } |
| } |
| } |
| |
| /** |
| * Will remove one or more of the single string value if artifact has it. Will not touch any other values. |
| */ |
| public void deleteSingletonAttributeValue(IAttributeType attributeType, String value) throws OseeCoreException { |
| for (Attribute<?> attribute : getAttributes(attributeType, value)) { |
| attribute.delete(); |
| } |
| } |
| |
| /** |
| * All existing attributes matching a new value will be left untouched. Then for any remaining values, other existing |
| * attributes will be changed to match or if need be new attributes will be added to stored these values. Finally any |
| * excess attributes will be deleted. |
| */ |
| public final void setAttributeValues(IAttributeType attributeType, Collection<String> newValues) throws OseeCoreException { |
| ensureAttributesLoaded(); |
| // ensure new values are unique |
| HashSet<String> uniqueNewValues = new HashSet<String>(newValues); |
| |
| List<Attribute<Object>> remainingAttributes = getAttributes(attributeType); |
| List<String> remainingNewValues = new ArrayList<String>(uniqueNewValues.size()); |
| |
| // all existing attributes matching a new value will be left untouched |
| for (String newValue : uniqueNewValues) { |
| boolean found = false; |
| for (Attribute<Object> attribute : remainingAttributes) { |
| if (attribute.getValue().toString().equals(newValue)) { |
| remainingAttributes.remove(attribute); |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| remainingNewValues.add(newValue); |
| } |
| } |
| |
| for (String newValue : remainingNewValues) { |
| if (remainingAttributes.isEmpty()) { |
| setOrAddAttribute(attributeType, newValue); |
| } else { |
| int index = remainingAttributes.size() - 1; |
| remainingAttributes.get(index).setFromString(newValue); |
| remainingAttributes.remove(index); |
| } |
| } |
| |
| for (Attribute<Object> attribute : remainingAttributes) { |
| attribute.delete(); |
| } |
| } |
| |
| public final <T> void setAttributeFromValues(IAttributeType attributeType, Collection<T> values) throws OseeCoreException { |
| ensureAttributesLoaded(); |
| |
| Set<T> uniqueItems = Collections.toSet(values); |
| |
| List<Attribute<T>> remainingAttributes = getAttributes(attributeType); |
| List<T> remainingNewValues = new ArrayList<T>(uniqueItems.size()); |
| |
| // all existing attributes matching a new value will be left untouched |
| for (T newValue : uniqueItems) { |
| boolean found = false; |
| for (Attribute<T> attribute : remainingAttributes) { |
| if (newValue.equals(attribute.getValue())) { |
| remainingAttributes.remove(attribute); |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| remainingNewValues.add(newValue); |
| } |
| } |
| |
| for (T newValue : remainingNewValues) { |
| if (remainingAttributes.isEmpty()) { |
| setOrAddAttribute(attributeType, newValue); |
| } else { |
| int index = remainingAttributes.size() - 1; |
| remainingAttributes.get(index).setValue(newValue); |
| remainingAttributes.remove(index); |
| } |
| } |
| |
| for (Attribute<T> attribute : remainingAttributes) { |
| attribute.delete(); |
| } |
| } |
| |
| /** |
| * adds a new attribute of the type named attributeTypeName and assigns it the given value |
| */ |
| public final <T> void addAttribute(IAttributeType attributeType, T value) throws OseeCoreException { |
| initializeAttribute(attributeType, ModificationType.NEW, true, false).setValue(value); |
| } |
| |
| /** |
| * adds a new attribute of the type named attributeTypeName. The attribute is set to the default value for its type, |
| * if any. |
| */ |
| public final void addAttribute(IAttributeType attributeType) throws OseeCoreException { |
| initializeAttribute(attributeType, ModificationType.NEW, true, true); |
| } |
| |
| /** |
| * adds a new attribute of the type named attributeTypeName. The attribute is set to the default value for its type, |
| * if any. |
| */ |
| public final void addAttribute(AttributeType attributeType) throws OseeCoreException { |
| initializeAttribute(attributeType, ModificationType.NEW, true, true); |
| } |
| |
| /** |
| * adds a new attribute of the type named attributeTypeName and assigns it the given value |
| */ |
| public final void addAttributeFromString(IAttributeType attributeType, String value) throws OseeCoreException { |
| initializeAttribute(attributeType, ModificationType.NEW, true, false).setFromString(value); |
| } |
| |
| /** |
| * we do not what duplicated enumerated values so this method silently returns if the specified attribute type is |
| * enumerated and value is already present |
| */ |
| public final <T> void setOrAddAttribute(IAttributeType attributeType, T value) throws OseeCoreException { |
| List<Attribute<String>> attributes = getAttributes(attributeType); |
| for (Attribute<String> canidateAttribute : attributes) { |
| if (canidateAttribute.getValue().equals(value)) { |
| return; |
| } |
| } |
| addAttribute(attributeType, value); |
| } |
| |
| /** |
| * @return string collection containing of all the attribute values of type attributeType |
| */ |
| public final List<String> getAttributesToStringList(IAttributeType attributeType) throws OseeCoreException { |
| ensureAttributesLoaded(); |
| |
| List<String> items = new ArrayList<String>(); |
| for (Attribute<?> attribute : getAttributes(attributeType)) { |
| items.add(attribute.getDisplayableString()); |
| } |
| return items; |
| } |
| |
| public final <T> List<T> getAttributeValues(IAttributeType attributeType) throws OseeCoreException { |
| ensureAttributesLoaded(); |
| |
| List<T> items = new ArrayList<T>(); |
| List<Attribute<T>> data = getAttributes(attributeType); |
| for (Attribute<T> attribute : data) { |
| T value = attribute.getValue(); |
| if (value != null) { |
| items.add(value); |
| } |
| } |
| return items; |
| } |
| |
| @Override |
| public final String getName() { |
| String name = null; |
| try { |
| ensureAttributesLoaded(); |
| // use the first name attribute whether deleted or not. |
| for (Attribute<?> attribute : internalGetAttributes()) { |
| if (attribute.isOfType(CoreAttributeTypes.Name)) { |
| name = (String) attribute.getValue(); |
| } |
| } |
| } catch (OseeCoreException ex) { |
| OseeLog.log(Activator.class, Level.SEVERE, ex); |
| } |
| if (!Strings.isValid(name)) { |
| return UNNAMED; |
| } |
| return name; |
| } |
| |
| @Override |
| public final void setName(String name) throws OseeCoreException { |
| setSoleAttributeValue(CoreAttributeTypes.Name, name); |
| } |
| |
| public final ArtifactFactory getFactory() { |
| return parentFactory; |
| } |
| |
| /** |
| * artifact.persist(); artifact.reloadAttributesAndRelations(); Will need to be called afterwards to see replaced |
| * data in memory |
| */ |
| public void replaceWithVersion(int gammaId) { |
| lastValidModType = this.modType; |
| this.modType = ModificationType.REPLACED_WITH_VERSION; |
| this.gammaId = gammaId; |
| } |
| |
| /** |
| * This is used to mark that the artifact deleted. |
| */ |
| public final void internalSetDeleted() throws OseeCoreException { |
| this.modType = ModificationType.DELETED; |
| |
| for (Attribute<?> attribute : getAttributes()) { |
| attribute.setArtifactDeleted(); |
| } |
| } |
| |
| public final void internalSetDeletedFromRemoteEvent() throws OseeCoreException { |
| if (!isHistorical()) { |
| this.modType = ModificationType.DELETED; |
| ArtifactCache.deCache(this); |
| |
| for (Attribute<?> attribute : getAttributes()) { |
| attribute.internalSetDeletedFromRemoteEvent(); |
| } |
| } |
| } |
| |
| /** |
| * This is used to mark that the artifact not deleted. This should only be called by the RemoteEventManager. |
| */ |
| public final void resetToPreviousModType() { |
| this.modType = lastValidModType; |
| |
| for (Attribute<?> attribute : attributes.getValues()) { |
| if (attribute.getModificationType() == ModificationType.ARTIFACT_DELETED) { |
| attribute.resetModType(); |
| } |
| } |
| } |
| |
| /** |
| * @return whether this artifact has unsaved attribute changes |
| */ |
| public final boolean hasDirtyAttributes() { |
| for (Attribute<?> attribute : internalGetAttributes()) { |
| if (attribute.isDirty()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @return whether this artifact has unsaved relation changes |
| */ |
| public final boolean hasDirtyRelations() { |
| return RelationManager.hasDirtyLinks(this); |
| } |
| |
| public final EditState getEditState() { |
| return objectEditState; |
| } |
| |
| public final boolean hasDirtyArtifactType() { |
| return objectEditState.isArtifactTypeChange(); |
| } |
| |
| /** |
| * @return whether this artifact has unsaved relation changes |
| */ |
| public final boolean isDirty() { |
| return hasDirtyAttributes() || hasDirtyRelations() || hasDirtyArtifactType(); |
| } |
| |
| public final boolean isReadOnly() { |
| boolean result = true; |
| AccessPolicy service = null; |
| try { |
| service = ServiceUtil.getAccessPolicy(); |
| } catch (OseeCoreException ex) { |
| OseeLog.log(Activator.class, Level.SEVERE, ex); |
| } |
| if (service != null) { |
| result = service.isReadOnly(this); |
| } |
| return result; |
| } |
| |
| /** |
| * Revert artifact to it's state at base transaction of the branch. <br> |
| * This will remove all changes from osee_txs for this artifact on it's branch.<br> |
| * <br> |
| * NOTE: This should NOT normally be used for baseline branches as the artifact will disappear from existence. <br> |
| * <br> |
| * Instead use reloadAttributesAndRelations() to restore in memory artifact back to it's non-dirty state. |
| */ |
| /** |
| * Reloads this artifact's attributes and relations back to the last state saved. <br> |
| * <br> |
| * This will have no effect if the artifact has never been saved. |
| */ |
| public final void reloadAttributesAndRelations() throws OseeCoreException { |
| if (!isInDb()) { |
| return; |
| } |
| |
| ArtifactQuery.reloadArtifactFromId(getArtId(), getBranch()); |
| } |
| |
| void prepareForReload() { |
| attributes.clear(); |
| linksLoaded = false; |
| |
| RelationManager.prepareRelationsForReload(this); |
| } |
| |
| public final void persist(String comment) throws OseeCoreException { |
| SkynetTransaction transaction = TransactionManager.createTransaction(branch, comment); |
| persist(transaction); |
| transaction.execute(); |
| } |
| |
| /** |
| * <b>THIS ASSUMES YOU ARE MAINTAINING YOUR OWN TRANSACTION</b> vs {@link #SkynetTransaction.persist(String)} where |
| * silently you are provided a transaction. |
| * <p> |
| * Example: |
| * |
| * <pre> |
| * ... |
| * Artifact artifact = ArtifactTypeManager.addArtifact(CoreArtifactTypes.Folder, ARTIFACT_BRANCH); |
| * ... |
| * <b>SkynetTransaction transaction = TransactionManager.createTransaction(ARTIFACT_BRANCH, name);</b> |
| * ... |
| * <b>artifact.persist(transaction);</b> |
| * ... |
| * <b>transaction.execute();</b> |
| * ... |
| * </pre> |
| * |
| * </p> |
| * |
| * @param managedTransaction |
| * @throws OseeCoreException |
| */ |
| public final void persist(SkynetTransaction managedTransaction) throws OseeCoreException { |
| managedTransaction.addArtifact(this); |
| } |
| |
| /** |
| * Returns all of the descendants through the primary decomposition tree that have a particular human readable id. |
| * This will not return the called upon node if the name matches since it can not be a descendant of itself. |
| * |
| * @param humanReadableId The human readable id text to match against. |
| * @param caseSensitive Whether to use case sensitive matching. |
| * @return <code>Collection</code> of <code>Artifact</code>'s that match. |
| */ |
| public final Collection<Artifact> getDescendants(String humanReadableId, boolean caseSensitive) throws OseeCoreException { |
| Collection<Artifact> descendants = new LinkedList<Artifact>(); |
| |
| for (Artifact child : getChildren()) { |
| if (caseSensitive && child.getName().equals(humanReadableId) || !caseSensitive && child.getName().equalsIgnoreCase( |
| humanReadableId)) { |
| descendants.add(child); |
| } |
| descendants.addAll(child.getDescendants(humanReadableId, caseSensitive)); |
| } |
| |
| return descendants; |
| } |
| |
| /** |
| * Starting from this artifact, walks down the child hierarchy based on the list of child names provided and returns |
| * the child of the last name provided. ArtifactDoesNotExist exception is thrown ff any child along the path does not |
| * exist. |
| * |
| * @return child at the leaf (bottom) of the specified hierarchy. |
| */ |
| public final Artifact getDescendant(String... names) throws OseeCoreException { |
| if (names.length == 0) { |
| throw new OseeArgumentException("Must suply at least one name to getDescendant()"); |
| } |
| Artifact descendant = this; |
| for (String name : names) { |
| descendant = descendant.getChild(name); |
| } |
| return descendant; |
| } |
| |
| /** |
| * Removes artifact from a specific branch |
| */ |
| public final void deleteAndPersist() throws OseeCoreException { |
| SkynetTransaction transaction = |
| TransactionManager.createTransaction(branch, "Delete artifact from a specific branch"); |
| deleteAndPersist(transaction); |
| transaction.execute(); |
| } |
| |
| public final void deleteAndPersist(SkynetTransaction transaction, boolean overrideChecks) throws OseeCoreException { |
| ArtifactPersistenceManager.deleteArtifact(transaction, overrideChecks, this); |
| } |
| |
| /** |
| * Removes artifact from a specific branch |
| */ |
| public final void deleteAndPersist(SkynetTransaction transaction) throws OseeCoreException { |
| ArtifactPersistenceManager.deleteArtifact(transaction, false, this); |
| } |
| |
| public final void delete() throws OseeCoreException { |
| ArtifactPersistenceManager.deleteArtifact(null, false, this); |
| } |
| |
| /** |
| * Remove artifact from a specific branch in the database |
| */ |
| public final void purgeFromBranch(boolean purgeChildren) throws OseeCoreException { |
| Collection<Artifact> artifacts = new LinkedHashSet<Artifact>(); |
| artifacts.add(this); |
| if (purgeChildren) { |
| artifacts.addAll(getDescendants()); |
| } |
| Operations.executeWorkAndCheckStatus(new PurgeArtifacts(artifacts)); |
| } |
| |
| public final void purgeFromBranch() throws OseeCoreException { |
| purgeFromBranch(false); |
| } |
| |
| public final boolean isDeleted() { |
| return modType == ModificationType.DELETED; |
| } |
| |
| public final void setLinksLoaded(boolean loaded) { |
| linksLoaded = loaded; |
| } |
| |
| public final void addRelation(IRelationSorterId sorterId, IRelationTypeSide relationTypeSide, Artifact artifact, String rationale) throws OseeCoreException { |
| Pair<Artifact, Artifact> sides = determineArtifactSides(artifact, relationTypeSide); |
| RelationManager.addRelation(sorterId, relationTypeSide, sides.getFirst(), sides.getSecond(), rationale); |
| } |
| |
| public final void addRelation(IRelationTypeSide relationSide, Artifact artifact) throws OseeCoreException { |
| addRelation(RelationOrderBaseTypes.PREEXISTING, relationSide, artifact, null); |
| } |
| |
| public final void addRelation(IRelationSorterId sorterId, IRelationTypeSide relationSide, Artifact artifact) throws OseeCoreException { |
| addRelation(sorterId, relationSide, artifact, null); |
| } |
| |
| public final void addRelation(IRelationSorterId sorterId, IRelationTypeSide relationEnumeration, Artifact targetArtifact, boolean insertAfterTarget, Artifact itemToAdd, String rationale) throws OseeCoreException { |
| boolean sideA = relationEnumeration.getSide().isSideA(); |
| Artifact artifactA = sideA ? itemToAdd : this; |
| Artifact artifactB = sideA ? this : itemToAdd; |
| |
| RelationManager.addRelation(sorterId, relationEnumeration, artifactA, artifactB, rationale); |
| setRelationOrder(relationEnumeration, targetArtifact, insertAfterTarget, itemToAdd); |
| } |
| |
| public final void setRelationOrder(IRelationTypeSide relationSide, List<Artifact> artifactsInNewOrder) throws OseeCoreException { |
| RelationManager.setRelationOrder(this, relationSide, relationSide.getSide(), RelationOrderBaseTypes.USER_DEFINED, |
| artifactsInNewOrder); |
| } |
| |
| public final void setRelationOrder(IRelationTypeSide relationEnumeration, IRelationSorterId orderId) throws OseeCoreException { |
| if (RelationOrderBaseTypes.USER_DEFINED == orderId) { |
| setRelationOrder(relationEnumeration, getRelatedArtifacts(relationEnumeration)); |
| } else { |
| List<Artifact> empty = java.util.Collections.emptyList(); |
| RelationManager.setRelationOrder(this, relationEnumeration, relationEnumeration.getSide(), orderId, empty); |
| } |
| } |
| |
| public final void setRelationOrder(IRelationTypeSide relationEnumeration, Artifact targetArtifact, boolean insertAfterTarget, Artifact itemToAdd) throws OseeCoreException { |
| List<Artifact> currentOrder = getRelatedArtifacts(relationEnumeration, Artifact.class); |
| // target artifact doesn't exist |
| if (!currentOrder.contains(targetArtifact)) { |
| // add to end of list if not already in list |
| if (!currentOrder.contains(itemToAdd)) { |
| currentOrder.add(itemToAdd); |
| } |
| } |
| boolean result = Collections.moveItem(currentOrder, itemToAdd, targetArtifact, insertAfterTarget); |
| if (!result) { |
| throw new OseeStateException("Could not set Relation Order"); |
| } |
| |
| RelationManager.setRelationOrder(this, relationEnumeration, relationEnumeration.getSide(), |
| RelationOrderBaseTypes.USER_DEFINED, currentOrder); |
| } |
| |
| public final void deleteRelation(IRelationTypeSide relationTypeSide, Artifact artifact) throws OseeCoreException { |
| Pair<Artifact, Artifact> sides = determineArtifactSides(artifact, relationTypeSide); |
| RelationManager.deleteRelation(relationTypeSide, sides.getFirst(), sides.getSecond()); |
| } |
| |
| public final void deleteRelations(IRelationTypeSide relationSide) throws OseeCoreException { |
| for (Artifact art : getRelatedArtifacts(relationSide)) { |
| deleteRelation(relationSide, art); |
| } |
| } |
| |
| /** |
| * Creates new relations that don't already exist and removes relations to artifacts that are not in collection |
| */ |
| public final void setRelations(IRelationSorterId sorterId, IRelationTypeSide relationSide, Collection<? extends Artifact> artifacts) throws OseeCoreException { |
| Collection<Artifact> currentlyRelated = getRelatedArtifacts(relationSide, Artifact.class); |
| // Remove relations that have been removed |
| for (Artifact artifact : currentlyRelated) { |
| if (!artifacts.contains(artifact)) { |
| deleteRelation(relationSide, artifact); |
| } |
| } |
| // Add new relations if don't exist |
| for (Artifact artifact : artifacts) { |
| if (!currentlyRelated.contains(artifact)) { |
| addRelation(sorterId, relationSide, artifact); |
| } |
| } |
| } |
| |
| /** |
| * Creates new relations that don't already exist and removes relations to artifacts that are not in collection |
| */ |
| public final void setRelations(IRelationTypeSide relationSide, Collection<? extends Artifact> artifacts) throws OseeCoreException { |
| setRelations(RelationOrderBaseTypes.PREEXISTING, relationSide, artifacts); |
| } |
| |
| /** |
| * Creates new relations that don't already exist and removes relations to artifacts that are not in collection |
| */ |
| public final void setRelationsOfTypeUseCurrentOrder(IRelationTypeSide relationSide, Collection<? extends Artifact> artifacts, Class<?> clazz) throws OseeCoreException { |
| RelationTypeSideSorter sorter = RelationManager.createTypeSideSorter(this, relationSide, relationSide.getSide()); |
| Collection<Artifact> currentlyRelated = getRelatedArtifacts(relationSide, Artifact.class); |
| // Add new relations if don't exist |
| for (Artifact artifact : artifacts) { |
| if (clazz.isInstance(artifact) && !currentlyRelated.contains(artifact)) { |
| addRelation(sorter.getSorterId(), relationSide, artifact); |
| } |
| } |
| // Remove relations that have been removed |
| for (Artifact artifact : currentlyRelated) { |
| if (clazz.isInstance(artifact) && !artifacts.contains(artifact)) { |
| deleteRelation(relationSide, artifact); |
| } |
| } |
| } |
| |
| public final boolean isLinksLoaded() { |
| return linksLoaded; |
| } |
| |
| public final String getHumanReadableId() { |
| return humanReadableId; |
| } |
| |
| /** |
| * @return Returns the descriptor. |
| */ |
| @Override |
| public final ArtifactType getArtifactType() { |
| return artifactType; |
| } |
| |
| public final IArtifactType getArtifactTypeToken() { |
| return artifactType; |
| } |
| |
| public final String getVersionedName() { |
| String name = getName(); |
| |
| if (isHistorical()) { |
| name += " [Rev:" + transactionId + "]"; |
| } |
| |
| return name; |
| } |
| |
| /** |
| * Return true if this artifact any of it's links specified or any of the artifacts on the other side of the links |
| * are dirty |
| */ |
| public final String isRelationsAndArtifactsDirty(Set<IRelationTypeSide> links) { |
| try { |
| if (hasDirtyAttributes()) { |
| |
| for (Attribute<?> attribute : internalGetAttributes()) { |
| if (attribute.isDirty()) { |
| return "===> Dirty Attribute - " + attribute.getAttributeType().getName() + "\n"; |
| } |
| } |
| return "Artifact isDirty == true??"; |
| } |
| // Loop through all relations |
| for (IRelationTypeSide side : links) { |
| for (Artifact art : getRelatedArtifacts(side)) { |
| // Check artifact dirty |
| if (art.hasDirtyAttributes()) { |
| return art.getArtifactTypeName() + " \"" + art + "\" => dirty\n"; |
| } |
| // Check the links to this artifact |
| for (RelationLink link : getRelations(side, art)) { |
| if (link.isDirty()) { |
| return "Link \"" + link + "\" => dirty\n"; |
| } |
| } |
| } |
| } |
| } catch (Exception ex) { |
| OseeLog.log(Activator.class, Level.SEVERE, ex); |
| } |
| return null; |
| } |
| |
| /** |
| * Creates a new artifact and duplicates all of its attribute data. |
| */ |
| public final Artifact duplicate(IOseeBranch branch) throws OseeCoreException { |
| return duplicate(branch, new ArrayList<IAttributeType>()); |
| } |
| |
| public final Artifact duplicate(IOseeBranch branch, Collection<IAttributeType> excudeAttributeTypes) throws OseeCoreException { |
| Artifact newArtifact = ArtifactTypeManager.addArtifact(artifactType, branch); |
| // we do this because attributes were added on creation to meet the |
| // minimum attribute requirements |
| newArtifact.attributes.clear(); |
| copyAttributes(newArtifact, excudeAttributeTypes); |
| return newArtifact; |
| } |
| |
| private void copyAttributes(Artifact artifact, Collection<IAttributeType> excudeAttributeTypes) throws OseeCoreException { |
| for (Attribute<?> attribute : getAttributes()) { |
| if (!excudeAttributeTypes.contains(attribute) && isCopyAllowed(attribute) && artifact.isAttributeTypeValid(attribute.getAttributeType())) { |
| artifact.addAttribute(attribute.getAttributeType(), attribute.getValue()); |
| } |
| } |
| } |
| |
| private boolean isCopyAllowed(Attribute<?> attribute) { |
| return attribute != null && !attribute.isOfType(CoreAttributeTypes.RelationOrder); |
| } |
| |
| /** |
| * An artifact reflected about its own branch returns itself. Otherwise a new artifact is introduced on the |
| * destinationBranch |
| * |
| * @return the newly created artifact or this artifact if the destinationBranch is this artifact's branch |
| */ |
| public final Artifact reflect(IOseeBranch destinationBranch) throws OseeCoreException { |
| if (branch.equals(destinationBranch)) { |
| return this; |
| } |
| return reflectHelper(destinationBranch); |
| } |
| |
| private Artifact reflectHelper(IOseeBranch branch) throws OseeCoreException { |
| Artifact reflectedArtifact = |
| ArtifactTypeManager.getFactory(artifactType).reflectExisitingArtifact(artId, getGuid(), humanReadableId, |
| artifactType, gammaId, branch, ModificationType.INTRODUCED); |
| |
| for (Attribute<?> sourceAttribute : attributes.getValues()) { |
| // In order to reflect attributes they must exist in the data store |
| // and be valid for the destination branch as well |
| if (sourceAttribute.isInDb() && reflectedArtifact.isAttributeTypeValid(sourceAttribute.getAttributeType())) { |
| reflectedArtifact.internalInitializeAttribute(sourceAttribute.getAttributeType(), sourceAttribute.getId(), |
| sourceAttribute.getGammaId(), ModificationType.INTRODUCED, true, |
| sourceAttribute.getAttributeDataProvider().getData()); |
| } |
| } |
| return reflectedArtifact; |
| } |
| |
| public final void updateArtifactFromBranch(IOseeBranch updateSourceBranch) throws OseeCoreException { |
| // Do not update the artifact with itself. |
| if (branch.equals(updateSourceBranch)) { |
| return; |
| } |
| updateRelationsFromBranch(updateSourceBranch); |
| updateAttributesFromBranch(updateSourceBranch); |
| } |
| |
| @SuppressWarnings({"unchecked", "rawtypes"}) |
| private void updateAttributesFromBranch(IOseeBranch updateSourceBranch) throws OseeCoreException { |
| Artifact updateSourceArtifact = ArtifactQuery.getArtifactFromId(this.getArtId(), updateSourceBranch); |
| for (Attribute<?> updateSourceAttr : updateSourceArtifact.getAttributes()) { |
| Attribute thisAttr = getAttributeById(updateSourceAttr.getId(), true); |
| if (thisAttr != null && (thisAttr.getGammaId() != updateSourceAttr.getGammaId() || thisAttr.isDirty())) { |
| thisAttr.setValue(updateSourceAttr.getValue()); |
| } |
| } |
| } |
| |
| private void updateRelationsFromBranch(IOseeBranch updateSourceBranch) throws OseeCoreException { |
| Artifact updateSourceArtifact = ArtifactQuery.getArtifactFromId(this.getArtId(), updateSourceBranch); |
| for (RelationLink updateSourceRel : updateSourceArtifact.getRelationsAll(DeletionFlag.EXCLUDE_DELETED)) { |
| Artifact artifactOnSourceOtherSide = updateSourceRel.getArtifactOnOtherSide(updateSourceArtifact); |
| Artifact artifactToBeRelated = |
| ArtifactQuery.checkArtifactFromId(artifactOnSourceOtherSide.getArtId(), this.branch, |
| DeletionFlag.EXCLUDE_DELETED); |
| if (artifactToBeRelated == null) { |
| continue; |
| } |
| RelationTypeSide relTypeSide = |
| new RelationTypeSide(updateSourceRel.getRelationType(), updateSourceRel.getSide(artifactOnSourceOtherSide)); |
| try { |
| addRelation(RelationOrderBaseTypes.PREEXISTING, relTypeSide, artifactToBeRelated); |
| } catch (OseeCoreException ex) { |
| // do nothing |
| } |
| } |
| } |
| |
| /** |
| * @return the transaction number that was set when this artifact was loaded |
| */ |
| public final int getTransactionNumber() { |
| return transactionId; |
| } |
| |
| public final TransactionRecord getTransactionRecord() throws OseeCoreException { |
| if (transactionId == TRANSACTION_SENTINEL) { |
| return null; |
| } |
| return TransactionManager.getTransactionId(transactionId); |
| } |
| |
| /** |
| * @return Returns the gammaId. |
| */ |
| public final int getGammaId() { |
| return gammaId; |
| } |
| |
| public final Collection<AttributeChange> getDirtyFrameworkAttributeChanges() throws OseeDataStoreException { |
| List<AttributeChange> dirtyAttributes = new LinkedList<AttributeChange>(); |
| |
| for (Attribute<?> attribute : internalGetAttributes()) { |
| if (attribute.isDirty()) { |
| AttributeChange change = new AttributeChange(); |
| change.setAttrTypeGuid(attribute.getAttributeType().getGuid()); |
| change.setGammaId(attribute.getGammaId()); |
| change.setAttributeId(attribute.getId()); |
| change.setModTypeGuid(AttributeEventModificationType.getType(attribute.getModificationType()).getGuid()); |
| for (Object obj : attribute.getAttributeDataProvider().getData()) { |
| if (obj == null) { |
| change.getData().add(""); |
| } else if (obj instanceof String) { |
| change.getData().add((String) obj); |
| } else { |
| OseeLog.log(Activator.class, Level.SEVERE, "Unhandled data type " + obj.getClass().getSimpleName()); |
| } |
| } |
| dirtyAttributes.add(change); |
| } |
| } |
| return dirtyAttributes; |
| } |
| |
| /** |
| * Changes the artifact type. |
| */ |
| public final void setArtifactType(IArtifactType artifactType) throws OseeCoreException { |
| if (!this.artifactType.equals(artifactType)) { |
| this.artifactType = ArtifactTypeManager.getType(artifactType); |
| objectEditState = EditState.ARTIFACT_TYPE_MODIFIED; |
| if (isInDb()) { |
| lastValidModType = modType; |
| modType = ModificationType.MODIFIED; |
| } |
| } |
| } |
| |
| public final void clearEditState() { |
| objectEditState = EditState.NO_CHANGE; |
| resetToPreviousModType(); |
| } |
| |
| private static final Pattern safeNamePattern = Pattern.compile("[^A-Za-z0-9 ]"); |
| private static final String[] NUMBER = new String[] { |
| "Zero", |
| "One", |
| "Two", |
| "Three", |
| "Four", |
| "Five", |
| "Six", |
| "Seven", |
| "Eight", |
| "Nine"}; |
| |
| /** |
| * Since artifact names are free text it is important to reformat the name to ensure it is suitable as an element |
| * name |
| * |
| * @return artifact name in a form that is valid as an XML element |
| */ |
| public final String getSafeName() { |
| String elementName = safeNamePattern.matcher(getName()).replaceAll("_"); |
| |
| // Fix the first character if it is a number by replacing it with its name |
| char firstChar = elementName.charAt(0); |
| if (firstChar >= '0' && firstChar <= '9') { |
| elementName = NUMBER[firstChar - '0'] + elementName.substring(1); |
| } |
| |
| if (elementName.length() > 75) { |
| elementName = elementName.substring(0, 75); |
| } |
| |
| return elementName; |
| } |
| |
| @Override |
| @SuppressWarnings({"rawtypes"}) |
| public final Object getAdapter(Class adapter) { |
| if (adapter == null) { |
| throw new IllegalArgumentException("adapter can not be null"); |
| } |
| |
| if (adapter.isInstance(this)) { |
| return this; |
| } |
| return null; |
| } |
| |
| @Override |
| public final int hashCode() { |
| // Don't use branch so we are consistent with equals method |
| return super.hashCode(); |
| } |
| |
| /** |
| * @param obj the reference object with which to compare. |
| * @return <code>true</code> if this artifact has the same GUID and branch <code>false</code> otherwise. |
| */ |
| @Override |
| public final boolean equals(Object obj) { |
| if (obj instanceof IBasicGuidArtifact) { |
| IBasicGuidArtifact other = (IBasicGuidArtifact) obj; |
| boolean result = getGuid().equals(other.getGuid()); |
| if (result) { |
| if (getBranchGuid() != null && other.getBranchGuid() != null) { |
| result = getBranchGuid().equals(other.getBranchGuid()); |
| } |
| } |
| return result; |
| } |
| if (obj instanceof IArtifact) { |
| IArtifact other = (IArtifact) obj; |
| boolean result = getGuid().equals(other.getGuid()); |
| if (result) { |
| if (getBranch() != null && other.getBranch() != null) { |
| result = getBranch().equals(other.getBranch()); |
| } else { |
| result = getBranch() == null && other.getBranch() == null; |
| } |
| } |
| return result; |
| } |
| if (obj instanceof IArtifactToken) { |
| IArtifactToken token = (IArtifactToken) obj; |
| return getGuid().equals(token.getGuid()); |
| } |
| return false; |
| } |
| |
| public final int getRemainingAttributeCount(IAttributeType attributeType) throws OseeCoreException { |
| return AttributeTypeManager.getMaxOccurrences(attributeType) - getAttributeCount(attributeType); |
| } |
| |
| public final int getAttributeCount(IAttributeType attributeType) throws OseeCoreException { |
| ensureAttributesLoaded(); |
| return getAttributes(attributeType).size(); |
| } |
| |
| void setArtId(int artifactId) { |
| this.artId = artifactId; |
| } |
| |
| /** |
| * Return relations that exist between artifacts |
| */ |
| public final ArrayList<RelationLink> internalGetRelations(Artifact artifact) throws OseeCoreException { |
| ArrayList<RelationLink> relations = new ArrayList<RelationLink>(); |
| for (RelationLink relation : getRelationsAll(DeletionFlag.EXCLUDE_DELETED)) { |
| try { |
| if (relation.getArtifactOnOtherSide(this).equals(artifact)) { |
| relations.add(relation); |
| } |
| } catch (ArtifactDoesNotExist ex) { |
| OseeLog.log(Activator.class, Level.SEVERE, ex); |
| } |
| } |
| return relations; |
| } |
| |
| public final List<RelationLink> getRelations(IRelationTypeSide relationEnum) throws OseeCoreException { |
| return RelationManager.getRelations(this, relationEnum, relationEnum.getSide()); |
| } |
| |
| /** |
| * Return relations that exist between artifacts of type side |
| */ |
| @Deprecated |
| public final ArrayList<RelationLink> getRelations(IRelationTypeSide side, Artifact artifact) throws OseeCoreException { |
| ArrayList<RelationLink> relations = new ArrayList<RelationLink>(); |
| for (RelationLink relation : getRelations(side)) { |
| try { |
| if (relation.getArtifactOnOtherSide(this).equals(artifact)) { |
| relations.add(relation); |
| } |
| } catch (ArtifactDoesNotExist ex) { |
| OseeLog.log(Activator.class, Level.SEVERE, ex); |
| } |
| } |
| return relations; |
| } |
| |
| public final List<RelationLink> getRelationsAll(DeletionFlag deletionFlag) { |
| return RelationManager.getRelationsAll(this, deletionFlag); |
| } |
| |
| /** |
| * This method should never be called from outside the OSEE Application Framework |
| */ |
| void internalSetPersistenceData(int gammaId, int transactionId, ModificationType modType, boolean historical) { |
| this.gammaId = gammaId; |
| this.transactionId = transactionId; |
| this.historical = historical; |
| this.modType = modType; |
| this.lastValidModType = modType; |
| this.objectEditState = EditState.NO_CHANGE; |
| } |
| |
| /** |
| * This method should never be called from outside the OSEE Application Framework |
| */ |
| public final void setTransactionId(int transactionId) { |
| this.transactionId = transactionId; |
| } |
| |
| public final Date getLastModified() throws OseeCoreException { |
| if (transactionId == TRANSACTION_SENTINEL) { |
| return new Date(); |
| } |
| return getTransactionRecord().getTimeStamp(); |
| } |
| |
| public final User getLastModifiedBy() throws OseeCoreException { |
| TransactionRecord transactionRecord = getTransactionRecord(); |
| if (transactionRecord == null) { |
| return UserManager.getUser(SystemUser.OseeSystem); |
| } |
| return UserManager.getUserByArtId(transactionRecord.getAuthor()); |
| } |
| |
| void meetMinimumAttributeCounts(boolean isNewArtifact) throws OseeCoreException { |
| if (modType == ModificationType.DELETED) { |
| return; |
| } |
| for (IAttributeType attributeType : getAttributeTypes()) { |
| int missingCount = AttributeTypeManager.getMinOccurrences(attributeType) - getAttributeCount(attributeType); |
| for (int i = 0; i < missingCount; i++) { |
| initializeAttribute(attributeType, ModificationType.NEW, isNewArtifact, true); |
| } |
| } |
| } |
| |
| public final ModificationType getModType() { |
| return modType; |
| } |
| |
| @Override |
| public final Artifact getFullArtifact() { |
| return this; |
| } |
| |
| public final DefaultBasicGuidArtifact getBasicGuidArtifact() { |
| return new DefaultBasicGuidArtifact(getBranch().getGuid(), getArtifactType().getGuid(), getGuid()); |
| } |
| |
| @Override |
| public final Long getArtTypeGuid() { |
| return getArtifactType().getGuid(); |
| } |
| |
| @Override |
| public final String getBranchGuid() { |
| return getBranch().getGuid(); |
| } |
| |
| public final Set<DefaultBasicGuidRelationReorder> getRelationOrderRecords() { |
| return relationOrderRecords; |
| } |
| |
| public Set<AttributeType> getAttributeTypesUsed() throws OseeCoreException { |
| Set<AttributeType> types = new HashSet<AttributeType>(); |
| for (Attribute<?> attr : getAttributes()) { |
| types.add(attr.getAttributeType()); |
| } |
| return types; |
| } |
| |
| } |