/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.ptc.tifworkbench.reader;
import com.mks.api.Command;
import com.mks.api.Option;
import com.mks.api.response.APIException;
import com.mks.api.response.Field;
import com.mks.api.response.Item;
import com.mks.api.response.ItemList;
import com.mks.api.response.Response;
import com.mks.api.response.WorkItem;
import com.mks.api.response.WorkItemIterator;
import com.ptc.tifworkbench.integrity.IntegrityException;
import com.ptc.tifworkbench.integrity.IntegrityExceptionEx;
import com.ptc.tifworkbench.jaxbbinding.ConstraintDefinition;
import com.ptc.tifworkbench.jaxbbinding.ConstraintTargetDefinition;
import com.ptc.tifworkbench.jaxbbinding.ConstraintType;
import com.ptc.tifworkbench.jaxbbinding.ConstraintsDefinition;
import com.ptc.tifworkbench.jaxbbinding.DocumentModelDefinition;
import com.ptc.tifworkbench.jaxbbinding.DocumentRole;
import com.ptc.tifworkbench.jaxbbinding.FieldReference;
import com.ptc.tifworkbench.jaxbbinding.FieldsReference;
import com.ptc.tifworkbench.jaxbbinding.MandatoryFieldReference;
import com.ptc.tifworkbench.jaxbbinding.MandatoryFields;
import com.ptc.tifworkbench.jaxbbinding.NextState;
import com.ptc.tifworkbench.jaxbbinding.PropertiesDefinition;
import com.ptc.tifworkbench.jaxbbinding.PropertyDefinition;
import com.ptc.tifworkbench.jaxbbinding.SignificantEdits;
import com.ptc.tifworkbench.jaxbbinding.StateReference;
import com.ptc.tifworkbench.jaxbbinding.StatesReference;
import com.ptc.tifworkbench.jaxbbinding.TestManagementDefintion;
import com.ptc.tifworkbench.jaxbbinding.TestManagementDefintion.Testcase;
import com.ptc.tifworkbench.jaxbbinding.TestManagementDefintion.Testcase.ResultFields;
import com.ptc.tifworkbench.jaxbbinding.TestManagementDefintion.Testsession;
import com.ptc.tifworkbench.jaxbbinding.TestManagementDefintion.Testsession.Groups;
import com.ptc.tifworkbench.jaxbbinding.TestManagementRoleType;
import com.ptc.tifworkbench.jaxbbinding.TestResultModificationType;
import com.ptc.tifworkbench.jaxbbinding.TypeDefinition;
import com.ptc.tifworkbench.jaxbbinding.TypesDefinition;
import com.ptc.tifworkbench.worker.StatusReporter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/**
*
* @author pbowden
*/
public class TypeReader extends AdminObjectReader
{
public static final String [] IGNORE_TYPES =
{"FVA-temporary-ibpl-type", "FVA-temporary"};
private TypesDefinition types;
public TypeReader(TypesDefinition types, StatusReporter reporter) throws IntegrityExceptionEx
{
super(reporter);
this.types=types;
}
@Override
void read() throws IntegrityException
{
log("Reading types.");
List<String> ignore = new ArrayList<String>(Arrays.asList(IGNORE_TYPES));
Command cmd = new Command(Command.IM, "types");
List<String> names = new ArrayList<String>();
try
{
Response resp = getApi().execute(cmd);
WorkItemIterator wkIt = resp.getWorkItems();
while(wkIt.hasNext())
{
WorkItem wk = wkIt.next();
String typeName = wk.getId();
log("Read type: " + typeName);
names.add(typeName);
}
}catch(APIException ex)
{
throw IntegrityExceptionEx.create("Could not get list of types.", ex);
}
int numTypes = names.size();
int count = 0;
for(String typeName : names)
{
if(!ignore.contains(typeName))
{
int prog = (100 * count++)/numTypes;
reportStatus(prog, "Read type: " + typeName);
TypeDefinition td = getFactory().createTypeDefinition();
td.setName(typeName);
types.getType().add(td);
try
{
readType(td, typeName);
} catch(Exception e)
{
log("Failed to read type: " + e.getMessage());
log(" " + e.getClass().getName());
System.out.println("Failed to read type " + typeName + ", " + e.getMessage());
e.printStackTrace(System.out);
}
}
}
}
protected void readType(TypeDefinition tdef, String typeName) throws APIException
{
FieldsReference fref = getFactory().createFieldsReference();
tdef.setFields(fref);
StatesReference sref = getFactory().createStatesReference();
tdef.setStates(sref);
Command cmd = new Command(Command.IM, "viewtype");
cmd.addOption(new Option("showProperties"));
cmd.addSelection(typeName);
Response resp = getApi().execute(cmd);
WorkItem wk = resp.getWorkItem(typeName);
readAttributes(tdef, wk);
readChangePackageAttributes(tdef, wk);
readProperties(tdef, wk);
readVisibleFields(fref, tdef, wk);
readStates(sref, wk);
readDocumentModel(tdef, wk);
readTestManagement(tdef, wk);
readConstraints(tdef, wk);
}
protected void readVisibleFields(FieldsReference fref, TypeDefinition tdef, WorkItem wk)
{
ItemList visibleFields = (ItemList)wk.getField("visibleFields").getList();
if(visibleFields == null)return;
Iterator<Item> itemIterator = visibleFields.getItems();
while(itemIterator.hasNext())
{
Item item = (Item)itemIterator.next();
String fieldName = item.getId();
log(" Read visible field: " + fieldName);
FieldReference fieldRef = getFactory().createFieldReference();
fieldRef.setName(fieldName);
fref.getField().add(fieldRef);
String overrideName = "none";
try
{
overrideName = "relevance";
String relOverride = getOverride(tdef.getName(), fieldName, overrideName);
if(relOverride != null && relOverride.length() > 0)
fieldRef.setRelevance(relOverride);
overrideName = "editability";
String editOverride = getOverride(tdef.getName(), fieldName, overrideName);
if(editOverride != null && editOverride.length() > 0)
fieldRef.setEditability(editOverride);
overrideName = "default";
String defaultOverride = getDefaultOverride(tdef.getName(), fieldName);
if(defaultOverride != null && defaultOverride.length() > 0)
fieldRef.setDefault(defaultOverride);
overrideName = "description";
String descOverride = getDescriptionOverride(tdef.getName(), fieldName);
if(descOverride != null && descOverride.length() > 0)
fieldRef.setDescription(descOverride);
}catch(Exception e)
{
log("Error reading override " + overrideName + " for field " + fieldName + " in type " + tdef.getName());
}
}
}
protected void readStates(StatesReference sref, WorkItem wk)
{
ItemList states = (ItemList)wk.getField("stateTransitions").getList();
if(states == null)return;
Iterator<Item> itemIterator = states.getItems();
while(itemIterator.hasNext())
{
Item item = (Item)itemIterator.next();
String stateName = item.getId();
log(" Read state field: " + stateName);
StateReference stateRef = getFactory().createStateReference();
stateRef.setName(stateName);
sref.getState().add(stateRef);
readMandatoryFieldsForState(stateRef, wk, stateName);
readTransitionsForState(stateRef, item, wk, stateName);
}
}
protected void readAttributes(TypeDefinition tdef, WorkItem wk)
{
tdef.setCanLabel(getBooleanField("labelEnabled", wk));
tdef.setBacksProject(getBooleanField("backsProject", wk));
tdef.setHaveRevisions(getBooleanField("revisionEnabled", wk));
tdef.setCanDelete(getBooleanField("deleteItemEnabled", wk));
tdef.setShowWorkflow(getBooleanField("showWorkflow", wk));
tdef.setShowHistory(getBooleanField("showHistory", wk));
tdef.setTimeTracking(getBooleanField("timeTrackingEnabled", wk));
tdef.setPhase(getSafeField("phaseField", wk)); // Actually in the Item ID.
tdef.setDescription(getSafeField("description", wk));
tdef.setPresentation(getSafeField("viewPresentation", wk));
}
protected void readChangePackageAttributes(TypeDefinition tdef, WorkItem wk)
{
tdef.setCpPolicy(getSafeField("createCPPolicy", wk));
tdef.setAllowCP(getBooleanField("allowChangePackages", wk));
}
protected void readProperties(TypeDefinition tdef, WorkItem wk)
{
ItemList properties = (ItemList)wk.getField("properties").getList();
if(properties != null)
{
Iterator propIterator = properties.getItems();
PropertiesDefinition props = getFactory().createPropertiesDefinition();
tdef.setProperties(props);
while(propIterator.hasNext())
{
Item item = (Item)propIterator.next();
String itemName = item.getId();
log(" Read property: " + itemName);
PropertyDefinition prop = getFactory().createPropertyDefinition();
prop.setName(itemName);
prop.setValue(getSafeField("value", item));
String desc = getSafeField("description", item);
// Make the description safe. Should this be done in the transform?
// We want TIF to be as accurate as possible.
desc = desc.replaceAll("\n", "");
desc = desc.replaceAll("\r", "");
desc = desc.replaceAll("\"", "");
desc = desc.replaceAll(":", ",");
desc = desc.replaceAll(";", ",");
prop.setDescription(desc);
props.getProperty().add(prop);
}
}
}
protected void readDocumentModel(TypeDefinition tdef, WorkItem wk)
{
String docRole = wk.getField("documentClass").getValueAsString();
if(DocumentRole.NONE.value().equals(docRole))
return;
DocumentModelDefinition docDef = getFactory().createDocumentModelDefinition();
tdef.setDocumentModel(docDef);
docDef.setRole(DocumentRole.fromValue(docRole));
if(DocumentRole.SHAREDITEM.value().equals(docRole))
return;
String assocType = wk.getField("associatedType").getItem().getId();
docDef.setAssociatedType(assocType);
Field sigEditsFld = wk.getField("significantEdit");
List<Item> itemList = sigEditsFld.getList();
if(itemList.size() > 0)
{
SignificantEdits sigEdits = getFactory().createSignificantEdits();
for(Item item : itemList)
{
FieldReference fref = getFactory().createFieldReference();
fref.setName(item.getId());
sigEdits.getField().add(fref);
}
docDef.setSignificantEdits(sigEdits);
}
}
protected void readTestManagement(TypeDefinition tdef, WorkItem wk)
{
String testRole = wk.getField("testRole").getValueAsString();
if(TestManagementRoleType.NONE.value().equals(testRole))
return;
TestManagementDefintion testDef = getFactory().createTestManagementDefintion();
tdef.setTestManagement(testDef);
testDef.setRole(TestManagementRoleType.fromValue(testRole));
if(TestManagementRoleType.TEST_CASE.value().equals(testRole))
{
Testcase tc = getFactory().createTestManagementDefintionTestcase();
tc.setEnableTestSteps(getBooleanField("testStepsEnabled", wk));
ResultFields resFlds = getFactory().createTestManagementDefintionTestcaseResultFields();
Field resFld = wk.getField("testCaseResultFields");
List<Item> itemList = resFld.getList();
for(Item item : itemList)
resFlds.getField().add(item.getId());
tc.setResultFields(resFlds);
testDef.setTestcase(tc);
}
if(TestManagementRoleType.TEST_SESSION.value().equals(testRole))
{
Testsession sess = getFactory().createTestManagementDefintionTestsession();
String modPolicy = wk.getField("modifyTestResultPolicy").getValueAsString();
if(modPolicy.equals(TestResultModificationType.ANYONE.value()))
{
sess.setResultModBy(TestResultModificationType.ANYONE);
}
else if(modPolicy.startsWith(TestResultModificationType.GROUPS.value()))
{
sess.setResultModBy(TestResultModificationType.GROUPS);
Groups groups = getFactory().createTestManagementDefintionTestsessionGroups();
sess.setGroups(groups);
List<String> grpList = Arrays.asList(modPolicy.split("=")[1].split(","));
for(String grp : grpList)
groups.getGroup().add(grp);
}
else if(modPolicy.startsWith(TestResultModificationType.USER_FIELD.value()))
{
sess.setResultModBy(TestResultModificationType.USER_FIELD);
String fldName = modPolicy.split("=")[1];
sess.setFieldname(fldName);
}
else if(modPolicy.startsWith(TestResultModificationType.GROUP_FIELD.value()))
{
sess.setResultModBy(TestResultModificationType.GROUP_FIELD);
String fldName = modPolicy.split("=")[1];
sess.setFieldname(fldName);
}
testDef.setTestsession(sess);
}
}
protected void readConstraints(TypeDefinition tdef, WorkItem wk)
{
List<Item> constrItems = wk.getField("fieldRelationships").getList();
if(constrItems.size() == 0)
return;
ConstraintsDefinition constraints = getFactory().createConstraintsDefinition();
tdef.setConstraints(constraints);
// Each item is a separate constraint.
for(Item item : constrItems)
{
String model = item.getModelType();
ConstraintType constrType = getConstraintType(model);
String srcField = item.getId();
// List of the target fields constraining this source field.
// The ID of each item in targetFields field is the constrained field.
List<Item> targetItems = getConstraintTargetFields(item, constrType);
for(Item targetItem : targetItems)
{
ConstraintDefinition constDef = getFactory().createConstraintDefinition();
constDef.setType(constrType);
boolean mandatory = false;
String targetName = "";
List<String> targetValues = null;
if("Rule".equals(model) || "ConstraintRule".equals(model))
{
mandatory = item.getField("mandatory").getBoolean();
targetName = item.getField("targetField").getItem().getId();
String rule = item.getField("rule").getValueAsString();
constDef.setRule(rule);
targetValues = getConstraintValueList(item, "targetValues");
}
else // Basic or field relationship.
{
mandatory = targetItem.getField("mandatory").getBoolean();
targetName = targetItem.getId();
List<String> sourceValues = getConstraintValueList(targetItem, "sourceValues");
ConstraintDefinition.Source constrSource = getFactory().createConstraintDefinitionSource();
constrSource.setName(srcField);
constrSource.getValue().addAll(sourceValues);
constDef.setSource(constrSource);
targetValues = getConstraintValueList(targetItem, "targetValues");
}
ConstraintTargetDefinition constrTarget = getFactory().createConstraintTargetDefinition();
constDef.setTarget(constrTarget);
constrTarget.setMandatory(mandatory);
constrTarget.setName(targetName);
if(targetValues != null)
constrTarget.getValue().addAll(targetValues);
constraints.getConstraint().add(constDef);
}
}
}
private List<Item> getConstraintTargetFields(Item item, ConstraintType constrType)
{
List<Item> ret = new ArrayList<Item>();
if(constrType==ConstraintType.RULE || constrType==ConstraintType.IBPL)
{
Item tgt = item.getField("targetField").getItem();
ret.add(tgt);
}
if(constrType==ConstraintType.BASIC || constrType==ConstraintType.FIELD_RELATIONSHIP)
{
List<Item> tgt = item.getField("targetFields").getList();
ret.addAll(tgt);
}
return ret;
}
private ConstraintType getConstraintType(String ctype)
{
if("Rule".equals(ctype)) return ConstraintType.IBPL;
if("ConstraintRule".equals(ctype)) return ConstraintType.RULE;
return ConstraintType.FIELD_RELATIONSHIP;
}
// Some BASIC constraints have the targetValue(s) field set to null and the only
// indication of the target value in the cliSpec field - this is used for dynamic
// values associated with the Assigned User field, etc: hasPermissions.
// The only way we can access this is parsing the cliSpec for the stuff after the
// last equals.
protected List<String> getConstraintValueList(Item item, String fname)
{
List<String> ret = new ArrayList<String>();
try
{
if(item.getField(fname) == null || item.getField(fname).getList() == null) // Fall back to the cliSpec
{
String cli = item.getField("cliSpec").getValueAsString();
if(cli != null && cli.lastIndexOf("=") != -1)
{
int idx = cli.lastIndexOf("=");
String val = cli.substring(idx+1, cli.length()-1);
ret.add(val);
}
}
else
{
Field fld = item.getField(fname);
List itemList = fld.getList();
// ret.addAll(fld.getAll()); fails when the target fields are users.
for(Object it : itemList)
{
String val = it.toString();
ret.add(val);
}
}
}
catch(NoSuchElementException e)
{
// Non-fatal error. Just return the empty list.
}
return ret;
}
////////////////////////////////////////////////////////////////////////////
// TODO: we can do all these three in one call.
protected String getOverride(String typeName, String fieldName, String override) throws Exception
{
Command cmd = new Command(Command.IM, "viewfield");
cmd.addOption(new Option("overrideForType", typeName));
cmd.addSelection(fieldName);
Response res = getApi().execute(cmd);
try
{
return res.getWorkItem(fieldName).getField(override + "Rule").getValueAsString();
}catch(Exception e)
{
return "";
}
}
protected String getDescriptionOverride(String typeName, String fieldName) throws Exception
{
Command cmd = new Command(Command.IM, "viewfield");
cmd.addOption(new Option("overrideForType", typeName));
cmd.addSelection(fieldName);
Response res = getApi().execute(cmd);
try
{
return res.getWorkItem(fieldName).getField("description").getValueAsString();
}catch(Exception e)
{
return "";
}
}
// If we can't find a valid default we just assume it doesn't exist and return nothing.
protected String getDefaultOverride(String typeName, String fieldName) throws Exception
{
Command cmd = new Command(Command.IM, "viewfield");
cmd.addOption(new Option("overrideForType", typeName));
cmd.addSelection(fieldName);
Response res = getApi().execute(cmd);
try
{
return res.getWorkItem(fieldName).getField("default").getValueAsString();
}catch(Exception e)
{
return "";
}
}
// Mandatory fields are reported a little oddly. They are a list from the top workitem
// rather than sub-items of the state.
protected void readMandatoryFieldsForState(StateReference stateRef, WorkItem wk, String state)
{
ItemList mandFields = (ItemList)wk.getField("mandatoryFields").getList();
if (mandFields != null && mandFields.contains(state))
{
ItemList theFields = (ItemList)mandFields.getItem(state).getField("fields").getList();
if (theFields != null)
{
MandatoryFields mf = getFactory().createMandatoryFields();
stateRef.setMandatory(mf);
Iterator<Item> theItems = theFields.getItems();
while (theItems.hasNext())
{
Item item = theItems.next();
MandatoryFieldReference mrf = getFactory().createMandatoryFieldReference();
mrf.setName(item.getId());
mf.getField().add(mrf);
}
}
}
}
protected void readTransitionsForState(StateReference stateRef, Item item, WorkItem wk, String state)
{
Field transitions = item.getField("targetStates");
ItemList targetList = (ItemList)transitions.getList();
Iterator targetIt = targetList.getItems();
while(targetIt.hasNext())
{
Item target = (Item)targetIt.next();
String targetState = target.getId();
log(" Read target state field: " + targetState);
NextState next = getFactory().createNextState();
stateRef.getNext().add(next);
next.setName(targetState);
// Get the permitted groups.
StringBuffer groupString = new StringBuffer();
Field groups = target.getField("permittedGroups");
ItemList groupList = (ItemList)groups.getList();
Iterator groupIt = groupList.getItems();
while(groupIt.hasNext())
{
Item group = (Item)groupIt.next();
String groupName = group.getId();
log(" Read permitted group: " + groupName);
groupString.append(groupName + ",");
}
if (groupString.charAt(groupString.length()-1) == ',')
groupString.deleteCharAt(groupString.length()-1); // snip the last comma.
next.setGroup(groupString.toString());
}
}
}