All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.language.datasonnet.DatasonnetExpression Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.camel.language.datasonnet;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import com.datasonnet.Mapper;
import com.datasonnet.MapperBuilder;
import com.datasonnet.document.DefaultDocument;
import com.datasonnet.document.Document;
import com.datasonnet.document.MediaType;
import com.datasonnet.document.MediaTypes;
import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.RuntimeExpressionException;
import org.apache.camel.spi.ExpressionResultTypeAware;
import org.apache.camel.support.ExchangeHelper;
import org.apache.camel.support.ExpressionAdapter;
import org.apache.camel.support.MessageHelper;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DatasonnetExpression extends ExpressionAdapter implements ExpressionResultTypeAware {
    private static final Logger LOG = LoggerFactory.getLogger(DatasonnetExpression.class);

    private String expression;
    private Expression metaExpression;
    private MediaType bodyMediaType;
    private MediaType outputMediaType;
    private Class resultType;
    private Collection libraryPaths;

    public DatasonnetExpression(String expression) {
        this.expression = expression;
    }

    public DatasonnetExpression(Expression expression) {
        this.metaExpression = expression;
    }

    public static DatasonnetExpression builder(String expression) {
        DatasonnetExpression answer = new DatasonnetExpression(expression);
        return answer;
    }

    public static DatasonnetExpression builder(Expression expression) {
        DatasonnetExpression answer = new DatasonnetExpression(expression);
        return answer;
    }

    public static DatasonnetExpression builder(String expression, Class resultType) {
        DatasonnetExpression answer = new DatasonnetExpression(expression);
        answer.setResultType(resultType);
        return answer;
    }

    public static DatasonnetExpression builder(Expression expression, Class resultType) {
        DatasonnetExpression answer = new DatasonnetExpression(expression);
        answer.setResultType(resultType);
        return answer;
    }

    @Override
    public boolean matches(Exchange exchange) {
        this.outputMediaType = MediaTypes.APPLICATION_JAVA;
        return evaluate(exchange, Boolean.class);
    }

    @SuppressWarnings("unchecked")
    @Override
    public  T evaluate(Exchange exchange, Class type) {
        try {
            if (metaExpression != null) {
                expression = metaExpression.evaluate(exchange, String.class);
            }

            Objects.requireNonNull(expression, "String expression property must be set!");

            Document result = doEvaluate(exchange);
            if (!type.equals(Object.class)) {
                return ExchangeHelper.convertToType(exchange, type, result.getContent());
            } else if (resultType == null || resultType.equals(Document.class)) {
                return (T) result;
            } else {
                return (T) result.getContent();
            }
        } catch (Exception e) {
            throw new RuntimeExpressionException("Unable to evaluate DataSonnet expression: " + expression, e);
        } finally {
            CML.getInstance().getExchange().remove();
        }
    }

    private Document doEvaluate(Exchange exchange) {
        if (bodyMediaType == null) {
            //Try to auto-detect input mime type if it was not explicitly set
            String typeHeader = exchange.getProperty(DatasonnetConstants.BODY_MEDIATYPE,
                    exchange.getIn().getHeader(Exchange.CONTENT_TYPE), String.class);
            if (typeHeader != null) {
                bodyMediaType = MediaType.valueOf(typeHeader);
            }
        }

        Document body;
        if (exchange.getMessage().getBody() instanceof Document) {
            body = (Document) exchange.getMessage().getBody();
        } else if (MediaTypes.APPLICATION_JAVA.equalsTypeAndSubtype(bodyMediaType)) {
            body = new DefaultDocument<>(exchange.getMessage().getBody());
        } else {
            body = new DefaultDocument<>(MessageHelper.extractBodyAsString(exchange.getMessage()), bodyMediaType);
        }

        Map> inputs = Collections.singletonMap("body", body);

        DatasonnetLanguage language = (DatasonnetLanguage) exchange.getContext().resolveLanguage("datasonnet");
        Mapper mapper = language.computeIfMiss(expression, () -> new MapperBuilder(expression)
                .withInputNames(inputs.keySet())
                .withImports(resolveImports(language))
                .withLibrary(CML.getInstance())
                .withDefaultOutput(MediaTypes.APPLICATION_JAVA)
                .build());

        // pass exchange to CML lib using thread as context
        CML.getInstance().getExchange().set(exchange);

        if (outputMediaType == null) {
            //Try to auto-detect output mime type if it was not explicitly set
            String typeHeader = exchange.getProperty(DatasonnetConstants.OUTPUT_MEDIATYPE,
                    exchange.getIn().getHeader(DatasonnetConstants.OUTPUT_MEDIATYPE), String.class);
            if (typeHeader != null) {
                outputMediaType = MediaType.valueOf(typeHeader);
            } else {
                outputMediaType = MediaTypes.ANY;
            }
        }

        if (resultType == null || resultType.equals(Document.class)) {
            return mapper.transform(body, inputs, outputMediaType, Object.class);
        } else {
            return mapper.transform(body, inputs, outputMediaType, resultType);
        }
    }

    private Map resolveImports(DatasonnetLanguage language) {
        if (libraryPaths == null) {
            return language.getClasspathImports();
        }

        Map answer = new HashMap<>();
        LOG.debug("Explicit library path is: {}", libraryPaths);
        for (String nextPath : libraryPaths) {
            final File nextLibDir = new File(nextPath);
            if (nextLibDir.isDirectory()) {
                try {
                    Files.walkFileTree(nextLibDir.toPath(), new SimpleFileVisitor() {
                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                            File f = file.toFile();
                            if (!f.isDirectory() && f.getName().toLowerCase().endsWith(".libsonnet")) {
                                String content = IOUtils.toString(file.toUri(), Charset.defaultCharset());
                                Path relative = nextLibDir.toPath().relativize(file);
                                LOG.debug("Loading DataSonnet library: {}", relative);
                                answer.put(relative.toString(), content);
                            }
                            return FileVisitResult.CONTINUE;
                        }
                    });
                } catch (IOException e) {
                    LOG.warn("Unable to load DataSonnet library from: " + nextPath, e);
                }
            }
        }

        return answer;
    }

    // Getter/Setter methods
    // -------------------------------------------------------------------------

    public MediaType getBodyMediaType() {
        return bodyMediaType;
    }

    /**
     * The message's body MediaType
     */
    public void setBodyMediaType(MediaType inputMimeType) {
        this.bodyMediaType = inputMimeType;
    }

    public MediaType getOutputMediaType() {
        return outputMediaType;
    }

    /**
     * The MediaType to output
     */
    public void setOutputMediaType(MediaType outputMimeType) {
        this.outputMediaType = outputMimeType;
    }

    public Collection getLibraryPaths() {
        return libraryPaths;
    }

    /**
     * The paths to search for .libsonnet files
     */
    public void setLibraryPaths(Collection libraryPaths) {
        this.libraryPaths = libraryPaths;
    }

    @Override
    public String getExpressionText() {
        return this.expression;
    }

    @Override
    public Class getResultType() {
        return this.resultType;
    }

    /**
     * Sets the class of the result type (type from output).
     * 

* The default result type is com.datasonnet.document.Document */ public void setResultType(Class targetType) { this.resultType = targetType; } // Fluent builder methods // ------------------------------------------------------------------------- public DatasonnetExpression bodyMediaType(MediaType bodyMediaType) { setBodyMediaType(bodyMediaType); return this; } public DatasonnetExpression outputMediaType(MediaType outputMediaType) { setOutputMediaType(outputMediaType); return this; } @Override public String toString() { return "datasonnet: " + expression; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy