xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/search/context/FormattedLines.java (revision 5d9f3aa0ca3da3a714233f987fa732f62c0965f6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2018, Chris Fraire <cfraire@me.com>.
22  */
23 package org.opengrok.indexer.search.context;
24 
25 import java.util.Map;
26 import java.util.NoSuchElementException;
27 import java.util.SortedMap;
28 import java.util.TreeMap;
29 import org.apache.lucene.search.uhighlight.UnifiedHighlighter;
30 
31 /**
32  * Represents structured results from {@link ContextFormatter} that can be
33  * merged with other instances.
34  * <p>
35  * {@link UnifiedHighlighter} returns results separated by field, and
36  * {@link OGKUnifiedHighlighter} merges them together to return a coherent
37  * result for presentation.
38  */
39 public class FormattedLines {
40     private final SortedMap<Integer, String> lines = new TreeMap<>();
41     private String footer;
42     private boolean limited;
43 
44     /*
45      * Gets a count of the number of lines in the instance.
46      */
getCount()47     public int getCount() {
48         return lines.size();
49     }
50 
51     /**
52      * @return the footer
53      */
getFooter()54     public String getFooter() {
55         return footer;
56     }
57 
setFooter(String value)58     public void setFooter(String value) {
59         footer = value;
60     }
61 
62     /*
63      * Gets a value indicating if lines were limited.
64      */
isLimited()65     public boolean isLimited() {
66         return limited;
67     }
68 
69     /*
70      * Sets a value indicating if lines were limited.
71      */
setLimited(boolean value)72     public void setLimited(boolean value) {
73         limited = value;
74     }
75 
76     /**
77      * Removes the highest line from the instance.
78      * @return a defined value
79      * @throws NoSuchElementException if the instance is empty
80      */
pop()81     public String pop() {
82         return lines.remove(lines.lastKey());
83     }
84 
85     /**
86      * Sets the specified String line for the specified line number, replacing
87      * any previous entry for the same line number.
88      * @param lineno a value
89      * @param line a defined instance
90      * @return the former value or {@code null}
91      */
put(int lineno, String line)92     public String put(int lineno, String line) {
93         if (line == null) {
94             throw new IllegalArgumentException("line is null");
95         }
96         return lines.put(lineno, line);
97     }
98 
99     /**
100      * Creates a new instance with lines merged from this instance and
101      * {@code other}. Any lines in common for the same line number are taken
102      * from this instance rather than {@code other}; and likewise for
103      * {@link #getFooter()}.
104      * <p>
105      * {@link #isLimited()} will be {@code true} if either is {@code true}, but
106      * the value is suspect since it cannot be truly known if the merged result
107      * is actually the unlimited result.
108      * @param other a defined instance
109      * @return a defined instance
110      */
merge(FormattedLines other)111     public FormattedLines merge(FormattedLines other) {
112         FormattedLines res = new FormattedLines();
113         res.lines.putAll(this.lines);
114         for (Map.Entry<Integer, String> kv : other.lines.entrySet()) {
115             res.lines.putIfAbsent(kv.getKey(), kv.getValue());
116         }
117 
118         res.setFooter(this.footer != null ? this.footer : other.footer);
119         res.setLimited(this.limited || other.limited);
120         return res;
121     }
122 
123     @Override
toString()124     public String toString() {
125         StringBuilder bld = new StringBuilder();
126         for (String line : lines.values()) {
127             bld.append(line);
128         }
129         String f = footer;
130         if (f != null && limited) {
131             bld.append(f);
132         }
133         return bld.toString();
134     }
135 }
136