Skip to content
Open
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
20 changes: 14 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>uk.gov.moj.cpp.common</groupId>
<artifactId>service-parent-pom</artifactId>
<version>17.104.0</version>
<version>17.104.3</version>
</parent>

<groupId>uk.gov.moj.cpp.progression</groupId>
Expand Down Expand Up @@ -60,16 +60,19 @@
**/uk/gov/moj/cpp/progression/value/object/**/*
</sonar.exclusions>
<sonar.cpd.exclusions>**/uk/gov/moj/cpp/**/*.java</sonar.cpd.exclusions>
<!-- JDK HTTP transport for Azure SDK v12 — avoids netty conflicts with WildFly 26's own netty modules.
TODO: move to cpp-platform-maven-common-bom once available there -->
<azure-core-http-jdk-httpclient.version>1.0.0-beta.14</azure-core-http-jdk-httpclient.version>
<resteasy-multipart-provider.version>3.0.7.Final</resteasy-multipart-provider.version>
<mvn.site.url>file://${project.build.directory}/site</mvn.site.url>
<javafaker.version>1.0.2</javafaker.version>
<material.version>17.0.72</material.version>
<json-transformer.version>1.0.6</json-transformer.version>
<access.control.version>6.4.1</access.control.version>
<referencedata.version>17.0.120</referencedata.version>
<listing.version>17.0.125</listing.version>
<hearing.version>17.0.134</hearing.version>
<usersgroups.version>17.0.37</usersgroups.version>
<referencedata.version>17.103.132</referencedata.version>
<listing.version>17.103.163</listing.version>
<hearing.version>17.104.168</hearing.version>
<usersgroups.version>17.104.49</usersgroups.version>
<defence.version>17.0.85</defence.version>
<referencedata.offence.version>17.0.38</referencedata.offence.version>
<coredomain.version>17.104.1</coredomain.version>
Expand All @@ -80,7 +83,7 @@
<unifiedsearch.version>17.0.26</unifiedsearch.version>
<systemdocgenerator.version>17.0.64</systemdocgenerator.version>
<applicationscourtorders.version>17.0.60</applicationscourtorders.version>
<sjp.version>17.0.130</sjp.version>
<sjp.version>17.103.171</sjp.version>
<httpmime.version>4.5.1</httpmime.version>
<stagingpubhub.version>17.0.23</stagingpubhub.version>
<pdfbox.version>2.0.11</pdfbox.version>
Expand Down Expand Up @@ -194,6 +197,11 @@
<version>${javafaker.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-jdk-httpclient</artifactId>
<version>${azure-core-http-jdk-httpclient.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
17 changes: 12 additions & 5 deletions progression-command/progression-command-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,22 @@
<groupId>uk.gov.justice.framework-generators</groupId>
<artifactId>rest-client-core</artifactId>
</dependency>
<dependency>
<groupId>uk.gov.justice.framework-generators</groupId>
<artifactId>rest-adapter-file-service</artifactId>
</dependency>

<dependency>
<groupId>uk.gov.justice</groupId>
<artifactId>file-alfresco</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-blob</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-jdk-httpclient</artifactId>
</dependency>

<dependency>
<groupId>uk.gov.moj.cpp.access-control</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static uk.gov.justice.services.core.annotation.Component.COMMAND_API;

import uk.gov.justice.services.adapter.rest.interceptor.InputStreamFileInterceptor;
import uk.gov.justice.services.core.interceptor.InterceptorChainEntry;
import uk.gov.justice.services.core.interceptor.InterceptorChainEntryProvider;

Expand All @@ -19,7 +18,7 @@ public String component() {
@Override
public List<InterceptorChainEntry> interceptorChainTypes() {
final List<InterceptorChainEntry> interceptorChainEntries = new ArrayList<>();
interceptorChainEntries.add(new InterceptorChainEntry(6000, InputStreamFileInterceptor.class));
interceptorChainEntries.add(new InterceptorChainEntry(6000, ProgressionServiceFileInterceptor.class));
return interceptorChainEntries;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package uk.gov.moj.cpp.progression.command.api.interceptors;

import static com.azure.core.util.BinaryData.fromStream;
import static com.azure.core.util.Context.NONE;
import static javax.json.Json.createObjectBuilder;
import static uk.gov.justice.services.messaging.Envelope.metadataFrom;
import static uk.gov.justice.services.messaging.JsonEnvelope.envelopeFrom;

import uk.gov.justice.services.adapter.rest.multipart.FileInputDetails;
import uk.gov.justice.services.core.interceptor.Interceptor;
import uk.gov.justice.services.core.interceptor.InterceptorChain;
import uk.gov.justice.services.core.interceptor.InterceptorContext;
import uk.gov.justice.services.messaging.JsonEnvelope;

import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.options.BlobParallelUploadOptions;

import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import javax.inject.Inject;
import javax.json.JsonObjectBuilder;

public class ProgressionServiceFileInterceptor implements Interceptor {

private static final Duration TRANSFER_TIMEOUT = Duration.ofSeconds(300);

@Inject
private BlobContainerClient blobContainerClient;

@Override
@SuppressWarnings("unchecked")
public InterceptorContext process(final InterceptorContext interceptorContext, final InterceptorChain interceptorChain) {
final Optional<Object> inputParameter = interceptorContext.getInputParameter(FileInputDetails.FILE_INPUT_DETAILS_LIST);
if (inputParameter.isPresent()) {
final List<FileInputDetails> fileInputDetailsList = (List<FileInputDetails>) inputParameter.get();
final Map<String, UUID> results = storeFiles(fileInputDetailsList);
final JsonEnvelope modifiedEnvelope = addResultsToEnvelope(interceptorContext.inputEnvelope(), results);
return interceptorChain.processNext(interceptorContext.copyWithInput(modifiedEnvelope));
}
return interceptorChain.processNext(interceptorContext);
}

private Map<String, UUID> storeFiles(final List<FileInputDetails> fileInputDetailsList) {
final Map<String, UUID> results = new HashMap<>();
for (final FileInputDetails fileDetails : fileInputDetailsList) {
try (final InputStream inputStream = fileDetails.getInputStream()) {
final UUID fileId = UUID.randomUUID();
blobContainerClient.getBlobClient(fileId.toString())
.uploadWithResponse(
new BlobParallelUploadOptions(fromStream(inputStream))
.setMetadata(Map.of("fileName", fileDetails.getFileName().strip())),
TRANSFER_TIMEOUT, NONE);
results.put(fileDetails.getFieldName(), fileId);
} catch (final IOException e) {
throw new RuntimeException("Failed to store uploaded file: " + fileDetails.getFileName(), e);
}
}
return results;
}

private JsonEnvelope addResultsToEnvelope(final JsonEnvelope envelope, final Map<String, UUID> results) {
final JsonObjectBuilder payloadBuilder = createObjectBuilder(envelope.payloadAsJsonObject());
results.forEach((fieldName, fileId) -> payloadBuilder.add(fieldName, fileId.toString()));
return envelopeFrom(metadataFrom(envelope.metadata()), payloadBuilder.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package uk.gov.moj.cpp.progression.command.api.interceptors;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static uk.gov.justice.services.core.annotation.Component.COMMAND_API;

import uk.gov.justice.services.core.interceptor.InterceptorChainEntry;

import java.util.List;

import org.junit.jupiter.api.Test;

public class ProgressionCommandApiInterceptorChainProviderTest {

private final ProgressionCommandApiInterceptorChainProvider provider = new ProgressionCommandApiInterceptorChainProvider();

@Test
public void shouldReturnCommandApiAsComponent() {
assertThat(provider.component(), is(COMMAND_API));
}

@Test
public void shouldContainProgressionServiceFileInterceptorAtPriority6000() {
final List<InterceptorChainEntry> entries = provider.interceptorChainTypes();

assertThat(entries.size(), is(1));
assertThat(entries.get(0).getPriority(), is(6000));
assertThat(entries.get(0).getInterceptorType(), is(ProgressionServiceFileInterceptor.class));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package uk.gov.moj.cpp.progression.command.api.interceptors;

import static java.util.Optional.empty;
import static java.util.Optional.of;
import static java.util.UUID.randomUUID;
import static javax.json.Json.createObjectBuilder;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static uk.gov.justice.services.messaging.JsonEnvelope.envelopeFrom;
import static uk.gov.justice.services.messaging.JsonEnvelope.metadataBuilder;

import uk.gov.justice.services.adapter.rest.multipart.FileInputDetails;
import uk.gov.justice.services.core.interceptor.InterceptorChain;
import uk.gov.justice.services.core.interceptor.InterceptorContext;
import uk.gov.justice.services.messaging.JsonEnvelope;

import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobContainerClient;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class ProgressionServiceFileInterceptorTest {

private static final String FIELD_NAME = "fileServiceId";
private static final String FILE_NAME = "test-document.pdf";

@Mock
private BlobContainerClient blobContainerClient;

@Mock
private InterceptorContext interceptorContext;

@Mock
private InterceptorContext interceptorContextExpected;

@Mock
private InterceptorChain interceptorChain;

@InjectMocks
private ProgressionServiceFileInterceptor interceptor;

@Test
public void shouldStoreFileAndInjectFileIdIntoEnvelope() {
final JsonEnvelope originalEnvelope = envelopeFrom(
metadataBuilder().withId(randomUUID()).withName("progression.upload-document").withUserId(randomUUID().toString()).build(),
createObjectBuilder().build()
);

final FileInputDetails fileDetails = mock(FileInputDetails.class);
when(fileDetails.getFileName()).thenReturn(FILE_NAME);
when(fileDetails.getFieldName()).thenReturn(FIELD_NAME);
when(fileDetails.getInputStream()).thenReturn(new ByteArrayInputStream("file content".getBytes()));

final BlobClient blobClient = mock(BlobClient.class);

when(interceptorContext.getInputParameter(FileInputDetails.FILE_INPUT_DETAILS_LIST)).thenReturn(of(List.of(fileDetails)));
when(interceptorContext.inputEnvelope()).thenReturn(originalEnvelope);

final ArgumentCaptor<String> blobNameCaptor = ArgumentCaptor.forClass(String.class);
when(blobContainerClient.getBlobClient(blobNameCaptor.capture())).thenReturn(blobClient);

final ArgumentCaptor<JsonEnvelope> envelopeCaptor = ArgumentCaptor.forClass(JsonEnvelope.class);
when(interceptorContext.copyWithInput(envelopeCaptor.capture())).thenReturn(interceptorContextExpected);
when(interceptorChain.processNext(interceptorContextExpected)).thenReturn(interceptorContextExpected);

interceptor.process(interceptorContext, interceptorChain);

verify(interceptorChain).processNext(interceptorContextExpected);

final String blobName = blobNameCaptor.getValue();
assertThat(UUID.fromString(blobName), is(notNullValue()));

final JsonEnvelope modifiedEnvelope = envelopeCaptor.getValue();
assertThat(modifiedEnvelope.payloadAsJsonObject().getString(FIELD_NAME), is(blobName));
}

@Test
public void shouldPassThroughWhenNoFilesPresent() {
when(interceptorContext.getInputParameter(FileInputDetails.FILE_INPUT_DETAILS_LIST)).thenReturn(empty());
when(interceptorChain.processNext(interceptorContext)).thenReturn(interceptorContext);

interceptor.process(interceptorContext, interceptorChain);

verify(interceptorChain).processNext(interceptorContext);
}

@Test
public void shouldWrapIOExceptionInRuntimeException() {
final InputStream failingStream = new InputStream() {
@Override
public int read() {
return -1;
}

@Override
public void close() throws IOException {
throw new IOException("stream close failed");
}
};

final FileInputDetails fileDetails = mock(FileInputDetails.class);
when(fileDetails.getFileName()).thenReturn(FILE_NAME);
when(fileDetails.getFieldName()).thenReturn(FIELD_NAME);
when(fileDetails.getInputStream()).thenReturn(failingStream);

final BlobClient blobClient = mock(BlobClient.class);
when(blobContainerClient.getBlobClient(anyString())).thenReturn(blobClient);
when(interceptorContext.getInputParameter(FileInputDetails.FILE_INPUT_DETAILS_LIST)).thenReturn(of(List.of(fileDetails)));

assertThrows(RuntimeException.class, () -> interceptor.process(interceptorContext, interceptorChain));
}
}
5 changes: 5 additions & 0 deletions progression-command/progression-command-handler/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@
<artifactId>criminal-court-public-model</artifactId>
<version>${coredomain.version}</version>
</dependency>
<dependency>
<groupId>uk.gov.moj.cpp.progression</groupId>
<artifactId>progression-domain-message</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>uk.gov.moj.cpp.usersgroups</groupId>
<artifactId>usersgroups-query-api</artifactId>
Expand Down
12 changes: 10 additions & 2 deletions progression-event/progression-event-processor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,16 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>uk.gov.justice.services</groupId>
<artifactId>file-service-persistence</artifactId>
<groupId>com.azure</groupId>
<artifactId>azure-storage-blob</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-jdk-httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
Expand Down
Loading
Loading