Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blob was missing update and delete support. #682

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 66 additions & 12 deletions cwms-data-api/src/main/java/cwms/cda/api/BlobController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package cwms.cda.api;

import static com.codahale.metrics.MetricRegistry.name;
import static cwms.cda.api.Controllers.*;

import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
Expand All @@ -23,16 +26,13 @@
import io.javalin.plugin.openapi.annotations.OpenApiParam;
import io.javalin.plugin.openapi.annotations.OpenApiRequestBody;
import io.javalin.plugin.openapi.annotations.OpenApiResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.List;
import java.util.Optional;
import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;

import static com.codahale.metrics.MetricRegistry.name;
import static cwms.cda.api.Controllers.*;


/**
Expand Down Expand Up @@ -130,6 +130,8 @@ public void getAll(@NotNull Context ctx) {
}

@OpenApi(
description = "Returns the binary value of the requested blob as a seekable stream with the "
+ "appropriate media type.",
queryParams = {
@OpenApiParam(name = OFFICE, description = "Specifies the owning office."),
},
Expand Down Expand Up @@ -211,16 +213,68 @@ public void create(@NotNull Context ctx) {
}
}

@OpenApi(ignore = true)
@OpenApi(
description = "Update an existing Blob",
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = Blob.class, type = Formats.JSONV2),
@OpenApiContent(from = Blob.class, type = Formats.JSON)
},
required = true),
method = HttpMethod.POST,
tags = {TAG}
)
@Override
public void update(Context ctx, @NotNull String blobId) {
ctx.status(HttpCode.NOT_IMPLEMENTED).json(CdaError.notImplemented());
public void update(@NotNull Context ctx, @NotNull String blobId) {
try (final Timer.Context ignored = markAndTime(CREATE)) {
DSLContext dsl = getDslContext(ctx);

String reqContentType = ctx.req.getContentType();
String formatHeader = reqContentType != null ? reqContentType : Formats.JSON;

ContentType contentType = Formats.parseHeader(formatHeader);
Blob blob = Formats.parseContent(contentType, ctx.bodyAsInputStream(), Blob.class);

if (blob.getOfficeId() == null) {
throw new FormattingException("An officeId is required when updating a blob");
}

if (blob.getId() == null) {
throw new FormattingException("An Id is required when updating a blob");
}

if (blob.getValue() == null) {
throw new FormattingException("A non-empty value field is required when "
+ "updating a blob");
}

BlobDao dao = new BlobDao(dsl);
dao.update(blob, false);
ctx.status(HttpServletResponse.SC_OK);
}
}

@OpenApi(ignore = true)
@OpenApi(
description = "Deletes requested blob",
pathParams = {
@OpenApiParam(name = BLOB_ID, description = "The blob identifier to be deleted"),
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the "
+ "owning office of the blob to be deleted"),
},
method = HttpMethod.DELETE,
tags = {TAG}
)
@Override
public void delete(Context ctx, @NotNull String blobId) {
ctx.status(HttpCode.NOT_IMPLEMENTED).json(CdaError.notImplemented());
public void delete(@NotNull Context ctx, @NotNull String blobId) {
try (Timer.Context ignored = markAndTime(DELETE)) {
DSLContext dsl = getDslContext(ctx);
String office = requiredParam(ctx, OFFICE);
BlobDao dao = new BlobDao(dsl);
dao.delete(office, blobId);
ctx.status(HttpServletResponse.SC_NO_CONTENT);
}
}

}
62 changes: 55 additions & 7 deletions cwms-data-api/src/main/java/cwms/cda/data/dao/BlobDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@

import cwms.cda.api.errors.NotFoundException;
import cwms.cda.data.dto.Blob;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.ResultQuery;
import usace.cwms.db.dao.util.OracleTypeMap;
import usace.cwms.db.jooq.codegen.packages.CWMS_TEXT_PACKAGE;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -17,6 +10,12 @@
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.ResultQuery;
import usace.cwms.db.dao.util.OracleTypeMap;
import usace.cwms.db.jooq.codegen.packages.CWMS_TEXT_PACKAGE;

public class BlobDao extends JooqDao<Blob> {

Expand Down Expand Up @@ -178,6 +177,55 @@ public void create(Blob blob, boolean failIfExists, boolean ignoreNulls) {
blob.getOfficeId()));
}

public void update(Blob blob, boolean ignoreNulls) {
String pFailIfExists = OracleTypeMap.formatBool(false);
String pIgnoreNulls = OracleTypeMap.formatBool(ignoreNulls);

if(blob == null){
throw new NotFoundException("null blob provided to update");
}

if (!blobExists(blob.getOfficeId(), blob.getId())) {
throw new NotFoundException("Unable to find blob with id " + blob.getId() + " in office " + blob.getOfficeId());
}

dsl.connection(c -> CWMS_TEXT_PACKAGE.call_STORE_BINARY(
getDslContext(c, blob.getOfficeId()).configuration(),
blob.getValue(),
blob.getId(),
blob.getMediaTypeId(),
blob.getDescription(),
pFailIfExists,
pIgnoreNulls,
blob.getOfficeId()));
}

public void delete(String office, String id) {
if (!blobExists(office, id)) {
throw new NotFoundException("Unable to find blob with id " + id + " in office " + office);
}
dsl.connection(c -> CWMS_TEXT_PACKAGE.call_DELETE_BINARY(
getDslContext(c, office).configuration(),
id,
office));
}

private boolean blobExists(String office, String id) {
String existsQuery = "select 1 "
+ "from CWMS_20.AT_BLOB \n"
+ "join CWMS_20.CWMS_OFFICE on AT_BLOB.OFFICE_CODE = CWMS_OFFICE.OFFICE_CODE \n"
+ "WHERE ID = ? AND upper(CWMS_OFFICE.OFFICE_ID) = upper(?)";
return connectionResult(dsl, conn -> {
try (PreparedStatement preparedStatement = conn.prepareStatement(existsQuery)) {
preparedStatement.setString(1, id);
preparedStatement.setString(2, office);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
return resultSet.next();
}
}
});
}


public static byte[] readFully(@NotNull InputStream stream) throws IOException {
byte[] buffer = new byte[8192];
Expand Down
Loading