Skip to content

Commit

Permalink
Creation of a sample JODConverter Rest API using spring boot.
Browse files Browse the repository at this point in the history
  • Loading branch information
sbraconnier committed Jan 25, 2018
1 parent 548f74a commit 20d4430
Show file tree
Hide file tree
Showing 7 changed files with 359 additions and 1 deletion.
22 changes: 22 additions & 0 deletions jodconverter-samples/jodconverter-sample-rest/README.md
@@ -0,0 +1,22 @@
## JODConverter - Sample - Rest API

This is a sample application of a rest api that uses the spring boot integration module of the Java OpenDocument Converter (JODConverter) project to offer document conversion capabilities. The goal was to emulate a LibreOffice Online server that
would support the customization of custom (known) load/store properties.

### Running the Project using gradle

First, [build the entire jodconverter project](https://github.com/sbraconnier/jodconverter#building-the-project)

Then, run

```Shell
gradlew :jodconverter-samples:jodconverter-sample-rest:bootRun
```

Once started, use your favorite browser and visit this page:

```
http://localhost:8080/swagger-ui.html
```

Happy conversions!!
34 changes: 34 additions & 0 deletions jodconverter-samples/jodconverter-sample-rest/build.gradle
@@ -0,0 +1,34 @@
description = 'JODConverter - Sample Rest Web Api'

buildscript {
ext {
// Latest version -> https://mvnrepository.com/artifact/org.springframework.boot/spring-boot
springBootVersion = '1.5.9.RELEASE'
swaggerVersion = '2.8.0'
}
repositories {
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
}
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
compile project(':jodconverter-spring-boot-starter')
compile 'org.springframework.boot:spring-boot-starter-web'
compile "io.springfox:springfox-swagger2:$swaggerVersion"
compile "io.springfox:springfox-swagger-ui:$swaggerVersion"
}
@@ -0,0 +1,214 @@
/*
* Copyright 2004 - 2012 Mirko Nasato and contributors
* 2016 - 2017 Simon Braconnier and contributors
*
* This file is part of JODConverter - Java OpenDocument Converter.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jodconverter.sample.springboot;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import org.jodconverter.DocumentConverter;
import org.jodconverter.LocalConverter;
import org.jodconverter.document.DefaultDocumentFormatRegistry;
import org.jodconverter.document.DocumentFormat;
import org.jodconverter.office.OfficeException;
import org.jodconverter.office.OfficeManager;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;

/**
* Controller that will process conversion requests. The mapping is the same as LibreOffice Online
* (/lool/convert-to) so we can use the jodconverter-online module to send request to this
* controller. This controller does the same as LibreOffice Online, and also support custom
* conversions through filters and custom load/store properties.
*/
@Controller
@RequestMapping("/lool/convert-to")
@Api("Conversion Operations which emulate a LibreOffice Online server conversion capabilities.")
public class ConverterController {

private static final Logger LOGGER = LoggerFactory.getLogger(ConverterController.class);

private final OfficeManager officeManager;
private final DocumentConverter defaultConverter;

/**
* Creates a new controller.
*
* @param officeManager The manager used to execute conversions.
* @param defaultConverter The default converter used to execute conversions.
*/
public ConverterController(
final OfficeManager officeManager, final DocumentConverter defaultConverter) {
super();

this.officeManager = officeManager;
this.defaultConverter = defaultConverter;
}

@ApiOperation(
"Convert the incoming document to the specified format (provided as request param) and returns the converted document.")
@ApiResponses(
value = {
@ApiResponse(code = 200, message = "Document converted successfully."),
@ApiResponse(code = 400, message = "The input document or output format is missing."),
@ApiResponse(code = 500, message = "An unexpected error occured.")
}
)
@PostMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Object convertToUsingParam(
@ApiParam(value = "The input document to convert.", required = true) @RequestParam("data")
final MultipartFile inputFile,
@ApiParam(value = "The document format to convert the input document to.", required = true)
@RequestParam(name = "format")
final String convertToFormat,
@ApiParam(value = "The custom FilterOptions to apply when loading the input document.")
@RequestParam(name = "loadOptions", required = false)
final String loadOptions,
@ApiParam(value = "The custom FilterOptions to apply when storing the output document.")
@RequestParam(name = "storeOptions", required = false)
final String storeOptions) {

LOGGER.debug("convertUsingRequestParam > Converting file to {}", convertToFormat);
return convert(inputFile, convertToFormat, loadOptions, storeOptions);
}

@ApiOperation(
"Convert the incoming document to the specified format (provided as path param) and returns the converted document.")
@ApiResponses(
value = {
@ApiResponse(code = 200, message = "Document converted successfully."),
@ApiResponse(code = 400, message = "The input document or output format is missing."),
@ApiResponse(code = 500, message = "An unexpected error occured.")
}
)
@PostMapping(value = "/{format}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Object convertToUsingPath(
@ApiParam(value = "The input document to convert.", required = true) @RequestParam("data")
final MultipartFile inputFile,
@ApiParam(value = "The document format to convert the input document to.", required = true)
@PathVariable(name = "format")
final String convertToFormat,
@ApiParam(value = "The custom FilterOptions to apply when loading the input document.")
@RequestParam(name = "loadOptions", required = false)
final String loadOptions,
@ApiParam(value = "The custom FilterOptions to apply when storing the output document.")
@RequestParam(name = "storeOptions", required = false)
final String storeOptions) {

LOGGER.debug("convertUsingPathVariable > Converting file to {}", convertToFormat);
return convert(inputFile, convertToFormat, loadOptions, storeOptions);
}

private ResponseEntity<Object> convert(
final MultipartFile inputFile,
final String outputFormat,
final String loadOptions,
final String storeOptions) {

if (inputFile.isEmpty()) {
return ResponseEntity.badRequest().build();
}

if (StringUtils.isBlank(outputFormat)) {
return ResponseEntity.badRequest().build();
}

// Here, we could have a dedicated service that would convert document
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

final DocumentFormat targetFormat =
DefaultDocumentFormatRegistry.getFormatByExtension(outputFormat);

final Map<String, Object> loadProperties =
Optional.ofNullable(loadOptions)
.filter(StringUtils::isNotBlank)
.map(
options ->
Stream.of(options)
.collect(
Collectors.toMap(opts -> "FilterOptions", opts -> (Object) opts)))
.orElse(null);

final Map<String, Object> storeProperties =
Optional.ofNullable(storeOptions)
.filter(StringUtils::isNotBlank)
.map(
options ->
Stream.of(options)
.collect(
Collectors.toMap(opts -> "FilterOptions", opts -> (Object) opts)))
.orElse(null);

final DocumentConverter converter =
loadProperties == null && storeProperties == null
? defaultConverter
: LocalConverter.builder()
.officeManager(officeManager)
.loadProperties(storeProperties)
.storeProperties(storeProperties)
.build();

// Convert...
converter
.convert(inputFile.getInputStream())
.as(
DefaultDocumentFormatRegistry.getFormatByExtension(
FilenameUtils.getExtension(inputFile.getOriginalFilename())))
.to(baos)
.as(targetFormat)
.execute();

final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(targetFormat.getMediaType()));
headers.add(
"Content-Disposition",
"attachment; filename="
+ FilenameUtils.getBaseName(inputFile.getOriginalFilename())
+ "."
+ targetFormat.getExtension());
return ResponseEntity.ok().headers(headers).body(baos.toByteArray());

} catch (OfficeException | IOException ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex);
}
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2004 - 2012 Mirko Nasato and contributors
* 2016 - 2017 Simon Braconnier and contributors
*
* This file is part of JODConverter - Java OpenDocument Converter.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jodconverter.sample.springboot;

