• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yahoo / elide / #7464

06 Dec 2025 12:01AM UTC coverage: 84.293% (-0.1%) from 84.409%
#7464

push

justin-tay
Update to Spring Boot 3.5.8 and align dependencies

0 of 51 new or added lines in 3 files covered. (0.0%)

3 existing lines in 2 files now uncovered.

19744 of 23423 relevant lines covered (84.29%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

38.89
/elide-async/src/main/java/com/yahoo/elide/async/resources/ExportApiEndpoint.java
1
/*
2
 * Copyright 2021, Yahoo Inc.
3
 * Licensed under the Apache License, Version 2.0
4
 * See LICENSE file in project root for terms.
5
 */
6
package com.yahoo.elide.async.resources;
7

8
import com.yahoo.elide.async.service.storageengine.ResultStorageEngine;
9

10
import jakarta.inject.Inject;
11
import jakarta.inject.Named;
12
import jakarta.inject.Singleton;
13
import jakarta.servlet.http.HttpServletResponse;
14
import jakarta.ws.rs.GET;
15
import jakarta.ws.rs.InternalServerErrorException;
16
import jakarta.ws.rs.NotFoundException;
17
import jakarta.ws.rs.Path;
18
import jakarta.ws.rs.PathParam;
19
import jakarta.ws.rs.container.AsyncResponse;
20
import jakarta.ws.rs.container.Suspended;
21
import jakarta.ws.rs.core.Context;
22
import jakarta.ws.rs.core.MediaType;
23
import jakarta.ws.rs.core.Response;
24
import jakarta.ws.rs.core.Response.ResponseBuilder;
25
import jakarta.ws.rs.core.StreamingOutput;
26
import lombok.AllArgsConstructor;
27
import lombok.Data;
28
import lombok.extern.slf4j.Slf4j;
29

30
import java.io.OutputStream;
31
import java.time.Duration;
32
import java.util.concurrent.ExecutorService;
33
import java.util.concurrent.TimeUnit;
34
import java.util.function.Consumer;
35

36
/**
37
 * Default endpoint/servlet for using Elide and Async Export.
38
 */
39
@Slf4j
1✔
40
@Singleton
41
@Path("/")
42
public class ExportApiEndpoint {
43
    protected final ExportApiProperties exportApiProperties;
44
    protected final ResultStorageEngine resultStorageEngine;
45

46
    @Data
47
    @AllArgsConstructor
48
    public static class ExportApiProperties {
49
        private ExecutorService executor;
50
        private Duration maxDownloadTime;
51
    }
52

53
    @Inject
54
    public ExportApiEndpoint(
55
            @Named("resultStorageEngine") ResultStorageEngine resultStorageEngine,
56
            @Named("exportApiProperties") ExportApiProperties exportApiProperties) {
1✔
57
        this.resultStorageEngine = resultStorageEngine;
1✔
58
        this.exportApiProperties = exportApiProperties;
1✔
59
    }
1✔
60

61
    /**
62
     * Read handler.
63
     *
64
     * @param asyncQueryId asyncQueryId to download results
65
     * @param asyncResponse AsyncResponse object
66
     */
67
    @GET
68
    @Path("/{asyncQueryId}")
69
    public void get(@PathParam("asyncQueryId") String asyncQueryId, @Context HttpServletResponse httpServletResponse,
70
            @Suspended final AsyncResponse asyncResponse) {
71
        asyncResponse.setTimeout(exportApiProperties.getMaxDownloadTime().toSeconds(), TimeUnit.SECONDS);
1✔
72
        asyncResponse.setTimeoutHandler(async -> {
1✔
73
            ResponseBuilder resp = Response.status(Response.Status.REQUEST_TIMEOUT).entity("Timed out.");
×
74
            async.resume(resp.build());
×
75
        });
×
76

77
        exportApiProperties.getExecutor().submit(() -> {
1✔
78
            Consumer<OutputStream> observableResults = resultStorageEngine.getResultsByID(asyncQueryId);
1✔
79
            StreamingOutput streamingOutput = outputStream -> {
1✔
80
                try {
81
                    observableResults.accept(outputStream);
×
82
                } catch (RuntimeException e) {
×
83
                    String message = e.getMessage();
×
84
                    try {
85
                        log.debug(message);
×
86
                        if (message != null && message.equals(ResultStorageEngine.RETRIEVE_ERROR)) {
×
NEW
87
                            String errorMessage = asyncQueryId + " Not Found";
×
NEW
88
                            throw new NotFoundException(errorMessage,
×
NEW
89
                                    Response.status(Response.Status.NOT_FOUND).entity(errorMessage).build());
×
90
                        } else {
NEW
91
                            throw new InternalServerErrorException(
×
NEW
92
                                    Response.status(Response.Status.INTERNAL_SERVER_ERROR)
×
NEW
93
                                            .entity("Internal Server Error").build());
×
94
                        }
95
                    } catch (IllegalStateException ise) {
×
96
                        // If stream was flushed, Attachment download has already started.
97
                        // response.sendError causes java.lang.IllegalStateException:
98
                        // Cannot call sendError() after the response has been committed.
99
                        // This will return 200 status.
100
                        // Add error message in the attachment as a way to signal errors.
101
                        outputStream.write(
×
102
                                "Error Occured...."
103
                                .concat(System.lineSeparator())
×
104
                                .getBytes()
×
105
                                );
106
                        log.debug(ise.getMessage());
×
107
                    }
108
                } finally {
109
                    outputStream.flush();
×
110
                    outputStream.close();
×
111
                }
112
            };
×
113
            asyncResponse.resume(Response.ok(streamingOutput, MediaType.APPLICATION_OCTET_STREAM)
1✔
114
                    .header("Content-Disposition", "attachment; filename=" + asyncQueryId).build());
1✔
115
        });
1✔
116
    }
1✔
117
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc