001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 the ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package org.conqat.engine.index.shared; 018 019import java.util.Comparator; 020 021import org.conqat.engine.commons.findings.DetachedFinding; 022import org.conqat.engine.commons.findings.location.ElementLocation; 023import org.conqat.lib.commons.js_export.ExportToJavaScript; 024 025import com.fasterxml.jackson.annotation.JsonCreator; 026import com.fasterxml.jackson.annotation.JsonProperty; 027 028/** 029 * A {@link DetachedFinding} with additional attributes required for index-based 030 * analysis. 031 */ 032@ExportToJavaScript 033public class IndexFinding extends DetachedFinding { 034 035 /** Version for serialization. */ 036 private static final long serialVersionUID = 1; 037 038 /** A comparator for stable sorting of {@link IndexFinding}s. */ 039 public static final Comparator<IndexFinding> STABLE_INDEX_FINDING_COMPARATOR = Comparator 040 .comparing(IndexFinding::getLocationString).thenComparing(IndexFinding::getTypeId) 041 .thenComparing(IndexFinding::getMessage); 042 043 /** 044 * Value for {@link #analysisTimestamp} that indicates that there is no 045 * timestamp available. 046 */ 047 public static final long NO_TIMESTAMP = -1; 048 049 /** The separator for components of a finding type ID. */ 050 public static final String TYPE_ID_SEPARATOR = "/"; 051 052 /** 053 * The timestamp of the analysis creating this finding. This may be 054 * {@link #NO_TIMESTAMP} to indicate that this is updated in real-time. 055 */ 056 @JsonProperty("analysisTimestamp") 057 private long analysisTimestamp = NO_TIMESTAMP; 058 059 /** A unique ID for the type of finding. */ 060 @JsonProperty("typeId") 061 private final String typeId; 062 063 /** Constructor. */ 064 public IndexFinding(DetachedFinding finding, long analysisTimestamp) { 065 super(finding); 066 this.analysisTimestamp = analysisTimestamp; 067 this.typeId = determineTypeId(); 068 } 069 070 public IndexFinding(DetachedFinding finding, long analysisTimestamp, String typeId) { 071 super(finding); 072 this.analysisTimestamp = analysisTimestamp; 073 this.typeId = typeId; 074 } 075 076 /** 077 * Creates a {@link IndexFinding} from a {@link DetachedFinding}. 078 */ 079 public static IndexFinding asRealtimeFinding(DetachedFinding finding) { 080 return new IndexFinding(finding, NO_TIMESTAMP); 081 } 082 083 @JsonCreator 084 public IndexFinding(@JsonProperty(GROUP_NAME_PROPERTY) String groupName, 085 @JsonProperty(CATEGORY_NAME_PROPERTY) String categoryName, @JsonProperty(MESSAGE_PROPERTY) String message, 086 @JsonProperty(LOCATION_PROPERTY) ElementLocation location) { 087 super(groupName, categoryName, message, location); 088 this.typeId = determineTypeId(); 089 } 090 091 /** Returns the type ID to be used during construction. */ 092 private String determineTypeId() { 093 return makeFindingTypeId(getCategoryName(), getGroupName()); 094 } 095 096 /** Creates a finding type ID for given category and group. */ 097 public static String makeFindingTypeId(String category, String group) { 098 return category + TYPE_ID_SEPARATOR + group; 099 } 100 101 /** Copy constructor. */ 102 public IndexFinding(IndexFinding other) { 103 super(other); 104 this.analysisTimestamp = other.analysisTimestamp; 105 this.typeId = other.typeId; 106 } 107 108 /** 109 * Returns the analysis timestamp. This may be {@link #NO_TIMESTAMP} to indicate 110 * that no analysis timestamp is available. 111 */ 112 public long getAnalysisTimestamp() { 113 return analysisTimestamp; 114 } 115 116 /** Sets the analysis timestamp. */ 117 public void setAnalysisTimestamp(long timestamp) { 118 this.analysisTimestamp = timestamp; 119 } 120 121 /** Returns the type id of this finding. */ 122 public String getTypeId() { 123 return typeId; 124 } 125 126 /** 127 * Checks whether the finding is updated in real-time. 128 * 129 * @return <code>true</code> if the finding is updated in real-time, 130 * <code>false</code> if it is updated in 'nightly' analyses. 131 */ 132 public boolean isRealTime() { 133 return analysisTimestamp == NO_TIMESTAMP; 134 } 135}