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

org.wisdom.maven.osgi.DependencyEmbedder Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * Wisdom-Framework
 * %%
 * Copyright (C) 2013 - 2014 Wisdom Framework
 * %%
 * 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.
 * #L%
 */
package org.wisdom.maven.osgi;

import aQute.bnd.osgi.Constants;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.shared.artifact.filter.PatternExcludesArtifactFilter;
import org.apache.maven.shared.artifact.filter.PatternIncludesArtifactFilter;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

/**
 * A class responsible for computing the instructions for the `Embed-Dependency` clauses.
 */
public class DependencyEmbedder {

    /**
     * Embed Dependency instruction.
     */
    public static final String EMBED_DEPENDENCY = "Embed-Dependency";

    /**
     * Embed Transitive instruction.
     */
    public static final String EMBED_TRANSITIVE = "Embed-Transitive";

    private final boolean embedTransitive;
    private final Reporter reporter;

    private List embedded = new ArrayList<>();

    /**
     * Creates an instance of {@link org.wisdom.maven.osgi.DependencyEmbedder}.
     *
     * @param instructions the current set of instructions
     * @param reporter     the reporter
     */
    public DependencyEmbedder(Properties instructions, Reporter reporter) {
        this.reporter = reporter;
        String embedDependencyHeader = instructions.getProperty(EMBED_DEPENDENCY);
        embedTransitive = "true".equalsIgnoreCase(instructions.getProperty(EMBED_TRANSITIVE));
        if (!Strings.isNullOrEmpty(embedDependencyHeader)) {
            parse(embedDependencyHeader);
        }

    }

    private void parse(String embedDependencyHeader) {
        List inst = Splitter.on(",").omitEmptyStrings().trimResults().splitToList(embedDependencyHeader);
        for (String s : inst) {
            embedded.add(parseIndividual(s));
        }
    }

    private EmbeddedDependency parseIndividual(String s) {
        List segments = Splitter.on(";").omitEmptyStrings().trimResults().splitToList(s);
        if (segments.isEmpty()) {
            // Broken instruction
            reporter.error("Incorrect Embed-Dependency clause : " + s);
            return null;
        }

        EmbeddedDependency configuration = new EmbeddedDependency(s);
        AndArtifactFilter filter = new AndArtifactFilter();
        configuration.setFilter(filter);

        filter.add(new PatternIncludesArtifactFilter(ImmutableList.of(segments.get(0)), embedTransitive));
        for (int i = 1; i < segments.size(); i++) {
            List inc = Splitter.on("=").limit(2).omitEmptyStrings().trimResults().splitToList(segments.get(i));
            if (inc.size() != 2) {
                throw new IllegalArgumentException("Malformed embed dependency clause: " + segments.get(i));
            }
            String attribute = inc.get(0);
            String value = inc.get(1);

            if ("scope".equalsIgnoreCase(attribute)) {
                final List values = getMultiValues(value);
                filter.add(new ArtifactFilter() {
                    @Override
                    public boolean include(Artifact artifact) {
                        return values.contains(artifact.getScope()); //NOSONAR
                    }
                });
            }

            if ("exclude".equalsIgnoreCase(attribute)) {
                filter.add(new PatternExcludesArtifactFilter(getMultiValues(value)));
            }

            if ("type".equalsIgnoreCase(attribute)) {
                final List values = getMultiValues(value);
                filter.add(new ArtifactFilter() {
                    @Override
                    public boolean include(Artifact artifact) {
                        return values.contains(artifact.getType()); //NOSONAR
                    }
                });
            }

            if ("optional".equalsIgnoreCase(attribute)) {
                final boolean v = Boolean.parseBoolean(value);
                filter.add(new ArtifactFilter() {
                    @Override
                    public boolean include(Artifact artifact) {
                        return artifact.isOptional() == v;
                    }
                });
            }

            if ("transitive".equalsIgnoreCase(attribute)) {
                final boolean v = Boolean.parseBoolean(value);
                configuration.setTransitive(v);
            }

            if ("inline".equalsIgnoreCase(attribute)) {
                configuration.setInline(value);
            }
        }

        return configuration;
    }

    private List getMultiValues(String value) {
        return Splitter.on('|').trimResults().omitEmptyStrings().splitToList(value);
    }

    /**
     * Generates the new set of instruction containing the original set of instructions enhanced with the embed
     * dependencies results.
     *
     * @param instructions the current set of instructions
     * @param dependencies the project's dependencies
     * @return the final set of instructions
     */
    public Properties generate(Properties instructions, ProjectDependencies dependencies) {
        Properties result = new Properties();
        result.putAll(instructions);
        StringBuilder include = new StringBuilder();
        if (instructions.getProperty(Constants.INCLUDE_RESOURCE) != null) {
            include.append(instructions.getProperty(Constants.INCLUDE_RESOURCE));
        }
        StringBuilder classpath = new StringBuilder();
        final String originalClassPath = instructions.getProperty(Constants.BUNDLE_CLASSPATH);
        if (originalClassPath != null) {
            classpath.append(originalClassPath);
        }

        for (EmbeddedDependency configuration : embedded) {
            configuration.addClause(dependencies, include, classpath, reporter);
        }

        if (include.length() != 0) {
            result.setProperty(Constants.INCLUDE_RESOURCE, include.toString());
        }
        if (classpath.length() != 0) {
            if (originalClassPath != null) {
                result.setProperty(Constants.BUNDLE_CLASSPATH, classpath.toString());
            } else {
                // Prepend . to the classpath.
                result.setProperty(Constants.BUNDLE_CLASSPATH, "., " + classpath.toString());
            }
        }

        return result;

    }

    private class EmbeddedDependency {

        private final String clause;
        private ArtifactFilter filter;
        private String inline;
        private boolean full = true;
        private boolean transitive = embedTransitive;

        /**
         * Creates an instance of {@link org.wisdom.maven.osgi.DependencyEmbedder.EmbeddedDependency}.
         *
         * @param clause the clause
         */
        public EmbeddedDependency(String clause) {
            this.clause = clause;
        }

        /**
         * Sets the artifact filter.
         *
         * @param filter the filter
         */
        public void setFilter(ArtifactFilter filter) {
            this.filter = filter;
        }

        /**
         * Sets the inline attribute.
         *
         * @param inline the inline
         */
        public void setInline(String inline) {
            if ("true".equalsIgnoreCase(inline)) {
                this.full = true;
                return;
            }
            if ("false".equalsIgnoreCase(inline)) {
                this.full = false;
                return;
            }
            this.full = false;
            this.inline = inline;
        }

        private boolean inline() {
            return full || inline != null;
        }

        /**
         * Computes the include-resource and bundle-classpath clauses.
         *
         * @param dependencies the project's dependencies
         * @param include      the current include-resource
         * @param classpath    the current bundle-classpath
         * @param reporter     the reporter
         */
        public void addClause(ProjectDependencies dependencies, StringBuilder include,
                              StringBuilder classpath, Reporter reporter) {
            boolean generated = false;

            Set artifacts = dependencies.getDirectDependencies();
            if (transitive) {
                artifacts = dependencies.getTransitiveDependencies();
            }

            for (Artifact artifact : artifacts) {
                if (filter.include(artifact)) {
                    if (inline()) {
                        String clause = "@" + artifact.getFile().getAbsolutePath();
                        if (!full) {
                            clause += "!/" + inline;  //NOSONAR can be appended here.
                        }
                        append(include, clause);
                        generated = true;
                    } else {
                        append(include, artifact.getFile().getAbsolutePath());
                        append(classpath, artifact.getFile().getName());
                        generated = true;
                    }
                }
            }
            if (!generated) {
                reporter.warn("A clause from `Embed-Dependency` did not match any artifacts: " + clause);
            }
        }

        /**
         * Sets the transitive attribute.
         *
         * @param transitive whether or not the clause must analyze the transitive set of dependencies
         */
        public void setTransitive(boolean transitive) {
            this.transitive = transitive;
        }
    }

    private void append(StringBuilder builder, String content) {
        if (builder.length() != 0) {
            builder.append(", ");
        }
        builder.append(content);
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy