/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.ptc.tifworkbench.model;
import com.ptc.tifworkbench.jaxbbinding.FieldDefinition;
import com.ptc.tifworkbench.jaxbbinding.FieldsDefinitions;
import com.ptc.tifworkbench.jaxbbinding.ImSolution;
import com.ptc.tifworkbench.jaxbbinding.ObjectFactory;
import com.ptc.tifworkbench.jaxbbinding.QueriesDefinition;
import com.ptc.tifworkbench.jaxbbinding.QueryDefinition;
import com.ptc.tifworkbench.jaxbbinding.StateDefinition;
import com.ptc.tifworkbench.jaxbbinding.StatesDefinition;
import com.ptc.tifworkbench.jaxbbinding.TriggerDefinition;
import com.ptc.tifworkbench.jaxbbinding.TriggersDefinition;
import com.ptc.tifworkbench.jaxbbinding.TypeDefinition;
import com.ptc.tifworkbench.jaxbbinding.TypesDefinition;
import com.ptc.tifworkbench.worker.StatusReporter;
import java.util.List;
/**
* Calculate a difference model that will make S1 equivalent to S2.
* @author pbowden
*/
public class SolutionDifferencer
{
private ImSolution diffSol, s1, s2;
private ObjectFactory factory = new ObjectFactory();
private StatusReporter reporter;
public SolutionDifferencer(ImSolution s1, ImSolution s2)
{
this.s1=s1;
this.s2=s2;
}
public ImSolution getDifferenceSolution()
{
assert(diffSol != null);
return diffSol;
}
public void setReporter(StatusReporter reporter)
{
this.reporter = reporter;
}
public void doDifference()
{
this.diffSol = factory.createImSolution();
diffSol.setUsers(factory.createUsersDefinitions());
diffSol.setGroups(factory.createGroupsDefinition());
diffSol.setProjects(factory.createProjectsDefinitions());
if(!s1.equals(s2))
{
report(0, "Differencing");
diffStates();
diffFields();
diffTriggers();
diffQueries();
diffTypes();
report(100, "Done differencing solutions.");
}
else
report(100, "Solutions are identical");
}
protected void diffStates()
{
report(10, "State definitions");
StatesDefinition diffStateDefs = factory.createStatesDefinition();
diffSol.setStates(diffStateDefs);
SimpleTifDifference<StateDefinition> sd =
new SimpleTifDifference<StateDefinition>(s1.getStates().getState(),
s2.getStates().getState(),
diffStateDefs.getState(),
diffStateDefs.getEditState())
{
@Override
public String getKey(StateDefinition d)
{
return d.getName();
}
@Override
public void logMessage(String message)
{
log(message);
}
};
sd.compareDefinitions();
}
protected void diffFields()
{
report(20, "Field definitions");
FieldsDefinitions diffFieldDefs = factory.createFieldsDefinitions();
diffSol.setFields(diffFieldDefs);
SimpleTifDifference<FieldDefinition> fd =
new SimpleTifDifference<FieldDefinition>(s1.getFields().getField(),
s2.getFields().getField(),
diffFieldDefs.getField(),
diffFieldDefs.getEditField())
{
@Override
public String getKey(FieldDefinition d)
{
return d.getName();
}
@Override
public void logMessage(String message)
{
log(message);
}
};
fd.compareDefinitions();
}
protected void diffTriggers()
{
report(30, "Trigger definitions");
TriggersDefinition diffTriggerDefs = factory.createTriggersDefinition();
diffSol.setTriggers(diffTriggerDefs);
SimpleTifDifference<TriggerDefinition> td =
new SimpleTifDifference<TriggerDefinition>(s1.getTriggers().getTrigger(),
s2.getTriggers().getTrigger(),
diffTriggerDefs.getTrigger(),
diffTriggerDefs.getEditTrigger())
{
@Override
public String getKey(TriggerDefinition d)
{
return d.getName();
}
@Override
public void logMessage(String message)
{
log(message);
}
};
td.compareDefinitions();
}
protected void diffQueries()
{
report(40, "Query definitions");
QueriesDefinition diffQueryDefs = factory.createQueriesDefinition();
diffSol.setQueries(diffQueryDefs);
SimpleTifDifference<QueryDefinition> qd =
new SimpleTifDifference<QueryDefinition>(s1.getQueries().getQuery(),
s2.getQueries().getQuery(),
diffQueryDefs.getQuery(),
diffQueryDefs.getEditQuery())
{
@Override
public String getKey(QueryDefinition d)
{
return d.getName();
}
@Override
public void logMessage(String message)
{
log(message);
}
};
qd.compareDefinitions();
}
/**
* Things to diff within types:
* Properties
* Visible fields / editability / relevance (these can be done in the same diff)
* State transitions / mandatory fields (need to be done in one lump)
* Domain declarations
*/
protected void diffTypes()
{
report(50, "Type definitions");
TypesDefinition diffTypeDefs = factory.createTypesDefinition();
diffSol.setTypes(diffTypeDefs);
CompoundTifDifference<TypeDefinition> td =
new CompoundTifDifference<TypeDefinition>(s1.getTypes().getType(),
s2.getTypes().getType(),
diffTypeDefs.getType(),
diffTypeDefs.getEditType())
{
@Override
public String getKey(TypeDefinition d)
{
return d.getName();
}
@Override
public void subCompare(TypeDefinition td1, TypeDefinition td2,
List<TypeDefinition> diffEdit)
{
diffTypeComponents(td1, td2, diffEdit);
}
@Override
public void logMessage(String message)
{
log(message);
}
};
td.compareDefinitions();
}
protected void diffTypeComponents(TypeDefinition td1, TypeDefinition td2, List<TypeDefinition> diff)
{
TypeDefinition tdDiff = factory.createTypeDefinition();
tdDiff.setName(td1.getName());
diff.add(tdDiff);
diffTypeAttributes(td1, td2, tdDiff);
diffTypeProperties(td1, td2, tdDiff);
diffTypeVisibleFields(td1, td2, tdDiff);
diffTypeStates(td1, td2, tdDiff);
diffTypeDocumentModel(td1, td2, tdDiff);
diffTypeTestModel(td1, td2, tdDiff);
diffTypeConstraints(td1, td2, tdDiff);
}
/**
* If any properties are different we have to re-specify <b>all</b> of them
* and not only the ones that are different.
* @param td1
* @param td2
* @param tdDiff
*/
protected void diffTypeAttributes(TypeDefinition td1, TypeDefinition td2, TypeDefinition tdDiff)
{
report(55, " " + td1.getName() + " attributes.");
if(td1.isBacksProject() != td2.isBacksProject())
{
log(" Changing attribute 'backs project': " + td2.isBacksProject());
tdDiff.setBacksProject(td2.isBacksProject());
}
if(td1.isAllowCP() != td2.isAllowCP())
{
log(" Changing attribute 'allows change package': " + td2.isAllowCP());
tdDiff.setAllowCP(td2.isAllowCP());
}
if(td1.isCanDelete() != td2.isCanDelete())
{
log(" Changing attribute 'can delete': " + td2.isCanDelete());
tdDiff.setCanDelete(td2.isCanDelete());
}
if(td1.isCanLabel() != td2.isCanLabel())
{
log(" Changing attribute 'can label': " + td2.isCanLabel());
tdDiff.setCanLabel(td2.isCanLabel());
}
if(td1.isHaveRevisions() != td2.isHaveRevisions())
{
log(" Changing attribute 'has revisions': " + td2.isHaveRevisions());
tdDiff.setHaveRevisions(td2.isHaveRevisions());
}
if(td1.isShowHistory() != td2.isShowHistory())
{
log(" Changing attribute 'show history': " + td2.isShowHistory());
tdDiff.setShowHistory(td2.isShowHistory());
}
if(td1.isShowWorkflow() != td2.isShowWorkflow())
{
log(" Changing attribute 'show workflow': " + td2.isShowWorkflow());
tdDiff.setShowWorkflow(td2.isShowWorkflow());
}
if(td1.isTimeTracking() != td2.isTimeTracking())
{
log(" Changing attribute 'can track time': " + td2.isTimeTracking());
tdDiff.setTimeTracking(td2.isTimeTracking());
}
}
/**
* If any properties are different we have to re-specify <b>all</b> of them
* and not only the ones that are different.
* @param td1
* @param td2
* @param tdDiff
*/
protected void diffTypeProperties(TypeDefinition td1, TypeDefinition td2, TypeDefinition tdDiff)
{
report(60, " " + td1.getName() + " property definitions.");
String name = td1.getName();
if(td1.getProperties() == null || td1.getProperties().getProperty().isEmpty())
{
// No properties in the source type: if we have td2 just copy them in.
if(td2.getProperties() != null)
{
log(" ** No type properties in source solution. Adding from target solution.");
tdDiff.setProperties(td2.getProperties());
}
}
else if(td2.getProperties() == null || td2.getProperties().getProperty().isEmpty())
{
log(" ** No type properties in target solution. Removing from the source solution.");
tdDiff.setProperties(null);
}
else if(!td1.getProperties().equals(td2.getProperties()))
{
log(" ** Type properties differ. Editing");
tdDiff.setProperties(td2.getProperties());
}
/* We can log more details if required.
PropertiesDefinition diffPropsDefs = factory.createPropertiesDefinition();
tdDiff.setProperties(diffPropsDefs);
SimpleTifDifference<PropertyDefinition> pd =
new SimpleTifDifference<PropertyDefinition>(td1.getProperties().getProperty(),
td2.getProperties().getProperty(),
diffPropsDefs.getProperty())
{
@Override
public String getKey(PropertyDefinition d)
{
return d.getName();
}
};
pd.compareDefinitions();
*/
}
protected void diffTypeVisibleFields(TypeDefinition td1, TypeDefinition td2, TypeDefinition tdDiff)
{
report(70, " " + td1.getName() + " visible fields.");
if(!td1.getFields().equals(td2.getFields()))
{
log(" ** Visible differ. Adding");
tdDiff.setFields(td2.getFields());
}
}
protected void diffTypeStates(TypeDefinition td1, TypeDefinition td2, TypeDefinition tdDiff)
{
report(80, " " + td1.getName() + " state definitions.");
if(!td1.getStates().equals(td2.getStates()))
{
log(" ** State transitions differ. Adding");
tdDiff.setStates(td2.getStates());
}
}
protected void diffTypeDocumentModel(TypeDefinition td1, TypeDefinition td2, TypeDefinition tdDiff)
{
report(85, " " + td1.getName() + " document model.");
if(td1.getDocumentModel() == null)
{
if(td2.getDocumentModel() != null)
{
log(" ** No type document in source solution. Adding from target solution.");
tdDiff.setDocumentModel(td2.getDocumentModel());
return;
}
}
if(td2.getDocumentModel() == null)
{
log(" ** No type document model in target solution. Removing from the source solution.");
tdDiff.setDocumentModel(null);
return;
}
if(!td1.getDocumentModel().equals(td2.getDocumentModel()))
{
log(" ** Document models differ. Adding");
tdDiff.setDocumentModel(td2.getDocumentModel());
}
}
protected void diffTypeTestModel(TypeDefinition td1, TypeDefinition td2, TypeDefinition tdDiff)
{
report(90, " " + td1.getName() + " test model.");
if(td1.getTestManagement() == null)
{
if(td2.getTestManagement() != null)
{
log(" ** No type test management in source solution. Adding from target solution.");
tdDiff.setTestManagement(td2.getTestManagement());
return;
}
}
if(td2.getTestManagement() == null)
{
log(" ** No type test management model in target solution. Removing from the source solution.");
tdDiff.setTestManagement(null);
return;
}
if(!td1.getTestManagement().equals(td2.getTestManagement()))
{
log(" ** Test management models differ. Adding");
tdDiff.setTestManagement(td2.getTestManagement());
}
}
protected void diffTypeConstraints(TypeDefinition td1, TypeDefinition td2, TypeDefinition tdDiff)
{
report(95, " " + td1.getName() + " constraints.");
if(td1.getConstraints() == null)
{
if(td2.getConstraints() != null)
{
log(" ** No type constraints in source solution. Adding from target solution.");
tdDiff.setConstraints(td2.getConstraints());
return;
}
}
if(td2.getConstraints() == null)
{
log(" ** No type constraints in target solution. Removing from the source solution.");
tdDiff.setConstraints(null);
return;
}
if(!td1.getConstraints().equals(td2.getConstraints()))
{
log(" ** Constraints differ. Adding");
tdDiff.setConstraints(td2.getConstraints());
}
}
protected void report(int prog, String mess)
{
if(reporter != null)
{
reporter.reportStatus(prog, mess);
log(mess);
}
}
protected void log(String message)
{
if(reporter != null)
reporter.reportDetail(message);
}
}