001/*-----------------------------------------------------------------------+
002 | com.teamscale.index
003 |                                                                       |
004   $Id$            
005 |                                                                       |
006 | Copyright (c)  2009-2013 CQSE GmbH                                 |
007 +-----------------------------------------------------------------------*/
008package org.conqat.engine.service.shared.data;
009
010import java.io.Serializable;
011import java.util.Objects;
012
013import javax.annotation.Nullable;
014
015import org.conqat.lib.commons.js_export.ExportToJavaScript;
016import org.conqat.lib.commons.string.StringUtils;
017
018import com.fasterxml.jackson.annotation.JsonCreator;
019import com.fasterxml.jackson.annotation.JsonProperty;
020import com.teamscale.commons.lang.ToStringHelpers;
021
022/**
023 * Information about a blacklisted finding.
024 *
025 * <strong>This class is used for communication with IDE clients (via the @link
026 * {@link org.conqat.engine.service.shared.client.IdeServiceClient}, special
027 * care has to be taken when changing its signature!</strong>
028 */
029@ExportToJavaScript
030public class FindingBlacklistInfo implements Serializable {
031
032        /** Serial version UID. */
033        private static final long serialVersionUID = 1;
034
035        /** The name of the JSON property name for {@link #findingId}. */
036        private static final String FINDING_ID_PROPERTY = "findingId";
037
038        /** The name of the JSON property name for {@link #timestamp}. */
039        private static final String TIMESTAMP_PROPERTY = "timestamp";
040
041        /** The name of the JSON property name for {@link #user}. */
042        private static final String USER_PROPERTY = "user";
043
044        /** The name of the JSON property name for {@link #rationale}. */
045        private static final String RATIONALE_PROPERTY = "rationale";
046
047        /** The name of the JSON property name for {@link #type}. */
048        private static final String TYPE_PROPERTY = "type";
049
050        /** The ID of the blacklisted finding */
051        @JsonProperty(FINDING_ID_PROPERTY)
052        private final String findingId;
053
054        /** The time when the finding was blacklisted */
055        @JsonProperty(TIMESTAMP_PROPERTY)
056        private final long timestamp;
057
058        /** The name of the user who blacklisted the finding */
059        @JsonProperty(USER_PROPERTY)
060        private final String user;
061
062        /** A rationale why the finding was blacklisted */
063        @JsonProperty(RATIONALE_PROPERTY)
064        private final String rationale;
065
066        @JsonProperty(TYPE_PROPERTY)
067        @Nullable
068        private final EFindingBlacklistType type;
069
070        /** Copy constructor. */
071        public FindingBlacklistInfo(FindingBlacklistInfo info) {
072                this.findingId = info.findingId;
073                this.timestamp = info.timestamp;
074                this.user = info.user;
075                this.rationale = info.rationale;
076                this.type = info.type;
077        }
078
079        /** Constructor. */
080        @JsonCreator
081        public FindingBlacklistInfo(@JsonProperty(FINDING_ID_PROPERTY) String findingId,
082                        @JsonProperty(TIMESTAMP_PROPERTY) long timestamp, @JsonProperty(USER_PROPERTY) String user,
083                        @JsonProperty(RATIONALE_PROPERTY) String rationale,
084                        @JsonProperty(TYPE_PROPERTY) EFindingBlacklistType type) {
085                this.findingId = findingId;
086                this.timestamp = timestamp;
087                this.user = user;
088                this.rationale = rationale;
089                this.type = type;
090        }
091
092        /** Clones this FindingBlacklistInfo but uses the given findingId. */
093        public FindingBlacklistInfo cloneWithNewFindingId(String findingId) {
094                return new FindingBlacklistInfo(findingId, timestamp, user, rationale, type);
095        }
096
097        /** Clones this FindingBlacklistInfo but uses the given findingId. */
098        public FindingBlacklistInfo cloneWithNewType(EFindingBlacklistType newType) {
099                return new FindingBlacklistInfo(findingId, timestamp, user, rationale, newType);
100        }
101
102        /**
103         * Ensures that the type of blacklisting is set. If it is null it is tried to
104         * heuristically derive the type from the rationale. The default is
105         * {@link EFindingBlacklistType#TOLERATION}.
106         */
107        public static FindingBlacklistInfo ensureBlacklistTypeSet(FindingBlacklistInfo blacklistInfo) {
108                if (blacklistInfo.getType() != null) {
109                        return blacklistInfo;
110                }
111                String rationale = blacklistInfo.getRationale();
112                if (!StringUtils.isEmpty(rationale) && rationale.toLowerCase().contains("false")
113                                && rationale.toLowerCase().contains("positive")) {
114                        return blacklistInfo.cloneWithNewType(EFindingBlacklistType.FALSE_POSITIVE);
115                }
116                return blacklistInfo.cloneWithNewType(EFindingBlacklistType.TOLERATION);
117        }
118
119        /** Returns the finding id. */
120        public String getFindingId() {
121                return findingId;
122        }
123
124        /** Returns the timestamp. */
125        public long getTimestamp() {
126                return timestamp;
127        }
128
129        /** Returns the user who blacklisted the finding. */
130        public String getUser() {
131                return user;
132        }
133
134        /** Returns the rationale. */
135        public String getRationale() {
136                return rationale;
137        }
138
139        /**
140         * Returns the blacklist type. This can be <code>null</code> for backwards
141         * compatibility
142         */
143        public EFindingBlacklistType getType() {
144                return type;
145        }
146
147        @Override
148        public final boolean equals(Object obj) {
149                if (obj instanceof FindingBlacklistInfo) {
150                        FindingBlacklistInfo other = (FindingBlacklistInfo) obj;
151                        return Objects.equals(findingId, other.findingId) && Objects.equals(rationale, other.rationale)
152                                        && timestamp == other.timestamp && Objects.equals(user, other.user)
153                                        && Objects.equals(type, other.type);
154                }
155                return false;
156        }
157
158        @Override
159        public final int hashCode() {
160                return Objects.hash(findingId, rationale, timestamp, user, type);
161        }
162
163        @Override
164        public String toString() {
165                return ToStringHelpers.toReflectiveStringHelper(this).toString();
166        }
167}