Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #1 from 3d-system-navigation/feature/smg-flow
Feature/smg flow
  • Loading branch information
dds14002 committed Mar 3, 2020
2 parents 9f4dfdc + bdc0eb5 commit ff84ec7
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 17 deletions.
Expand Up @@ -3,16 +3,17 @@ package com.lmco.spectrum.systemnavigation3d.controller;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.util.IOUtils;
import com.lmco.spectrum.systemnavigation3d.service.ResourceService;
import com.lmco.spectrum.systemnavigation3d.service.SmgService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -21,36 +22,80 @@ import java.io.InputStream;
@RequestMapping("api/resources")
public class ResourceController {

private final HttpHeaders PDF_HEADERS;

@Autowired
ResourceService resourceService;
@Autowired
SmgService smgService;

private ResponseEntity<?> handleS3Input(String key, @Nullable HttpHeaders headers) {
try (InputStream is = resourceService.getFileAsStream(key)) {
return new ResponseEntity<>(IOUtils.toByteArray(is), headers, HttpStatus.OK);
} catch (AmazonS3Exception e) {
if(e.getErrorCode().equals("NoSuchKey")) {
return new ResponseEntity<>(e.getErrorMessage(), HttpStatus.NOT_FOUND);
public ResourceController() {
this.PDF_HEADERS = new HttpHeaders();
PDF_HEADERS.setContentType(MediaType.APPLICATION_PDF);
}

private HttpHeaders getAutoDownloadHeaders(String key) {
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData(key, key);
return headers;
}

private ResponseEntity<?> respondToException(Exception e) {
if (e instanceof AmazonS3Exception) {
AmazonS3Exception ex = (AmazonS3Exception)e;
if (ex.getErrorCode().equals("NoSuchKey")) {
return new ResponseEntity<>(ex.getErrorMessage(), HttpStatus.NOT_FOUND);
} else {
e.printStackTrace();
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
ex.printStackTrace();
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
} catch (IOException e) {
} else if(e instanceof IOException) {
e.printStackTrace();
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}

// Return 500 as default.
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}

@RequestMapping(value = "/pdf/{key}", method = RequestMethod.GET)
private ResponseEntity<?> fetchResponseFromS3(String key, @Nullable HttpHeaders headers) {
try (InputStream is = resourceService.getFileAsStream(key)) {
return new ResponseEntity<>(IOUtils.toByteArray(is), headers, HttpStatus.OK);
} catch (Exception e) {
return respondToException(e);
}
}

@GetMapping("/pdf/{key}")
public ResponseEntity<?> getResourcePDF(@PathVariable("key") String key){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
// headers.setContentDispositionFormData(key, key); // Auto download
return handleS3Input(key, headers);
return fetchResponseFromS3(key, this.PDF_HEADERS);
}

@RequestMapping(value = "/{key}", method = RequestMethod.GET)
@GetMapping("/{key}")
public ResponseEntity<?> getResource(@PathVariable("key") String key){
return handleS3Input(key, null);
return fetchResponseFromS3(key, null);
}

// TODO what input data?
@GetMapping("/smg/{key}")
public ResponseEntity<?> getResourceSMG(@PathVariable("key") String key) {

try(InputStream is = resourceService.getFileAsStream(String.format("smg/%s", key))) {

byte[] data = IOUtils.toByteArray(is);

byte[] processed = smgService.processSmg(data);
if(processed == null) {
// TODO failed to process, error?
// TODO maybe return error list
return new ResponseEntity<>("Failed to process SMG file.", HttpStatus.INTERNAL_SERVER_ERROR);
} else {
return new ResponseEntity<>(processed, getAutoDownloadHeaders(key), HttpStatus.OK);
}

} catch(Exception e) {
return respondToException(e);
}
}

}
@@ -0,0 +1,85 @@
package com.lmco.spectrum.systemnavigation3d.service;

import com.amazonaws.util.IOUtils;
import com.lmco.spectrum.systemnavigation3d.util.io.SfxZipInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

@Service
public class SmgService {

private static final Logger log = LoggerFactory.getLogger(SmgService.class);
private static final String PRODUCT_XML = "product.smgXml";

@Autowired
TransformationService transformationService;

// Max capacity is 2^31-1 bytes or ~2GB.
@Nullable
public byte[] processSmg(byte[] data){
Map<String, byte[]> entryMap = getSmgXmlEntry(data);
byte[] smgXmlData = entryMap.get(PRODUCT_XML);
if(smgXmlData != null) {
String smgXml = new String(smgXmlData);
smgXml = transformationService.transform(smgXml);
entryMap.put(PRODUCT_XML, smgXml.getBytes()); // Update XML entry.
return repackageSmg(entryMap);
} else {
return null;
}
}

public Map<String, byte[]> getSmgXmlEntry(byte[] data) {

Map<String, byte[]> entryMap = new HashMap<>();

try(ZipInputStream zis = new ZipInputStream(new SfxZipInputStream(new ByteArrayInputStream(data)))) {

ZipEntry entry;
while((entry = zis.getNextEntry()) != null) {
entryMap.put(entry.getName(), IOUtils.toByteArray(zis));
zis.closeEntry();
}
return entryMap;

} catch (IOException e) {
log.error("Failed to read .smgXml entry!");
e.printStackTrace();
}

return entryMap;
}

@Nullable
public byte[] repackageSmg(Map<String, byte[]> entryMap) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(bos)) {
for(Map.Entry<String, byte[]> entry : entryMap.entrySet()) {
ZipEntry zipEntry = new ZipEntry(entry.getKey());
zos.putNextEntry(zipEntry);
zos.write(entry.getValue());
zos.closeEntry();
}
} catch (IOException e) {
log.error("Failed to repackage smg file");
e.printStackTrace();
return null;
}

return bos.toByteArray();

}

}
@@ -0,0 +1,17 @@
package com.lmco.spectrum.systemnavigation3d.service;

import org.springframework.stereotype.Service;

@Service
public class TransformationService {

// TODO make functional
// TODO consider types of transformations we need to make
// accept list of transformation options?
// accept GEIA dtos and infer transformations?
// pending
public String transform(String smgXml){
return smgXml;
}

}
@@ -0,0 +1,46 @@
package com.lmco.spectrum.systemnavigation3d.util.io;

import javax.annotation.Nonnull;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

// Credit
// https://stackoverflow.com/questions/7924895/how-can-i-read-from-a-winzip-self-extracting-exe-zip-file-in-java
public class SfxZipInputStream extends FilterInputStream {

// https://en.wikipedia.org/wiki/Zip_(file_format)#Local_file_header
public static final byte[] ZIP_LOCAL = { 0x50, 0x4b, 0x03, 0x04 };
protected int ip;
protected int op;

public SfxZipInputStream(InputStream is) {
super(is);
}

@Override
public int read() throws IOException {
while(ip < ZIP_LOCAL.length) {
int c = super.read();
if (c == ZIP_LOCAL[ip]) {
ip++;
}
else ip = 0;
}

if (op < ZIP_LOCAL.length)
return ZIP_LOCAL[op++];
else
return super.read();
}

@Override
public int read(@Nonnull byte[] b, int off, int len) throws IOException {
if (op == ZIP_LOCAL.length) return super.read(b, off, len);
int l = 0;
while (l < Math.min(len, ZIP_LOCAL.length)) {
b[l++] = (byte)read();
}
return l;
}
}

0 comments on commit ff84ec7

Please sign in to comment.