
edu.amherst.acdc.exts.image.ImageRouter Maven / Gradle / Ivy
/*
* Copyright Amherst College
*
* 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 edu.amherst.acdc.exts.image;
import static java.util.Arrays.stream;
import static org.apache.camel.Exchange.CONTENT_TYPE;
import static org.apache.camel.Exchange.HTTP_METHOD;
import static org.apache.camel.Exchange.HTTP_RESPONSE_CODE;
import static org.apache.camel.Exchange.HTTP_URI;
import static org.apache.camel.LoggingLevel.INFO;
import static org.apache.camel.builder.PredicateBuilder.and;
import static org.apache.camel.component.exec.ExecBinding.EXEC_COMMAND_ARGS;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashSet;
import org.apache.camel.Exchange;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.builder.RouteBuilder;
import org.slf4j.Logger;
/**
* A content router for handling image conversion requests.
*
* @author Aaron Coburn
*/
public class ImageRouter extends RouteBuilder {
private static final String FEDORA_BASE_URL = "CamelFedoraBaseUrl";
private static final String FEDORA_URI = "CamelFedoraUri";
private static final String IMAGE_OUTPUT = "CamelImageOutput";
private static final String IMAGE_INPUT = "CamelImageInput";
private static final String HTTP_ACCEPT = "Accept";
private static final String HTTP_QUERY_OPTIONS = "options";
private static final String HTTP_QUERY_CONTEXT = "context";
private static final Logger LOGGER = getLogger(ImageRouter.class);
/**
* Configure the message route workflow.
*/
public void configure() throws Exception {
from("jetty:http://{{rest.host}}:{{rest.port}}{{rest.prefix}}?" +
"sendServerVersion=false&" +
"httpMethodRestrict=GET,OPTIONS").routeId("ImageRouter")
.process(e -> e.getIn().setHeader(FEDORA_URI,
e.getIn().getHeader(HTTP_QUERY_CONTEXT,
e.getIn().getHeader("Apix-Ldp-Resource"))))
.setHeader(FEDORA_BASE_URL).simple("{{fcrepo.baseUrl}}")
.setHeader(IMAGE_OUTPUT).header(HTTP_ACCEPT)
.removeHeaders(HTTP_ACCEPT)
.choice()
.when(and(header(HTTP_METHOD).isEqualTo("GET"), header(FEDORA_URI).startsWith(header(FEDORA_BASE_URL))))
.to("direct:get")
.when(header(HTTP_METHOD).isEqualTo("OPTIONS"))
.setHeader(CONTENT_TYPE).constant("text/turtle")
.setHeader(HTTP_ACCEPT).constant("GET,OPTIONS")
.to("language:simple:resource:classpath:options.ttl")
.otherwise()
.setHeader(HTTP_RESPONSE_CODE).constant(400)
.setHeader(CONTENT_TYPE).constant("text/plain")
.transform(constant("Missing/invalid context parameter"));
from("direct:get").routeId("ImageGet")
.setHeader(HTTP_URI).header(FEDORA_URI)
.setHeader(HTTP_METHOD).constant("HEAD")
.to("http4://localhost?authUsername={{fcrepo.authUsername}}" +
"&authPassword={{fcrepo.authPassword}}&throwExceptionOnFailure=false")
.choice()
.when(header(CONTENT_TYPE).startsWith("image/"))
.log(INFO, LOGGER, "Image Processing ${headers[CamelHttpPath]}")
.to("direct:convert")
.when(header("Link").contains(";rel=\"type\""))
.setBody(constant("Error: this resource is not an image"))
.to("direct:invalidFormat")
.when(header(HTTP_RESPONSE_CODE).isEqualTo(200))
.setBody(constant("Error: this resource is not an ldp:NonRDFSource"))
.to("direct:invalidFormat")
.otherwise()
.to("direct:error");
from("direct:invalidFormat").routeId("ImageInvalidFormat")
.removeHeaders("*")
.setHeader(CONTENT_TYPE).constant("text/plain")
.setHeader(HTTP_RESPONSE_CODE).constant(400);
from("direct:error").routeId("ImageError")
.setBody(constant("Error: this resource is not accessible"))
.setHeader(CONTENT_TYPE).constant("text/plain");
from("direct:convert").routeId("ImageConvert")
.setHeader(HTTP_METHOD).constant("GET")
.setHeader(HTTP_URI).header(FEDORA_URI)
.to("http4://localhost?authUsername={{fcrepo.authUsername}}" +
"&authPassword={{fcrepo.authPassword}}&throwExceptionOnFailure=true")
.setHeader(IMAGE_INPUT).header(CONTENT_TYPE)
.process(exchange -> {
final String accept = exchange.getIn().getHeader(IMAGE_OUTPUT, "", String.class);
final String fmt;
final boolean valid;
try {
if (accept.matches("^image/\\w+$")) {
fmt = accept.replace("image/", "");
} else {
fmt = getContext().resolvePropertyPlaceholders("{{default.format}}");
}
valid = stream(getContext().resolvePropertyPlaceholders("{{valid.formats}}").split(","))
.anyMatch(fmt::equals);
} catch (final Exception ex) {
throw new RuntimeCamelException("Couldn't resolve property placeholder", ex);
}
if (valid) {
exchange.getIn().setHeader(IMAGE_OUTPUT, "image/" + fmt);
exchange.getIn().setHeader(EXEC_COMMAND_ARGS,
" - " + cmdOptions(exchange) + " " + fmt + ":-");
} else {
throw new RuntimeCamelException("Invalid format: " + fmt);
}
})
.removeHeaders("CamelHttp*")
.log(INFO, LOGGER, "Converting from ${headers[CamelImageInput]} to ${headers[CamelImageOutput]}")
.to("exec:{{convert.path}}")
.process(exchange ->
exchange.getOut().setBody(exchange.getIn().getBody(InputStream.class)));
}
// Hack - cmdline options are often an array of repeated elements. Fix that
@SuppressWarnings("unchecked")
static final String cmdOptions(final Exchange e) {
final Object optHdr = e.getIn().getHeader(HTTP_QUERY_OPTIONS);
if (optHdr instanceof Collection) {
return String.join(" ", new HashSet<>((Collection) optHdr));
} else if (optHdr != null) {
return (String) optHdr;
}
return "";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy