blob: be258faccd6c7fe4b46b15800f39bf79bbd55665 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 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.conflict;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.TreeSet;
import java.util.logging.Level;
import org.eclipse.core.runtime.Platform;
import org.eclipse.osee.framework.core.enums.ConflictStatus;
import org.eclipse.osee.framework.core.enums.ConflictType;
import org.eclipse.osee.framework.core.enums.CoreAttributeTypes;
import org.eclipse.osee.framework.core.exception.ArtifactDoesNotExist;
import org.eclipse.osee.framework.core.exception.AttributeDoesNotExist;
import org.eclipse.osee.framework.core.exception.OseeExceptions;
import org.eclipse.osee.framework.core.model.Branch;
import org.eclipse.osee.framework.core.model.TransactionRecord;
import org.eclipse.osee.framework.core.model.type.AttributeType;
import org.eclipse.osee.framework.jdk.core.type.OseeCoreException;
import org.eclipse.osee.framework.jdk.core.type.OseeStateException;
import org.eclipse.osee.framework.jdk.core.util.io.Streams;
import org.eclipse.osee.framework.logging.OseeLevel;
import org.eclipse.osee.framework.logging.OseeLog;
import org.eclipse.osee.framework.skynet.core.artifact.Artifact;
import org.eclipse.osee.framework.skynet.core.artifact.Attribute;
import org.eclipse.osee.framework.skynet.core.artifact.BranchManager;
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.attribute.EnumeratedAttribute;
import org.eclipse.osee.framework.skynet.core.attribute.StringAttribute;
import org.eclipse.osee.framework.skynet.core.attribute.WordAttribute;
import org.eclipse.osee.framework.skynet.core.internal.Activator;
/**
* @author Jeff C. Phillips
* @author Theron Virgin
*/
public class AttributeConflict extends Conflict {
public static final String EMPTY_XML = "<w:p><w:r><w:t></w:t></w:r></w:p>";
public final static String NO_VALUE = "";
public final static String STREAM_DATA = "Stream data";
public final static String RESOLVE_MERGE_MARKUP =
"Can not mark as resolved an attribute that has merge markup. Finish merging the document to be able to resolve the conflict.";
public final static String DIFF_MERGE_MARKUP =
"Can not run a diff against an attribute that has merge markup. Finish merging the document to be able to resolve the conflict.";
private final int attrId;
private final long attrTypeId;
private Object sourceObject;
private Object destObject;
private Attribute<?> attribute = null;
private Attribute<?> sourceAttribute = null;
private Attribute<?> destAttribute = null;
private AttributeType attributeType;
private boolean mergeEqualsSource;
private boolean mergeEqualsDest;
private boolean sourceEqualsDest;
private static final boolean DEBUG =
"TRUE".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.osee.framework.ui.skynet/debug/Merge"));
public AttributeConflict(int sourceGamma, int destGamma, int artId, TransactionRecord toTransactionId, String sourceValue, int attrId, long attrTypeId, Branch mergeBranch, Branch sourceBranch, Branch destBranch) throws OseeCoreException {
super(sourceGamma, destGamma, artId, toTransactionId, null, mergeBranch, sourceBranch, destBranch);
this.attrId = attrId;
this.attrTypeId = attrTypeId;
this.status = ConflictStatus.EDITED;
computeEqualsValues();
}
public Attribute<?> getAttribute() throws OseeCoreException {
if (attribute != null) {
return attribute;
}
Collection<Attribute<Object>> localAttributes = getArtifact().getAttributes(getAttributeType());
for (Attribute<Object> localAttribute : localAttributes) {
if (localAttribute.getId() == attrId) {
attribute = localAttribute;
}
}
return attribute;
}
public Attribute<?> getSourceAttribute(boolean allowDeleted) throws OseeCoreException {
if (sourceAttribute != null) {
return sourceAttribute;
}
Collection<Attribute<?>> localAttributes;
if (allowDeleted) {
localAttributes = getSourceArtifact().getAttributes(true);
} else {
localAttributes = getSourceArtifact().getAttributes();
}
for (Attribute<?> localAttribute : localAttributes) {
if (localAttribute.getId() == attrId) {
sourceAttribute = localAttribute;
}
}
if (sourceAttribute == null) {
if (sourceBranch != null) {
throw new AttributeDoesNotExist("Attribute %d could not be found on artifact %d on branch %s", attrId,
getArtId(), sourceBranch.getUuid());
} else {
throw new AttributeDoesNotExist("Attribute %d could not be found on artifact %d", attrId, getArtId());
}
}
return sourceAttribute;
}
public Attribute<?> getDestAttribute() throws OseeCoreException {
if (destAttribute != null) {
return destAttribute;
}
Collection<Attribute<Object>> localAttributes = getDestArtifact().getAttributes(getAttributeType());
for (Attribute<Object> localAttribute : localAttributes) {
if (localAttribute.getId() == attrId) {
destAttribute = localAttribute;
}
}
if (destAttribute == null) {
throw new AttributeDoesNotExist("Attribute %d could not be found on artifact %d on branch %s", attrId,
getArtId(), destBranch.getUuid());
}
return destAttribute;
}
private Attribute<?> getAttribute(Artifact artifact) throws OseeCoreException {
Attribute<?> attribute = null;
Collection<Attribute<Object>> localAttributes = artifact.getAttributes(getAttributeType());
for (Attribute<Object> localAttribute : localAttributes) {
if (localAttribute.getId() == attrId) {
attribute = localAttribute;
}
}
if (attribute == null) {
throw new AttributeDoesNotExist("Attribute %d could not be found on artifact %d on branch %s", attrId,
artifact.getArtId(), artifact.getBranch().getGuid());
}
return attribute;
}
/**
* @return the attributeType
*/
public AttributeType getAttributeType() throws OseeCoreException {
if (attributeType == null) {
attributeType = AttributeTypeManager.getTypeByGuid(attrTypeId);
}
return attributeType;
}
public Object getSourceObject() throws OseeCoreException {
if (sourceObject != null) {
return sourceObject;
}
try {
sourceObject = getSourceAttribute(false).getValue();
} catch (AttributeDoesNotExist ex) {
sourceObject = "DELETED";
}
return sourceObject;
}
public Object getDestObject() throws OseeCoreException {
if (destObject != null) {
return destObject;
}
try {
destObject = getDestAttribute().getValue();
} catch (AttributeDoesNotExist ex) {
destObject = "DELETED";
}
return destObject;
}
@Override
@SuppressWarnings("rawtypes")
public Object getAdapter(Class adapter) {
if (adapter == null) {
throw new IllegalArgumentException("adapter can not be null");
}
if (adapter.isInstance(this)) {
return this;
}
try {
Attribute attribute = null;
try {
attribute = getSourceAttribute(true);
} catch (AttributeDoesNotExist ex) {
// do nothing
}
if (adapter.isInstance(attribute)) {
return attribute;
}
} catch (Exception ex) {
OseeLog.log(Activator.class, Level.SEVERE, ex);
}
return null;
}
public int getAttrId() {
return attrId;
}
public long getTypeId() {
return attrTypeId;
}
@Override
public String getDestDisplayData() throws OseeCoreException {
String displayValue =
isWordAttribute() ? STREAM_DATA : getDestObject() == null ? "Null Value" : getDestObject().toString();
try {
getDestAttribute();
} catch (AttributeDoesNotExist ex) {
displayValue = "DELETED";
}
return displayValue;
}
@Override
public String getSourceDisplayData() throws OseeCoreException {
String displayValue =
isWordAttribute() ? STREAM_DATA : getSourceObject() == null ? "Null Value" : getSourceObject().toString();
try {
getSourceAttribute(false);
} catch (AttributeDoesNotExist ex) {
displayValue = "DELETED";
}
return displayValue;
}
@Override
public boolean mergeEqualsSource() {
return mergeEqualsSource;
}
@Override
public boolean mergeEqualsDestination() {
return mergeEqualsDest;
}
@Override
public boolean sourceEqualsDestination() {
return sourceEqualsDest;
}
public Object getMergeObject() throws OseeCoreException {
return getAttribute() != null ? getAttribute().getValue() : null;
}
public TreeSet<String> getEnumerationAttributeValues() throws OseeCoreException {
return new TreeSet<String>(AttributeTypeManager.getEnumerationValues(getAttributeType()));
}
public boolean setStringAttributeValue(String value) throws OseeCoreException {
if (!getStatus().isOverwriteAllowed()) {
if (DEBUG) {
System.out.println(String.format("AttributeConflict: Failed setting the Merge Value for attr_id %d",
getAttrId()));
}
return false;
}
if (DEBUG) {
System.out.println(String.format("AttributeConflict: Set the Merge Value for attr_id %d", getAttrId()));
}
getArtifact().setSoleAttributeFromString(getAttributeType(), value);
getArtifact().persist(getClass().getSimpleName());
markStatusToReflectEdit();
return true;
}
public boolean setAttributeValue(Object value) throws OseeCoreException {
if (!getStatus().isOverwriteAllowed()) {
if (DEBUG) {
System.out.println(String.format("AttributeConflict: Failed setting the Merge Value for attr_id %d",
getAttrId()));
}
return false;
}
if (DEBUG) {
System.out.println(String.format("AttributeConflict: Set the Merge Value for attr_id %d", getAttrId()));
}
getArtifact().setSoleAttributeValue(getAttributeType(), value);
getArtifact().persist(getClass().getSimpleName());
markStatusToReflectEdit();
return true;
}
@Override
public boolean setToSource() throws OseeCoreException {
if (!getStatus().isOverwriteAllowed() || getSourceObject() == null) {
if (DEBUG) {
System.out.println(String.format(
"AttributeConflict: Failed setting the Merge Value to the Source Value for attr_id %d", getAttrId()));
}
return false;
}
if (DEBUG) {
System.out.println(String.format("AttributeConflict: Set the Merge Value to the Source Value for attr_id %d",
getAttrId()));
}
getArtifact().setSoleAttributeValue(getAttributeType(), getSourceObject());
getArtifact().persist(getClass().getSimpleName());
markStatusToReflectEdit();
return true;
}
@Override
public boolean setToDest() throws OseeCoreException {
if (!getStatus().isOverwriteAllowed() || getDestObject() == null) {
if (DEBUG) {
System.out.println(String.format(
"AttributeConflict: Failed setting the Merge Value to the Dest Value for attr_id %d", getAttrId()));
}
return false;
}
if (DEBUG) {
System.out.println(String.format("AttributeConflict: Set the Merge Value to the Dest Value for attr_id %d",
getAttrId()));
}
getArtifact().setSoleAttributeValue(getAttributeType(), getDestObject());
getArtifact().persist(getClass().getSimpleName());
markStatusToReflectEdit();
return true;
}
@Override
public boolean clearValue() throws OseeCoreException {
if (!getStatus().isOverwriteAllowed()) {
if (DEBUG) {
System.out.println(String.format("AttributeConflict: Failed to clear the Merge Value for attr_id %d",
getAttrId()));
}
return false;
}
if (DEBUG) {
System.out.println(String.format("AttributeConflict: Cleared the Merge Value for attr_id %d", getAttrId()));
}
setStatus(ConflictStatus.UNTOUCHED);
if (isWordAttribute()) {
getAttribute().resetToDefaultValue();
getArtifact().persist(getClass().getSimpleName());
} else {
getArtifact().setSoleAttributeFromString(getAttributeType(), NO_VALUE);
getArtifact().persist(getClass().getSimpleName());
}
computeEqualsValues();
return true;
}
@Override
public void computeEqualsValues() throws OseeCoreException {
mergeEqualsSource = compareObjects(getMergeObject(), getSourceObject());
mergeEqualsDest = compareObjects(getMergeObject(), getDestObject());
sourceEqualsDest = compareObjects(getSourceObject(), getDestObject());
}
private boolean compareObjects(Object obj1, Object obj2) throws OseeCoreException {
if (obj1 == null || obj2 == null) {
return false;
}
if (obj1 instanceof InputStream && obj2 instanceof InputStream) {
InputStream inputStream1 = (InputStream) obj1;
InputStream inputStream2 = (InputStream) obj2;
boolean equals = Arrays.equals(Streams.getByteArray(inputStream1), Streams.getByteArray(inputStream2));
try {
inputStream1.reset();
inputStream2.reset();
} catch (IOException ex) {
OseeExceptions.wrapAndThrow(ex);
}
return equals;
}
return obj1.equals(obj2);
}
public void markStatusToReflectEdit() throws OseeCoreException {
computeEqualsValues();
if (status.equals(ConflictStatus.UNTOUCHED) || status.equals(ConflictStatus.OUT_OF_DATE_RESOLVED) || status.equals(ConflictStatus.OUT_OF_DATE) || status.equals(ConflictStatus.PREVIOUS_MERGE_APPLIED_CAUTION) || status.equals(ConflictStatus.PREVIOUS_MERGE_APPLIED_SUCCESS)) {
setStatus(ConflictStatus.EDITED);
}
}
@Override
public ConflictStatus computeStatus() throws OseeCoreException {
ConflictStatus passedStatus = ConflictStatus.UNTOUCHED;
try {
getSourceAttribute(false);
} catch (AttributeDoesNotExist ex) {
passedStatus = ConflictStatus.INFORMATIONAL;
}
try {
getDestAttribute();
} catch (AttributeDoesNotExist ex) {
passedStatus = ConflictStatus.INFORMATIONAL;
}
return super.computeStatus(attrId, passedStatus);
}
@Override
public int getObjectId() {
return attrId;
}
@Override
public String getMergeDisplayData() throws OseeCoreException {
ConflictStatus status = getStatus();
if (status.isUntouched() && !(sourceEqualsDestination() && mergeEqualsSource()) || status.isInformational()) {
return NO_VALUE;
}
if (!isWordAttribute()) {
return getMergeObject() == null ? null : getMergeObject().toString();
}
return AttributeConflict.STREAM_DATA;
}
@Override
public String getChangeItem() throws OseeCoreException {
return getAttributeType().getName();
}
@Override
public ConflictType getConflictType() {
return ConflictType.ATTRIBUTE;
}
@Override
public int getMergeGammaId() throws OseeCoreException {
return getAttribute().getGammaId();
}
public boolean isWordAttribute() {
boolean toReturn = false;
try {
toReturn = getAttributeType().equals(CoreAttributeTypes.WordTemplateContent);
} catch (OseeCoreException ex) {
OseeLog.log(getClass(), OseeLevel.SEVERE_POPUP, ex);
}
return toReturn;
}
@Override
public void setStatus(ConflictStatus status) throws OseeCoreException {
if (status.equals(ConflictStatus.RESOLVED) && isWordAttribute() && ((WordAttribute) getAttribute()).containsWordAnnotations()) {
throw new OseeStateException(RESOLVE_MERGE_MARKUP);
}
super.setStatus(status);
}
public boolean wordMarkupPresent() throws OseeCoreException {
if (isWordAttribute() && ((WordAttribute) getAttribute()).containsWordAnnotations()) {
return true;
}
return false;
}
@Override
public boolean applyPreviousMerge(long mergeBranchId, long destBranchId) throws OseeCoreException {
if (DEBUG) {
System.out.println("Apply the merge using the merge branch value " + mergeBranchId);
}
if (!getStatus().isResolved()) {
Artifact mergeArtifact;
Artifact destArtifact;
try {
mergeArtifact =
ArtifactQuery.getArtifactFromId(getArtifact().getArtId(), BranchManager.getBranch(mergeBranchId));
destArtifact =
ArtifactQuery.getArtifactFromId(getArtifact().getArtId(), BranchManager.getBranch(destBranchId));
} catch (ArtifactDoesNotExist ex) {
return false;
}
setAttributeValue(getAttribute(mergeArtifact).getValue());
computeEqualsValues();
if (getDestAttribute().getValue().equals(getAttribute(destArtifact).getValue()) || getDestAttribute().getGammaId() == getAttribute(
destArtifact).getGammaId()) {
setStatus(ConflictStatus.PREVIOUS_MERGE_APPLIED_SUCCESS);
} else {
setStatus(ConflictStatus.PREVIOUS_MERGE_APPLIED_CAUTION);
}
return true;
}
return false;
}
public boolean isSimpleStringAttribute() {
boolean returnValue = true;
returnValue &= !isWordAttribute();
returnValue &= !(attribute instanceof EnumeratedAttribute);
returnValue &= attribute instanceof StringAttribute;
return returnValue;
}
public boolean involvesNativeContent() throws OseeCoreException {
return getArtifact().isAttributeTypeValid(CoreAttributeTypes.NativeContent);
}
}