package hudson.plugins.performance;
import hudson.model.AbstractProject;
import hudson.model.ModelObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* Configures the trend graph of this plug-in.
*/
public class GraphConfigurationDetail implements ModelObject {
/** Logger. */
private static final Logger LOGGER = Logger.getLogger(GraphConfigurationDetail.class.getName());
public static final String SEPARATOR = ";";
/** The number of builds to consider. */
private int buildCount;
/** The first days to consider. */
private String firstDayCount;
/** The last days to consider. */
private String lastDayCount;
/** The type of config to use. */
private String configType;
public static final int DEFAULT_COUNT = 0;
public static final String DEFAULT_DATE = "dd/MM/yyyy";
public static final String NONE_CONFIG = "NONE";
public static final String BUILD_CONFIG = "BUILD";
public static final String DATE_CONFIG = "DATE";
static DateFormat format = new SimpleDateFormat(DEFAULT_DATE);
public GraphConfigurationDetail(final AbstractProject<?, ?> project, final String pluginName,
final StaplerRequest request) {
String value = createCookieHandler(pluginName).getValue(request.getCookies());
List<Integer> initializationListResult = initializeFrom(value);
if (!initializationListResult.isEmpty()) {
File defaultsFile = createDefaultsFile(project, pluginName);
if (defaultsFile.exists()) {
String defaultValue = readFromDefaultsFile(defaultsFile);
initializationListResult = initializeFrom(defaultValue);
if (!initializationListResult.isEmpty()) {
reset(initializationListResult);
}
} else {
reset(initializationListResult);
}
}
}
/**
* Saves the configured values. Subclasses need to implement the actual
* persistence.
*
* @param request
* Stapler request
* @param response
* Stapler response
*/
public void doSave(final StaplerRequest request, final StaplerResponse response) {
try {
JSONObject formData = request.getSubmittedForm();
String buildCountString = formData.getString("buildCountString");
int buildCount = 0;
if (StringUtils.isNotBlank(buildCountString)) {
buildCount = formData.getInt("buildCountString");
}
String firstDayCountString = formData.getString("firstDayCountString");
String firstDayCount = DEFAULT_DATE;
if (StringUtils.isNotBlank(firstDayCountString)) {
firstDayCount = formData.getString("firstDayCountString");
}
String lastDayCountString = formData.getString("lastDayCountString");
String lastDayCount = DEFAULT_DATE;
if (StringUtils.isNotBlank(lastDayCountString)) {
lastDayCount = formData.getString("lastDayCountString");
}
String radioConfigType = formData.getString("radioConfigType");
String configType = NONE_CONFIG;
if (StringUtils.isNotBlank(radioConfigType)) {
configType = formData.getString("radioConfigType");
}
String value = serializeToString(configType, buildCount, firstDayCount, lastDayCount);
persistValue(value, request, response);
} catch (JSONException exception) {
LOGGER.log(Level.SEVERE, "Can't parse the form data: " + request, exception);
} catch (IllegalArgumentException exception) {
LOGGER.log(Level.SEVERE, "Can't parse the form data: " + request, exception);
} catch (ServletException exception) {
LOGGER.log(Level.SEVERE, "Can't process the form data: " + request, exception);
} finally {
try {
response.sendRedirect("../");
} catch (IOException exception) {
LOGGER.log(Level.SEVERE, "Can't redirect", exception);
}
}
}
public String getDisplayName() {
return Messages.GraphConfigurationDetail_DisplayName();
}
/**
* Creates a new cookie handler to convert the cookie to a string value.
*
* @param cookieName
* the suffix of the cookie name that is used to persist the
* configuration per user
* @return the new cookie handler
*/
private static CookieHandler createCookieHandler(final String cookieName) {
return new CookieHandler(cookieName);
}
protected void persistValue(final String value, final StaplerRequest request, final StaplerResponse response) {
Cookie cookie = createCookieHandler("performance").create(request.getAncestors(), value);
response.addCookie(cookie);
}
protected String serializeToString(final String configType, final int buildCount, final String firstDayCount,
final String lastDayCount) {
return configType + SEPARATOR + buildCount + SEPARATOR + firstDayCount + SEPARATOR + lastDayCount;
}
/**
* Creates a file with for the default values.
*
* @param project
* the project used as directory for the file
* @param pluginName
* the name of the plug-in
* @return the created file
*/
protected static File createDefaultsFile(final AbstractProject<?, ?> project, final String pluginName) {
return new File(project.getRootDir(), pluginName + ".txt");
}
/**
* Parses the provided string and initializes the members. If the string is
* not in the expected format, a list containing -1, 1, 2 and/or 3 is
* returned. -1 is a global error, 1 is a dayCount error, 2 is a first date
* error, 3 is a last date error. Return an empty list if all is good.
*
* @param value
* the initialization value stored in the format
* <code>configType;buildCount;firstDayCount;lastDayCount</code>
* @return an empty list is the initialization was successful, a list
* containing -1, 1, 2 or 3 otherwise
*/
private List<Integer> initializeFrom(final String value) {
List<Integer> listErrors = new ArrayList<Integer>(0);
if (StringUtils.isBlank(value)) {
listErrors.add(-1);
return listErrors;
}
String[] values = StringUtils.split(value, SEPARATOR);
if (values.length != 4) {
listErrors.add(-1);
return listErrors;
}
configType = values[0];
if (BUILD_CONFIG.compareToIgnoreCase(configType) != 0 && DATE_CONFIG.compareToIgnoreCase(configType) != 0
&& NONE_CONFIG.compareToIgnoreCase(configType) != 0) {
listErrors.add(-1);
}
try {
buildCount = Integer.parseInt(values[1]);
} catch (JSONException e) {
listErrors.add(1);
e.printStackTrace();
}
firstDayCount = values[2];
lastDayCount = values[3];
GregorianCalendar firstDate = null;
GregorianCalendar lastDate = null;
if (firstDayCount.compareTo(DEFAULT_DATE) == 0 && DATE_CONFIG.compareToIgnoreCase(configType) == 0) {
listErrors.add(2);
}
if (lastDayCount.compareTo(DEFAULT_DATE) == 0 && DATE_CONFIG.compareToIgnoreCase(configType) == 0) {
listErrors.add(3);
}
if (firstDayCount.compareTo(DEFAULT_DATE) != 0) {
try {
firstDate = getGregorianCalendarFromString(firstDayCount);
} catch (IllegalArgumentException e) {
listErrors.add(2);
e.printStackTrace();
} catch (ParseException e) {
listErrors.add(2);
e.printStackTrace();
}
}
if (lastDayCount.compareTo(DEFAULT_DATE) != 0) {
try {
lastDate = getGregorianCalendarFromString(lastDayCount);
} catch (IllegalArgumentException e) {
listErrors.add(3);
e.printStackTrace();
} catch (ParseException e) {
listErrors.add(3);
e.printStackTrace();
}
}
if (firstDate != null && lastDate != null && firstDate.after(lastDate)) {
listErrors.add(2);
listErrors.add(3);
}
// clean the error list
if (!listErrors.isEmpty()) {
Collections.sort(listErrors);
if (listErrors.get(0) == -1) {
listErrors = new ArrayList<Integer>(1);
listErrors.add(-1);
} else {
int actualErrorType = 0;
List<Integer> realListErrors = new ArrayList<Integer>(0);
for (Integer typeError : listErrors) {
if (actualErrorType != typeError) {
actualErrorType = typeError;
realListErrors.add(typeError);
}
}
listErrors = realListErrors;
}
}
return listErrors;
}
/**
* <p>
* Get a gregorian calendar from a String of type : DD/MM/YYYY
* </p>
*
* @param dateString
* @return GregorianCalendar
* @throws ParseException
*/
public static GregorianCalendar getGregorianCalendarFromString(String dateString) throws ParseException {
Date date = format.parse(dateString);
GregorianCalendar outCalendar = new GregorianCalendar();
outCalendar.setTime(date);
return outCalendar;
}
/**
* Resets the graph configuration to the default values.
*/
private void reset(List<Integer> initializationResult) {
configType = NONE_CONFIG;
for (Integer errorNumber : initializationResult) {
if (errorNumber == -1) {
buildCount = DEFAULT_COUNT;
firstDayCount = DEFAULT_DATE;
lastDayCount = DEFAULT_DATE;
} else if (errorNumber == 1) {
buildCount = DEFAULT_COUNT;
} else if (errorNumber == 2) {
firstDayCount = DEFAULT_DATE;
} else if (errorNumber == 3) {
lastDayCount = DEFAULT_DATE;
}
}
}
/**
* Reads the default values from file.
*
* @param defaultsFile
* the file with the default values
* @return the default values from file.
*/
private String readFromDefaultsFile(final File defaultsFile) {
String defaultValue = StringUtils.EMPTY;
FileInputStream input = null;
try {
input = new FileInputStream(defaultsFile);
defaultValue = IOUtils.toString(input);
} catch (IOException exception) {
// ignore
} finally {
IOUtils.closeQuietly(input);
}
return defaultValue;
}
public int getBuildCount() {
return buildCount;
}
public void setBuildCount(int buildCount) {
this.buildCount = buildCount;
}
public String getFirstDayCount() {
return firstDayCount;
}
public void setFirstDayCount(String firstDayCount) {
this.firstDayCount = firstDayCount;
}
public String getLastDayCount() {
return lastDayCount;
}
public void setLastDayCount(String lastDayCount) {
this.lastDayCount = lastDayCount;
}
public String getConfigType() {
return configType;
}
public void setConfigType(String configType) {
this.configType = configType;
}
}