CE-881 - support for streamed outputs, implemented for render saved reports process

This commit is contained in:
2024-04-01 12:47:11 -05:00
parent 6f406fc42d
commit 1eeb57f32f
4 changed files with 77 additions and 38 deletions

View File

@ -22,20 +22,19 @@
package com.kingsrook.qqq.api.implementations.savedreports; package com.kingsrook.qqq.api.implementations.savedreports;
import java.io.File;
import java.io.Serializable; import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.Map; import java.util.Map;
import com.kingsrook.qqq.api.model.actions.HttpApiResponse; import com.kingsrook.qqq.api.model.actions.HttpApiResponse;
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessOutputInterface; import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessOutputInterface;
import com.kingsrook.qqq.api.model.openapi.Content; import com.kingsrook.qqq.api.model.openapi.Content;
import com.kingsrook.qqq.api.model.openapi.Response; import com.kingsrook.qqq.api.model.openapi.Response;
import com.kingsrook.qqq.api.model.openapi.Schema; import com.kingsrook.qqq.api.model.openapi.Schema;
import com.kingsrook.qqq.backend.core.actions.tables.StorageAction;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
import org.apache.commons.io.FileUtils; import com.kingsrook.qqq.backend.core.model.actions.tables.storage.StorageInput;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
@ -51,25 +50,10 @@ public class RenderSavedReportProcessApiProcessOutput implements ApiProcessOutpu
@Override @Override
public Serializable getOutputForProcess(RunProcessInput runProcessInput, RunProcessOutput runProcessOutput) throws QException public Serializable getOutputForProcess(RunProcessInput runProcessInput, RunProcessOutput runProcessOutput) throws QException
{ {
try //////////////////////////////////////////////////////////////////
{ // we don't use output like this - see customizeHttpApiResponse //
ReportFormat reportFormat = ReportFormat.fromString(runProcessOutput.getValueString("reportFormat")); //////////////////////////////////////////////////////////////////
return (null);
String filePath = runProcessOutput.getValueString("serverFilePath");
File file = new File(filePath);
if(reportFormat.getIsBinary())
{
return FileUtils.readFileToByteArray(file);
}
else
{
return FileUtils.readFileToString(file, Charset.defaultCharset());
}
}
catch(Exception e)
{
throw new QException("Error streaming report contents", e);
}
} }
@ -85,8 +69,18 @@ public class RenderSavedReportProcessApiProcessOutput implements ApiProcessOutpu
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////
httpApiResponse.setNeedsFormattedAsJson(false); httpApiResponse.setNeedsFormattedAsJson(false);
/////////////////////////////////////////////
// set content type based on report format //
/////////////////////////////////////////////
ReportFormat reportFormat = ReportFormat.fromString(runProcessOutput.getValueString("reportFormat")); ReportFormat reportFormat = ReportFormat.fromString(runProcessOutput.getValueString("reportFormat"));
httpApiResponse.setContentType(reportFormat.getMimeType()); httpApiResponse.setContentType(reportFormat.getMimeType());
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// get an input stream from the backend where the report content is stored - send that down to the caller //
////////////////////////////////////////////////////////////////////////////////////////////////////////////
String storageTableName = runProcessOutput.getValueString("storageTableName");
String storageReference = runProcessOutput.getValueString("storageReference");
httpApiResponse.setInputStream(new StorageAction().getInputStream(new StorageInput(storageTableName).withReference(storageReference)));
} }

View File

@ -380,6 +380,16 @@ public class QJavalinApiHandler
context.contentType(response.getContentType()); context.contentType(response.getContentType());
} }
///////////////////////////////////////////////////////////////////////////////////
// if there's an input stream in the response, just send that down to the client //
///////////////////////////////////////////////////////////////////////////////////
if(response.getInputStream() != null)
{
context.result(response.getInputStream());
storeApiLog(apiLog.withStatusCode(context.statusCode()).withResponseBody("Streamed result"));
}
else
{
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
// else, try to return it raw - as byte[], or String, or as a converted-to-String // // else, try to return it raw - as byte[], or String, or as a converted-to-String //
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
@ -402,6 +412,7 @@ public class QJavalinApiHandler
} }
} }
} }
}

View File

@ -22,6 +22,7 @@
package com.kingsrook.qqq.api.model.actions; package com.kingsrook.qqq.api.model.actions;
import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
@ -37,6 +38,8 @@ public class HttpApiResponse
private String contentType; private String contentType;
private InputStream inputStream;
//////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////
// by default - QJavalinApiHandler will format the responseBodyObject as JSON. // // by default - QJavalinApiHandler will format the responseBodyObject as JSON. //
// set this field to false if you don't want it to do that (e.g., if your response is, say, a byte[]) // // set this field to false if you don't want it to do that (e.g., if your response is, say, a byte[]) //
@ -189,4 +192,35 @@ public class HttpApiResponse
return (this); return (this);
} }
/*******************************************************************************
** Getter for inputStream
*******************************************************************************/
public InputStream getInputStream()
{
return (this.inputStream);
}
/*******************************************************************************
** Setter for inputStream
*******************************************************************************/
public void setInputStream(InputStream inputStream)
{
this.inputStream = inputStream;
}
/*******************************************************************************
** Fluent setter for inputStream
*******************************************************************************/
public HttpApiResponse withInputStream(InputStream inputStream)
{
this.inputStream = inputStream;
return (this);
}
} }

View File

@ -175,7 +175,7 @@ public class TestUtils
private static void addSavedReports(QInstance qInstance) throws QException private static void addSavedReports(QInstance qInstance) throws QException
{ {
qInstance.add(TablesPossibleValueSourceMetaDataProvider.defineTablesPossibleValueSource(qInstance)); qInstance.add(TablesPossibleValueSourceMetaDataProvider.defineTablesPossibleValueSource(qInstance));
new SavedReportsMetaDataProvider().defineAll(qInstance, MEMORY_BACKEND_NAME, null); new SavedReportsMetaDataProvider().defineAll(qInstance, MEMORY_BACKEND_NAME, MEMORY_BACKEND_NAME, null);
RenderSavedReportProcessApiMetaDataEnricher.setupProcessForApi(qInstance.getProcess(RenderSavedReportMetaDataProducer.NAME), API_NAME, V2022_Q4); RenderSavedReportProcessApiMetaDataEnricher.setupProcessForApi(qInstance.getProcess(RenderSavedReportMetaDataProducer.NAME), API_NAME, V2022_Q4);
} }