Skip to content

Commit a11b766

Browse files
author
Vladimir Kotal
committed
change /system/pathdesc API endpoint to accept JSON
fixes #3374
1 parent e396c97 commit a11b766

File tree

6 files changed

+106
-89
lines changed

6 files changed

+106
-89
lines changed

apiary.apib

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -258,20 +258,19 @@ see https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java
258258
### updates path descriptions for web application [POST]
259259

260260
This will refresh the path descriptions. The web application will store
261-
the descriptions in a file so it is not necessary to reload the path
262-
descriptions after each web application redeploy.
261+
the descriptions in a file under data root so it is not necessary to load the path
262+
descriptions manually after each web application redeploy.
263263

264-
The input consists of strings separated by newline. Each string contains
265-
a path and its description.
264+
The paths are relative to source root, starting with /.
266265

267-
The paths are relative to source root, starting with /. The path and its
268-
description is separated by a single tab character.
269-
270-
+ Request (text/plain)
266+
+ Request (application/json)
271267
+ Body
272268

273-
/foo bar
274-
/foo/foo bar bar
269+
[
270+
{"path": "/foo", "description": "foo foo"},
271+
{"path": "/bar", "description": "bar"}
272+
]
273+
275274

276275
+ Response 204
277276

opengrok-indexer/src/main/java/org/opengrok/indexer/web/EftarFile.java

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,11 @@
2323
package org.opengrok.indexer.web;
2424

2525
import java.io.BufferedOutputStream;
26-
import java.io.BufferedReader;
2726
import java.io.DataOutputStream;
28-
import java.io.File;
29-
import java.io.FileNotFoundException;
3027
import java.io.FileOutputStream;
31-
import java.io.FileReader;
3228
import java.io.IOException;
33-
import java.io.StringReader;
3429
import java.util.Map;
30+
import java.util.Set;
3531
import java.util.StringTokenizer;
3632
import java.util.TreeMap;
3733

@@ -52,6 +48,7 @@ public class EftarFile {
5248

5349
public static final int RECORD_LENGTH = 14;
5450
private long offset;
51+
private Node root;
5552

5653
class Node {
5754

@@ -142,46 +139,28 @@ private void traverse(Node n) {
142139
traverse(childnode);
143140
}
144141
}
145-
private Node root;
146-
147-
public void readInput(File inputFile) throws IOException {
148-
try (BufferedReader r = new BufferedReader(new FileReader(inputFile))) {
149-
readInput(r);
150-
}
151-
}
152-
153-
public void readInput(String input) throws IOException {
154-
try (BufferedReader r = new BufferedReader(new StringReader(input))) {
155-
readInput(r);
156-
}
157-
}
158142

159143
/**
160144
* Reads the input into interim representation. Can be called multiple times.
161-
* @param r reader
145+
* @param descriptions set of PathDescription
162146
* @throws IOException
163147
*/
164-
private void readInput(BufferedReader r) throws IOException {
148+
private void readInput(Set<PathDescription> descriptions) throws IOException {
165149
if (root == null) {
166150
root = new Node(1, null);
167151
}
168-
String line;
169-
while ((line = r.readLine()) != null) {
170-
int tab = line.indexOf('\t');
171-
if (tab > 0) {
172-
String path = line.substring(0, tab);
173-
String desc = line.substring(tab + 1);
174-
StringTokenizer toks = new StringTokenizer(path, "\\/");
175-
Node n = root;
176-
while (toks.hasMoreTokens()) {
177-
n = n.put(myHash(toks.nextToken()), null);
178-
}
179-
n.tag = desc;
152+
153+
for (PathDescription desc : descriptions) {
154+
StringTokenizer toks = new StringTokenizer(desc.getPath(), "\\/");
155+
Node n = root;
156+
while (toks.hasMoreTokens()) {
157+
n = n.put(myHash(toks.nextToken()), null);
180158
}
159+
n.tag = desc.getDescription();
181160
}
182161
}
183162

184-
public void write(String outPath) throws FileNotFoundException, IOException {
163+
public void write(String outPath) throws IOException {
185164
offset = RECORD_LENGTH;
186165
traverse(root);
187166
try (DataOutputStream out = new DataOutputStream(
@@ -195,13 +174,8 @@ public void write(String outPath) throws FileNotFoundException, IOException {
195174
}
196175
}
197176

198-
public void create(File inputFile, String outputPath) throws IOException {
199-
readInput(inputFile);
200-
write(outputPath);
201-
}
202-
203-
public void create(String input, String outputPath) throws IOException, FileNotFoundException {
204-
readInput(input);
177+
public void create(Set<PathDescription> descriptions, String outputPath) throws IOException {
178+
readInput(descriptions);
205179
write(outputPath);
206180
}
207181
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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) 2020, Oracle and/or its affiliates. All rights reserved.
22+
*/
23+
package org.opengrok.indexer.web;
24+
25+
public class PathDescription {
26+
private String path;
27+
private String description;
28+
29+
PathDescription() { // needed for deserialization
30+
}
31+
32+
public PathDescription(String path, String description) {
33+
this.path = path;
34+
this.description = description;
35+
}
36+
37+
public String getDescription() {
38+
return description;
39+
}
40+
41+
public void setDescription(String description) {
42+
this.description = description;
43+
}
44+
45+
public String getPath() {
46+
return path;
47+
}
48+
49+
public void setPath(String path) {
50+
this.path = path;
51+
}
52+
}

opengrok-indexer/src/test/java/org/opengrok/indexer/web/EftarFileTest.java

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
package org.opengrok.indexer.web;
2424

2525
import java.io.File;
26-
import java.io.FileWriter;
2726
import java.io.IOException;
28-
import java.io.PrintWriter;
27+
import java.util.HashSet;
28+
import java.util.Set;
2929

3030
import org.junit.After;
3131
import org.junit.AfterClass;
@@ -40,7 +40,6 @@
4040
*/
4141
public class EftarFileTest {
4242

43-
private static File tsv;
4443
private static File eftar;
4544

4645
public EftarFileTest() {
@@ -50,35 +49,26 @@ public EftarFileTest() {
5049

5150
@BeforeClass
5251
public static void setUpClass() throws Exception {
53-
tsv = File.createTempFile("paths", ".tsv");
52+
5453
eftar = File.createTempFile("paths", ".eftar");
54+
int len = 100;
55+
Set<PathDescription> descriptions = new HashSet<>();
5556

56-
try (PrintWriter out = new PrintWriter(new FileWriter(tsv))) {
57-
StringBuilder sb = new StringBuilder();
58-
for (int ii = 0; ii < 100; ii++) {
59-
sb.append(PATH_STRING);
60-
sb.append(ii);
61-
out.print(sb.toString());
62-
out.print("\tDescription ");
63-
out.println(ii);
64-
}
65-
out.flush();
57+
StringBuilder sb = new StringBuilder();
58+
for (int ii = 0; ii < len; ii++) {
59+
sb.append(PATH_STRING);
60+
sb.append(ii);
61+
descriptions.add(new PathDescription(sb.toString(), "Description " + ii));
6662
}
6763

68-
// Create eftar files.
69-
String inputFile = tsv.getAbsolutePath();
7064
String outputFile = eftar.getAbsolutePath();
7165

7266
EftarFile ef = new EftarFile();
73-
ef.create(new File(inputFile), outputFile);
67+
ef.create(descriptions, outputFile);
7468
}
7569

7670
@AfterClass
7771
public static void tearDownClass() throws Exception {
78-
if (tsv != null) {
79-
tsv.delete();
80-
}
81-
8272
if (eftar != null) {
8373
eftar.delete();
8474
}
@@ -113,7 +103,7 @@ private void searchEftarFile(EftarFileReader er) throws IOException {
113103
match.setLength(offset);
114104
match.append(ii);
115105

116-
assertEquals(match.toString(), er.get(sb.toString()));
106+
assertEquals("description for path " + sb.toString(), match.toString(), er.get(sb.toString()));
117107
}
118108
er.close();
119109
}

opengrok-web/src/main/java/org/opengrok/web/api/v1/controller/SystemController.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,31 @@
2424

2525
import org.opengrok.indexer.configuration.RuntimeEnvironment;
2626
import org.opengrok.indexer.web.EftarFile;
27+
import org.opengrok.indexer.logger.LoggerFactory;
28+
import org.opengrok.indexer.web.PathDescription;
2729
import org.opengrok.web.api.v1.suggester.provider.service.SuggesterService;
2830

2931
import javax.inject.Inject;
32+
import javax.validation.Valid;
3033
import javax.ws.rs.Consumes;
3134
import javax.ws.rs.POST;
3235
import javax.ws.rs.PUT;
3336
import javax.ws.rs.Path;
3437
import javax.ws.rs.core.MediaType;
3538
import java.io.IOException;
3639
import java.util.Collections;
40+
import java.util.Set;
3741
import java.util.concurrent.CompletableFuture;
42+
import java.util.logging.Level;
43+
import java.util.logging.Logger;
3844

3945
@Path("/system")
4046
public class SystemController {
4147

4248
private final RuntimeEnvironment env = RuntimeEnvironment.getInstance();
4349

50+
private static final Logger LOGGER = LoggerFactory.getLogger(SystemController.class);
51+
4452
@Inject
4553
private SuggesterService suggester;
4654

@@ -60,9 +68,10 @@ public void reloadIncludes() {
6068

6169
@POST
6270
@Path("/pathdesc")
63-
@Consumes(MediaType.TEXT_PLAIN)
64-
public void loadPathDescriptions(final String input) throws IOException {
71+
@Consumes(MediaType.APPLICATION_JSON)
72+
public void loadPathDescriptions(@Valid final PathDescription[] descriptions) throws IOException {
6573
EftarFile ef = new EftarFile();
66-
ef.create(input, env.getDtagsEftarPath().toString());
74+
ef.create(Set.of(descriptions), env.getDtagsEftarPath().toString());
75+
LOGGER.log(Level.INFO, "reloaded path descriptions with {0} entries", descriptions.length);
6776
}
6877
}

opengrok-web/src/test/java/org/opengrok/web/api/v1/controller/SystemControllerTest.java

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.opengrok.indexer.configuration.RuntimeEnvironment;
2828
import org.opengrok.indexer.util.IOUtils;
2929
import org.opengrok.indexer.web.EftarFileReader;
30+
import org.opengrok.indexer.web.PathDescription;
3031
import org.opengrok.web.api.v1.RestApp;
3132

3233
import javax.ws.rs.client.Entity;
@@ -106,31 +107,23 @@ public void testDtagsEftarReload() throws IOException {
106107

107108
// Create path descriptions string.
108109
StringBuilder sb = new StringBuilder();
109-
String[][] descriptions = {
110-
{"/path1", "foo foo"},
111-
{"/path2", "bar bar"}
110+
PathDescription[] descriptions = {
111+
new PathDescription("/path1", "foo foo"),
112+
new PathDescription("/path2", "bar bar")
112113
};
113114

114-
for (String[] description : descriptions) {
115-
sb.append(description[0]);
116-
sb.append("\t");
117-
sb.append(description[1]);
118-
sb.append("\n");
119-
}
120-
String input = sb.toString();
121-
122115
// Reload the contents via API call.
123116
Response r = target("system")
124117
.path("pathdesc")
125-
.request().post(Entity.text(input));
118+
.request().post(Entity.json(descriptions));
126119
assertEquals(Response.Status.NO_CONTENT.getStatusCode(), r.getStatus());
127120

128121
// Check
129122
Path eftarPath = env.getDtagsEftarPath();
130123
assertTrue(eftarPath.toFile().exists());
131124
try (EftarFileReader er = new EftarFileReader(eftarPath.toString())) {
132-
for (String[] description : descriptions) {
133-
assertEquals(description[1], er.get(description[0]));
125+
for (PathDescription description : descriptions) {
126+
assertEquals(description.getDescription(), er.get(description.getPath()));
134127
}
135128
}
136129

0 commit comments

Comments
 (0)