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}