import java.util.Collections;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
public class SpringBootRestApplication {

public static void main(final String[] args) {
SpringApplication.run(SpringBootRestApplication.class, args);
}

@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("org.jodconverter.sample.springboot"))
.paths(PathSelectors.regex("/lool/convert-to.*"))
.build()
.apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
return new ApiInfo(
"JODConverter REST API",
"JODConverter REST API for Online conversion. JODConverter automates conversions between office document formats using LibreOffice or Apache OpenOffice.",
"0.1",
"Terms of service",
new Contact("John Doe", "www.jodconverter.org", "johndoe@company.com"),
"Apache License Version 2.0",
"https://www.apache.org/licenses/LICENSE-2.0",
Collections.emptyList());
}
}
}
@@ -0,0 +1,17 @@
server:
port: 8080

spring:
http:
multipart:
max-file-size: 5MB
max-request-size: 10MB
application:
name: JODConverter Sample Rest Api

jodconverter:
enabled: true

logging:
level:
root: debug
Expand Up @@ -3,7 +3,7 @@ description = 'JODConverter - Sample Spring Boot Web Application'
buildscript {
ext {
// Latest version -> https://mvnrepository.com/artifact/org.springframework.boot/spring-boot
springBootVersion = '1.5.8.RELEASE'
springBootVersion = '1.5.9.RELEASE'
}
repositories {
mavenCentral()
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Expand Up @@ -7,6 +7,7 @@ String[] modules = [
'jodconverter-cli',
'jodconverter-spring',
'jodconverter-spring-boot-starter',
'jodconverter-samples:jodconverter-sample-rest',
'jodconverter-samples:jodconverter-sample-spring-boot',
'jodconverter-samples:jodconverter-sample-webapp'
]
Expand Down

0 comments on commit 20d4430

Please sign in to comment.