com.github.wnameless.spring.bulkapi.DefaultBulkApiService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-bulk-api Show documentation
Show all versions of spring-bulk-api Show documentation
Add bulk operations support to any Spring RESTful API by a single annotation @EnableBulkApi.
/*
*
* Copyright 2016 Wei-Ming Wu
*
* 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 com.github.wnameless.spring.bulkapi;
import static org.springframework.http.HttpStatus.PAYLOAD_TOO_LARGE;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.RequestEntity.BodyBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
/**
*
* {@link DefaultBulkApiService} id the default implementation of
* {@link BulkApiService}.
*
*/
public class DefaultBulkApiService implements BulkApiService {
private final ApplicationContext appCtx;
private final Environment env;
private BulkApiValidator validator;
/**
* Creates a {@link DefaultBulkApiService}.
*
* @param appCtx
* the Spring {@link ApplicationContext}
*/
public DefaultBulkApiService(ApplicationContext appCtx) {
this.appCtx = appCtx;
env = appCtx.getEnvironment();
}
@PostConstruct
private void afterConstruct() {
validator = new BulkApiValidator(appCtx);
}
@Override
public BulkResponse bulk(BulkRequest req, HttpServletRequest servReq) {
validateBulkRequest(req, servReq);
List results = new ArrayList();
RestTemplate template = new RestTemplate();
for (BulkOperation op : req.getOperations()) {
BodyBuilder bodyBuilder = RequestEntity.method(//
httpMethod(op.getMethod()), computeUri(servReq, op));
ResponseEntity rawRes =
template.exchange(requestEntity(bodyBuilder, op), String.class);
if (!op.isSilent()) results.add(buldResult(rawRes));
}
return new BulkResponse(results);
}
private RequestEntity> requestEntity(
BodyBuilder bodyBuilder, BulkOperation op) {
for (Entry header : op.getHeaders().entrySet()) {
bodyBuilder.header(header.getKey(), header.getValue());
}
MultiValueMap params =
new LinkedMultiValueMap();
for (Entry param : op.getParams().entrySet()) {
params.add(param.getKey(), param.getValue());
}
return bodyBuilder.body(params);
}
private URI computeUri(HttpServletRequest servReq, BulkOperation op) {
String rawUrl = servReq.getRequestURL().toString();
String rawUri = servReq.getRequestURI().toString();
if (op.getUrl() == null || isBulkPath(op.getUrl())) {
throw new BulkApiException(UNPROCESSABLE_ENTITY,
"Invalid URL(" + rawUri + ") exists in this bulk request");
}
URI uri;
try {
String servletPath = rawUrl.substring(0, rawUrl.indexOf(rawUri));
uri = new URI(servletPath + urlify(op.getUrl()));
} catch (URISyntaxException e) {
throw new BulkApiException(UNPROCESSABLE_ENTITY, "Invalid URL("
+ urlify(op.getUrl()) + ") exists in this bulk request");
}
if (!validator.validatePath(urlify(op.getUrl()),
httpMethod(op.getMethod()))) {
throw new BulkApiException(UNPROCESSABLE_ENTITY, "Invalid URL("
+ urlify(op.getUrl()) + ") exists in this bulk request");
}
return uri;
}
private boolean isBulkPath(String url) {
String bulkPath = urlify(env.getProperty("spring.bulk.api.path", "/bulk"));
url = urlify(url);
return url.equals(bulkPath) || url.startsWith(bulkPath + "/");
}
private String urlify(String url) {
url = url.trim();
return url.startsWith("/") ? url : "/" + url;
}
private BulkResult buldResult(ResponseEntity rawRes) {
BulkResult res = new BulkResult();
res.setStatus(Short.valueOf(rawRes.getStatusCode().toString()));
res.setHeaders(rawRes.getHeaders().toSingleValueMap());
res.setBody(rawRes.getBody());
return res;
}
private void validateBulkRequest(BulkRequest req,
HttpServletRequest servReq) {
int max = env.getProperty("spring.bulk.api.limit", int.class, 100);
if (req.getOperations().size() > max) {
throw new BulkApiException(PAYLOAD_TOO_LARGE,
"Bulk operations exceed the limitation(" + max + ")");
}
// Check if any invalid URL exists
for (BulkOperation op : req.getOperations()) {
computeUri(servReq, op);
}
}
private static HttpMethod httpMethod(String method) {
try {
return HttpMethod.valueOf(method.toUpperCase());
} catch (Exception e) {
return HttpMethod.GET;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy