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

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

The newest version!
/*
 * 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.Set;

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 com.datasonnet.header.Header;
import com.datasonnet.spi.Library;
import org.apache.camel.CamelContext;
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.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 final String expression;
    private Expression source;
    private MediaType bodyMediaType;
    private MediaType outputMediaType;
    private Class resultType;
    private Collection libraryPaths;
    private transient DatasonnetLanguage language;

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

    @Deprecated
    public static DatasonnetExpression builder(String expression) {
        return new DatasonnetExpression(expression);
    }

    @Deprecated
    public static DatasonnetExpression builder(String 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 {
            // pass exchange to CML lib using thread as context
            CML.getInstance().getExchange().set(exchange);

            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) {
        MediaType bodyMT = bodyMediaType;
        if (bodyMT == null && !expression.startsWith(Header.DATASONNET_HEADER)) {
            //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) {
                bodyMT = MediaType.valueOf(typeHeader);
            }
        }

        Object payload = source != null ? source.evaluate(exchange, Object.class) : exchange.getMessage().getBody();
        Document doc = null;
        if (payload != null) {
            doc = exchange.getContext().getTypeConverter().tryConvertTo(Document.class, exchange, payload);
        }
        if (doc == null) {
            String text = exchange.getContext().getTypeConverter().tryConvertTo(String.class, exchange, payload);
            if (exchange.getMessage().getBody() == null || "".equals(text)) {
                //Empty body, force type to be application/java
                doc = new DefaultDocument<>("", MediaTypes.APPLICATION_JAVA);
            } else if (MediaTypes.APPLICATION_JAVA.equalsTypeAndSubtype(bodyMT) || bodyMT == null) {
                doc = new DefaultDocument<>(payload);
            } else {
                // force using string value
                doc = new DefaultDocument<>(text, bodyMT);
            }
        }

        // the mapper is pre initialized but can become empty
        Mapper mapper = language.computeIfMiss(expression, () -> {
            MapperBuilder builder = new MapperBuilder(expression)
                    .withInputNames("body")
                    .withImports(resolveImports(language))
                    .withLibrary(CML.getInstance())
                    .withDefaultOutput(MediaTypes.APPLICATION_JAVA);

            Set additionalLibraries = exchange.getContext().getRegistry().findByType(com.datasonnet.spi.Library.class);
            for (Library lib : additionalLibraries) {
                builder = builder.withLibrary(lib);
            }
            return builder.build();
        });

        MediaType outMT = outputMediaType;
        if (outMT == 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) {
                outMT = MediaType.valueOf(typeHeader);
            } else {
                outMT = MediaTypes.ANY;
            }
        }

        Map> inputs = Collections.singletonMap("body", doc);
        if (resultType == null || resultType.equals(Document.class)) {
            return mapper.transform(doc, inputs, outMT, Object.class);
        } else {
            return mapper.transform(doc, inputs, outMT, 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;
    }

    @Override
    public void init(CamelContext context) {
        super.init(context);

        language = (DatasonnetLanguage) context.resolveLanguage("datasonnet");
        // initialize mapper eager
        language.computeIfMiss(expression, () -> {
            MapperBuilder builder = new MapperBuilder(expression)
                    .withInputNames("body")
                    .withImports(resolveImports(language))
                    .withLibrary(CML.getInstance())
                    .withDefaultOutput(MediaTypes.APPLICATION_JAVA);

            Set additionalLibraries = context.getRegistry().findByType(com.datasonnet.spi.Library.class);
            for (Library lib : additionalLibraries) {
                builder = builder.withLibrary(lib);
            }
            return builder.build();
        });
    }

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

    public Expression getSource() {
        return source;
    }

    public void setSource(Expression source) {
        this.source = source;
    }

    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 // ------------------------------------------------------------------------- @Deprecated public DatasonnetExpression bodyMediaType(MediaType bodyMediaType) { setBodyMediaType(bodyMediaType); return this; } @Deprecated public DatasonnetExpression outputMediaType(MediaType outputMediaType) { setOutputMediaType(outputMediaType); return this; } @Override public String toString() { return "datasonnet: " + expression; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy