diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..906ba3855e2334983b2d4750bdc68ff99b03ba69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,313 @@ + +# Created by https://www.gitignore.io/api/java,maven,macos,linux,eclipse,windows,netbeans,intellij +# Edit at https://www.gitignore.io/?templates=java,maven,macos,linux,eclipse,windows,netbeans,intellij + + +# User specific +.sonarlint/ +Servers/ +*.log +*.gz + +### Eclipse ### + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +### Eclipse Patch ### +# Eclipse Core +.project + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Annotation Processing +.apt_generated + +.sts4-cache/ + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +### NetBeans ### +**/nbproject/private/ +**/nbproject/Makefile-*.mk +**/nbproject/Package-*.bash +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.gitignore.io/api/java,maven,macos,linux,eclipse,windows,netbeans,intellij +/.gradle/ + + +### Gradle ### +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### Gradle Patch ### +# Java heap dump +*.hprof + +# End of https://www.toptal.com/developers/gitignore/api/gradle +/CityDoctorWebService/CityDoctorWebService.iml +/Extensions/CityDoctorWebService/CityDoctorWebService.iml +/.idea/codeStyles/codeStyleConfig.xml +/GUISettings.properties +/.idea/inspectionProfiles/Project_Default.xml diff --git a/IfcConvert.exe b/IfcConvert.exe new file mode 100644 index 0000000000000000000000000000000000000000..9c8ac2723660e954cbff7e5e6573c4652d4194d7 Binary files /dev/null and b/IfcConvert.exe differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..e89f142d7300fc1dd13eba73bfa411a15de6f2e4 --- /dev/null +++ b/pom.xml @@ -0,0 +1,74 @@ + + 4.0.0 + de.hft.stuttgart + ifc-converter-server + 1.0.0 + + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 17 + 17 + + + + org.codehaus.mojo + exec-maven-plugin + 3.0.0 + + de.hft.stuttgart.lgl.ifc.ConverterApplication + + + + org.springframework.boot + spring-boot-maven-plugin + 2.6.3 + + true + + + + + repackage + + + convert + spring-boot + de.hft.stuttgart.lgl.ifc.ConverterApplication + + + + + + + + + + + org.springframework.boot + spring-boot-dependencies + 2.6.3 + import + pom + + + + \ No newline at end of file diff --git a/src/main/java/de/hft/stuttgart/lgl/ifc/ConverterApplication.java b/src/main/java/de/hft/stuttgart/lgl/ifc/ConverterApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..affae7e3a95cfcbc9b7be9e7fd7a2a70ca918640 --- /dev/null +++ b/src/main/java/de/hft/stuttgart/lgl/ifc/ConverterApplication.java @@ -0,0 +1,13 @@ +package de.hft.stuttgart.lgl.ifc; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ConverterApplication { + + public static void main(String[] args) { + SpringApplication.run(ConverterApplication.class, args); + } + +} diff --git a/src/main/java/de/hft/stuttgart/lgl/ifc/controller/ConverterEndpoints.java b/src/main/java/de/hft/stuttgart/lgl/ifc/controller/ConverterEndpoints.java new file mode 100644 index 0000000000000000000000000000000000000000..fcf4dfd12adb36ff216d1a126aaa9270a76ae29a --- /dev/null +++ b/src/main/java/de/hft/stuttgart/lgl/ifc/controller/ConverterEndpoints.java @@ -0,0 +1,106 @@ +package de.hft.stuttgart.lgl.ifc.controller; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import javax.servlet.http.HttpServletRequest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; + +@CrossOrigin +@RestController +public class ConverterEndpoints { + + @Value("${converter.executable}") + private String converterExecutable; + + @Autowired + public ConverterEndpoints() { + // constructor for injection + } + + private static final Logger logger = LoggerFactory.getLogger(ConverterEndpoints.class); + + @PostMapping(path = "/convert",produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public ResponseEntity checkAddress(@RequestParam("file") MultipartFile file, + HttpServletRequest request) { + logger.info("Convert request: {}", file.getOriginalFilename()); + + UUID id = UUID.randomUUID(); + Path workFolder = Paths.get("work"); + Path ifcFile = workFolder.resolve(id.toString() + ".ifc"); + Path output = workFolder.resolve(id.toString() + ".glb"); + try { + Files.createDirectories(workFolder); + Files.copy(file.getInputStream(), ifcFile); + List commands = new ArrayList<>(); + commands.add(converterExecutable); + commands.add(ifcFile.toAbsolutePath().toString()); + commands.add(output.toAbsolutePath().toString()); + ProcessBuilder processBuilder = new ProcessBuilder(commands); + Process process = processBuilder.start(); + Thread t = new Thread(() -> { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line = reader.readLine(); + while (line != null) { + line = reader.readLine(); + } + } catch (IOException e) { + } + }); + t.setDaemon(true); + t.start(); + process.waitFor(10, TimeUnit.MINUTES); + int exitValue = process.exitValue(); + logger.info("Converter exit code for file {} is {}", file.getOriginalFilename(), exitValue); + Files.delete(ifcFile); + String originalFileName = file.getOriginalFilename(); + if (originalFileName == null) { + originalFileName = "converted.ifc"; + } + String outputFileName = originalFileName.substring(0, originalFileName.lastIndexOf('.')) + ".glb"; + return ResponseEntity.ok().contentType(MediaType.parseMediaType("application/octet-stream")) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + outputFileName + "\"") + .body(new StreamingResponseBody() { + @Override + public void writeTo(OutputStream outputStream) throws IOException { + try { + Files.copy(output, outputStream); + } finally { + Files.delete(output); + } + } + }); + } catch (IOException | InterruptedException e) { + logger.error("Failed to convert file: {}", file.getOriginalFilename(), e); + try { + Files.delete(output); + Files.delete(ifcFile); + } catch (IOException ex) { + } + return ResponseEntity.internalServerError().build(); + } + } + +} diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties new file mode 100644 index 0000000000000000000000000000000000000000..d27ed46722aa89f372c14146fd88b61ce092c795 --- /dev/null +++ b/src/main/resources/application-dev.properties @@ -0,0 +1,16 @@ +converter.executable=ifcConvert.exe + +server.port=50000 +logging.file.name=backend-converter.log +logging.level.root=info +logging.logback.rollingpolicy.file-name-pattern=backend-converter-%d{yyyy-MM-dd}.%i.gz +logging.logback.rollingpolicy.max-file-size=10MB + +# Enable multipart uploads +spring.servlet.multipart.enabled=true +# Threshold after which files are written to disk. +spring.servlet.multipart.file-size-threshold=5MB +# Max file size. +spring.servlet.multipart.max-file-size=2000MB +# Max Request Size +spring.servlet.multipart.max-request-size=2000MB diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties new file mode 100644 index 0000000000000000000000000000000000000000..432cb74409ca7f0e27ffc5670f6bbaa3e117cd5b --- /dev/null +++ b/src/main/resources/application-prod.properties @@ -0,0 +1,16 @@ +converter.executable=./IfcConvert + +server.port=50000 +logging.file.name=backend-converter.log +logging.level.root=info +logging.logback.rollingpolicy.file-name-pattern=backend-converter-%d{yyyy-MM-dd}.%i.gz +logging.logback.rollingpolicy.max-file-size=10MB + +# Enable multipart uploads +spring.servlet.multipart.enabled=true +# Threshold after which files are written to disk. +spring.servlet.multipart.file-size-threshold=50MB +# Max file size. +spring.servlet.multipart.max-file-size=2000MB +# Max Request Size +spring.servlet.multipart.max-request-size=2000MB diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000000000000000000000000000000000000..257b30648523ed1765c075c8903efdea33a7a5c2 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.profiles.active=dev \ No newline at end of file