/**
*
*/
package hudson.plugins.starteam;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.starbase.starteam.Label;
import com.starbase.starteam.PromotionState;
import com.starbase.starteam.View;
import com.starbase.starteam.ViewConfiguration;
import com.starbase.util.OLEDate;
/**
*
* Contents of a View can be adjusted by selecting versions other then the tip.
*
* @author Jan Ruzicka
*
*/
public class StarTeamViewSelector implements Serializable {
private static final long serialVersionUID = 1L;
private final static Pattern labelPattern = Pattern.compile("%\\{(.*?):BUILD_NUMBER\\}");
/**
* Current: view brings the most recent or "tip" versions of items,
* Label: view brings items with the specified label attached,
* Time: view brings items designated by time,
* Promotion: view brings items designated by a promotion state, similar to label-based view.
*/
enum ConfigType {
CURRENT, LABEL, TIME, PROMOTION
};
private final String configInfo; // configuration information Label name, Promotion State name or date
private final ConfigType configType; // type of configuration.
private final DateFormat df = new SimpleDateFormat("yyyy/M/d HH:mm:ss");
/**
* Default constructor
*
* @param configType
* Current: view brings the most recent or "tip" versions of items,
* Label: view brings items with the specified label attached,
* Time: view brings items designated by time,
* Promotion: view brings items designated by a promotion state, similar to label-based view.
* @param configInfo
* Information according to configuration type. Label name, Promotion State name or date
*
* @throws ParseException
*/
public StarTeamViewSelector(String configInfo, String configType) throws ParseException {
this.configInfo = configInfo;
ConfigType result = ConfigType.CURRENT;
if (configType != null) {
try{
result = ConfigType.valueOf(configType.toUpperCase());
} catch ( IllegalArgumentException ignored) {
// ignored exception - by default the type will go to CURRENT
}
}
this.configType = result;
if (this.configType == ConfigType.TIME) {
df.parse(configInfo);
}
}
public StarTeamViewSelector(Date time) {
if (time != null) {
this.configType = ConfigType.TIME;
this.configInfo = df.format(time);
} else {
this.configType = ConfigType.CURRENT;
this.configInfo = null;
}
}
public View configView(View baseView, int buildNumber) throws StarTeamSCMException, ParseException{
final ViewConfiguration configuration;
if (configInfo != null && !configInfo.isEmpty()) {
switch (configType) {
case CURRENT:
configuration = ViewConfiguration.createTip();
break;
case LABEL:
int labelId;
// check if label is a pattern
String labelName = expandLabelPattern(configInfo, buildNumber);
if (!configInfo.equals(labelName)) {
// -1 is the buildNumber during a poll event. Use tip when polling,
// create label otherwise.
if (buildNumber == -1) {
configuration = ViewConfiguration.createTip();
break;
}
labelId = createLabelInView(baseView, labelName, buildNumber);
} else {
labelId = findLabelInView(baseView, labelName);
}
configuration = ViewConfiguration.createFromLabel(labelId);
break;
case PROMOTION:
// note: If the promotion state is assigned to <<current>> then the resulting ID will be NULL and
// we will revert to a view based on the current tip.
Integer promotionStateId = findPromotionStateInView(baseView, configInfo);
if (promotionStateId != null) {
configuration = ViewConfiguration.createFromPromotionState(promotionStateId);
} else {
configuration = ViewConfiguration.createTip();
}
break;
case TIME:
Date effectiveDate = df.parse(configInfo);
configuration = ViewConfiguration.createFromTime(new OLEDate(effectiveDate));
break;
default:
throw new StarTeamSCMException("Could not construct view - no configuration provided");
}
} else {
configuration = ViewConfiguration.createTip();
}
return new View(baseView, configuration);
}
public static String expandLabelPattern(final String labelformat, final int buildNumber) {
Matcher m = labelPattern.matcher(labelformat);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String fmt = "%" + m.group(1);
m.appendReplacement(sb, String.format(fmt, buildNumber));
}
m.appendTail(sb);
return sb.toString();
}
private static int findLabelInView(final View view, final String labelname) throws StarTeamSCMException {
for (Label label : view.getLabels()) {
if (labelname.equals(label.getName())) {
return label.getID();
}
}
throw new StarTeamSCMException("Couldn't find label [" + labelname + "] in view " + view.getName());
}
private static int createLabelInView(final View view, final String labelName, final int buildNumber) throws StarTeamSCMException {
final String labelDesc = String.format("Jenkins build %d", buildNumber);
final boolean buildLabel = true;
final boolean frozen = true;
Label label = view.createViewLabel(labelName, labelDesc, OLEDate.CURRENT_SERVER_TIME, buildLabel, frozen);
return label.getID();
}
private static Integer findPromotionStateInView(final View view, final String promotionState) throws StarTeamSCMException {
for (PromotionState ps : view.getPromotionModel().getPromotionStates()) {
if (promotionState.equals(ps.getName())) {
if (ps.getLabelID() == -1) {
// PROMOTION STATE is set to <<current>>
return null;
}
return ps.getObjectID();
}
}
throw new StarTeamSCMException("Couldn't find promotion state " + promotionState + " in view " + view.getName());
}
public String getConfigInfo() {
return configInfo;
}
public String getConfigType() {
return configType.name();
}
}