/*
* Copyright 2016 ThoughtWorks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thoughtworks.go.serverhealth;
import com.thoughtworks.go.config.CruiseConfig;
import com.thoughtworks.go.util.Clock;
import com.thoughtworks.go.util.SystemTimeClock;
import com.thoughtworks.go.utils.Timeout;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.joda.time.DateTime;
import java.text.SimpleDateFormat;
import java.util.*;
import static com.thoughtworks.go.util.ExceptionUtils.bombIfNull;
import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
public class ServerHealthState {
private final HealthStateLevel healthStateLevel;
private final HealthStateType type;
private final String message;
private final String description;
static Clock clock = new SystemTimeClock();
private DateTime expiryTime;
public static final SimpleDateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("MMM-dd HH:mm:ss");
private Date timestamp;
private ServerHealthState(HealthStateLevel healthStateLevel, HealthStateType type) {
this(healthStateLevel, type, "", "");
}
private ServerHealthState(HealthStateLevel healthStateLevel, HealthStateType type, String message, String description) {
this(healthStateLevel, type, message, description, Timeout.NEVER);
}
private ServerHealthState(HealthStateLevel healthStateLevel, HealthStateType type, String message, String description, Timeout timeout) {
bombIfNull(description, "description cannot be null");
bombIfNull(message, "message cannot be null");
this.healthStateLevel = healthStateLevel;
this.type = type;
this.message = message;
this.description = description;
setTimeout(timeout);
this.timestamp = new Date();
}
private ServerHealthState(HealthStateLevel healthStateLevel, HealthStateType healthStateType, String message, String description, long milliSeconds) {
bombIfNull(description, "description cannot be null");
bombIfNull(message, "message cannot be null");
this.healthStateLevel = healthStateLevel;
this.type = healthStateType;
this.message = message;
this.description = description;
setTimeout(milliSeconds);
this.timestamp = new Date();
}
private void setTimeout(long milliSeconds) {
this.expiryTime = milliSeconds == Timeout.NEVER.inMillis() ? null : clock.timeoutTime(milliSeconds);
}
public void setTimeout(Timeout timeout) {
this.expiryTime = timeout == Timeout.NEVER ? null : clock.timeoutTime(timeout);
}
public static ServerHealthState success(HealthStateType type) {
return new ServerHealthState(HealthStateLevel.OK, type);
}
public static ServerHealthState warning(String message, String description, HealthStateType healthStateType) {
return new ServerHealthState(HealthStateLevel.WARNING, healthStateType, escapeHtml(message), escapeHtml(description));
}
public static ServerHealthState error(String message, String description, HealthStateType type) {
return new ServerHealthState(HealthStateLevel.ERROR, type, escapeHtml(message), escapeHtml(description));
}
public static ServerHealthState warning(String message, String description, HealthStateType healthStateType, Timeout timeout) {
return new ServerHealthState(HealthStateLevel.WARNING, healthStateType, message, description, timeout);
}
public static ServerHealthState warning(String message, String description, HealthStateType healthStateType, long milliSeconds) {
return new ServerHealthState(HealthStateLevel.WARNING, healthStateType, escapeHtml(message), escapeHtml(description), milliSeconds);
}
public static ServerHealthState warningWithHtml(String message, String description, HealthStateType stateType) {
return new ServerHealthState(HealthStateLevel.WARNING, stateType, message, description);
}
public static ServerHealthState warningWithHtml(String message, String description, HealthStateType stateType, long milliSeconds) {
return new ServerHealthState(HealthStateLevel.WARNING, stateType, message, description, milliSeconds);
}
public static ServerHealthState failToScheduling(HealthStateType healthStateType, String pipelineName, String description) {
String message = String.format("Failed to trigger pipeline [%s]", pipelineName);
return new ServerHealthState(HealthStateLevel.ERROR, healthStateType, message, description);
}
public static ServerHealthState failedToScheduleStage(HealthStateType healthStateType, String pipelineName, String stageName, String description) {
String message = String.format("Failed to trigger stage [%s] pipeline [%s]", stageName, pipelineName);
return new ServerHealthState(HealthStateLevel.ERROR, healthStateType, message, description, Timeout.TWO_MINUTES);
}
public HealthStateType getType() {
return type;
}
boolean isWarning() {
return this.healthStateLevel.equals(HealthStateLevel.WARNING);
}
public boolean isRealSuccess() {
return this.healthStateLevel.equals(HealthStateLevel.OK);
}
public boolean isSuccess() {
return isRealSuccess() || isWarning();
}
public ServerHealthState trump(ServerHealthState otherServerHealthState) {
int result = healthStateLevel.compareTo(otherServerHealthState.healthStateLevel);
return result > 0 ? this : otherServerHealthState;
}
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (this.getClass() != that.getClass()) {
return false;
}
return equals((ServerHealthState) that);
}
private boolean equals(ServerHealthState that) {
if (!this.healthStateLevel.equals(that.healthStateLevel)) {
return false;
}
if (!this.type.equals(that.type)) {
return false;
}
if (!this.description.equals(that.description)) {
return false;
}
if (!this.message.equals(that.message)) {
return false;
}
return true;
}
public int hashCode() {
int result = healthStateLevel.hashCode();
result = 31 * result + type.hashCode();
result = 31 * result + message.hashCode();
result = 31 * result + description.hashCode();
return result;
}
public Map<String, String> asJson() {
Map<String, String> json = new LinkedHashMap<>();
json.put("message", getMessage());
json.put("detail", getDescription());
json.put("level", healthStateLevel.toString());
return json;
}
public HealthStateLevel getLogLevel() {
return healthStateLevel;
}
public String getMessage() {
return message;
}
public int getHttpCode() {
return getType().getHttpCode();
}
public String getDescription() {
return description;
}
public Date getTimestamp() {
return timestamp;
}
public String getMessageWithTimestamp() {
return getMessage() + " [" + TIMESTAMP_FORMAT.format(timestamp) + "]";
}
@Override public String toString() {
return ToStringBuilder.reflectionToString(this);
}
public boolean hasExpired() {
return expiryTime != null && expiryTime.isBefore(clock.currentDateTime());
}
public Set<String> getPipelineNames(CruiseConfig config) {
return type.getPipelineNames(config);
}
}