com.carrotgarden.maven.scr.CarrotOsgiScrGenerate.java Source code

Java tutorial

Introduction

Here is the source code for com.carrotgarden.maven.scr.CarrotOsgiScrGenerate.java

Source

/**
 * Copyright (C) 2010-2013 Andrei Pozolotin <Andrei.Pozolotin@gmail.com>
 *
 * All rights reserved. Licensed under the OSI BSD License.
 *
 * http://www.opensource.org/licenses/bsd-license.php
 */
package com.carrotgarden.maven.scr;

import static com.carrotgarden.maven.scr.MojoUtil.*;

import java.io.File;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoFailureException;

/**
 * Generate component descriptors form annotated java classes.
 * 
 * @goal generate
 * 
 * @phase process-classes
 * 
 * @inheritByDefault true
 * 
 * @requiresDependencyResolution test
 * 
 */
public class CarrotOsgiScrGenerate extends CarrotOsgiScr {

    /**
     * Empty DS descriptor included in the plugin jar.
     */
    protected static final String NULL_XML = "null.xml";

    /**
     * Progress counter for all classes.
     */
    private int allclassesCounter;

    /**
     * Progress counter for DS component classes.
     */
    private int descriptorCounter;

    /**
     * {@inheritDoc}
     */
    @Override
    public void execute() throws MojoFailureException {
        try {

            contextMessageClear(pomFile());

            logInfo("generate");
            logInfo("incremental: " + isContextIncremental());

            if (!isProperPackaging()) {
                logInfo("skip for packaging=" + project.getPackaging());
                return;
            }

            final File folder = outputDirectorySCR();
            if (!folder.exists()) {
                logDebug("");
                if (folder.mkdirs()) {
                    logDebug("folder created : " + folder);
                } else {
                    logError("failed to create folder : " + folder);
                }
            }

            logDebug("");
            logDebug("excludedServices");
            for (final String service : excludedServices) {
                logDebug("\t service=" + service);
            }

            logDebug("");
            logDebug("properPackaging");
            for (final String packaging : properPackaging) {
                logDebug("\t packaging=" + packaging);
            }

            descriptorCounter = 0;
            allclassesCounter = 0;

            final long timeStart = System.nanoTime();

            if (!isProcessMainClasses && !isProcessTestClasses) {
                logError("you have not selected neither main nor test classes");
            }

            if (isProcessMainClasses) {
                processClassFolder(ClassesSelector.COMPILE);
            }

            if (isProcessTestClasses) {
                processClassFolder(ClassesSelector.TESTING);
            }

            if (isIncludeEmptyDescriptor) {
                includeEmptyDescriptor();
            }

            if (isIncludeGeneratedDescritors) {
                includeDescriptorResource();
            }

            final long timeFinish = System.nanoTime();

            logDebug("");

            final long timeDiff = timeFinish - timeStart;
            final long timeRate = descriptorCounter == 0 ? 0 : timeDiff / descriptorCounter;
            logDebug("combined classes count = " + allclassesCounter);
            logDebug("descriptor class count = " + descriptorCounter);
            logDebug("time, millis total     = " + timeDiff / 1000 / 1000);
            logDebug("rate, millis per descr = " + timeRate / 1000 / 1000);

        } catch (final Throwable e) {
            final String message = "generate failure: " + e;
            logError(message);
            contextMessageError(pomFile(), message, e);
            throw new MojoFailureException("bada-boom", e);
        }
    }

    /**
     * Check if resource with given target path is present in the list.
     */
    protected boolean hasResource(final Resource resource, final List<Resource> resourceList) {
        for (final Resource existing : resourceList) {
            if (resource.getTargetPath().equals(existing.getTargetPath())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Attach DS descriptor resource folder to the final jar.
     */
    protected void includeDescriptorResource() {

        if (isContextIncremental()) {
            logDebug("do not include descriptor resource for incremental build");
            return;
        }

        final String sourcePath = outputDirectorySCR().getPath();
        final String targetPath = targetDirectorySCR;

        final Resource resource = new Resource();
        resource.setDirectory(sourcePath);
        resource.setTargetPath(targetPath);

        final List<Resource> resourceList = project.getResources();

        logDebug("");
        if (hasResource(resource, resourceList)) {
            logDebug("use existing descriptor resource = " + resource);
            return;
        } else {
            logDebug("include created descriptor resource = " + resource);
            resourceList.add(resource);
        }

    }

    /**
     * Attach empty place holder DS component descriptor to the final jar.
     */
    protected void includeEmptyDescriptor() throws Exception {

        if (isContextIncremental()) {
            logDebug("skip including empty descriptor for incremental build");
            return;
        }

        final URL source = getClass().getResource(NULL_XML);

        final File target = absolute(new File(outputDirectorySCR(), NULL_XML));

        logDebug("");
        logDebug("including empty descriptor = " + target);

        FileUtils.copyURLToFile(source, target);

    }

    /**
     * Generate extended class loader.
     * 
     * @return class loader that will include both project and plug-in
     *         dependencies
     **/
    protected ClassLoader makeClassLoader(final ClassesSelector selector) throws Exception {

        final List<String> pathList = selector.getClasspathElements(project);

        final URL[] entryUrlArray = new URL[pathList.size()];

        int index = 0;
        for (final String path : pathList) {
            final URL entryURL = absolute(path).toURI().toURL();
            logDebug("\t dependency = " + entryURL);
            entryUrlArray[index++] = entryURL;
        }

        /** Maven plug-in class loader. */
        final ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();

        /** Combo class path loader for a selector. */
        final URLClassLoader customLoader = new URLClassLoader(entryUrlArray, parentLoader);

        return customLoader;

    }

    /**
     * Generate full java class name.
     * 
     * @return java class FQN
     */
    protected String makeClassName(final File classesDirectory, final File classFile) {

        final URI folderURI = absolute(classesDirectory).toURI();
        final URI fileURI = absolute(classFile).toURI();

        final String path = folderURI.relativize(fileURI).getPath();

        /**
         * Cut out file extension and convert to java class FQN.
         * <p>
         * from: com/carrotgarden/test/TestComp.class
         * <p>
         * into: com.carrotgarden.test.TestComp
         */

        final int index = path.lastIndexOf(".");

        final String name = path.substring(0, index).replace("/", ".");

        return name;

    }

    /**
     * Generate DS descriptor file name.
     */
    protected String outputFileSCR(final String name) {
        return name + "." + outputExtensionSCR;
    }

    /**
     * Generate DS component descriptors for given class path type.
     */
    protected void processClassFolder(final ClassesSelector selector) throws Throwable {

        final File classesDirectory = selector.getClassesDirectory(this);

        logDebug("");
        if (!classesDirectory.exists()) {
            logDebug("skip for missing classes directory");
            return;
        } else {
            logDebug("input classes = " + classesDirectory);
        }

        /** Collect all class files. */
        final Iterator<File> iter = processIterator(classesDirectory);

        if (!iter.hasNext()) {
            logDebug("");
            logDebug("skip for no changes in classes directory");
            return;
        }

        final ClassLoader loader = makeClassLoader(selector);

        logDebug("");
        logDebug("output directory = " + outputDirectorySCR());

        final Pattern excludePattern = Pattern.compile(excludeFileNameRegex);

        while (iter.hasNext()) {

            /** Discovered *.class file. */
            final File file = iter.next();

            // logDebug("\t file : " + file);

            /** Ignore excluded files. */
            if (excludePattern.matcher(file.getName()).matches()) {
                continue;
            }

            /** Resolved class name. */
            final String name = makeClassName(classesDirectory, file);

            // logDebug("\t class : " + name);

            /** Make individual descriptor. */
            final String text = maker().make(loader, name);

            /** Non components return null. */
            final boolean isComponent = text != null;

            allclassesCounter++;

            if (isComponent) {

                final String outputFile = outputFileSCR(name);

                logDebug("\t descriptor = " + outputFile);

                saveDescriptor(name, text);

                descriptorCounter++;

            } else {

                logDebug("\t class is not a component: " + name);

            }

        }

        logInfo("");
        if (descriptorCounter == 0) {
            logInfo("did not find any active scr components.");
        } else {
            logInfo("active components count = " + descriptorCounter);
        }

    }

    /**
     * Find changed class files in class folder.
     */
    protected Iterator<File> processIterator(final File folder) {
        return contextIterator(folder, contextChanged(folder, "**/*.class"));
    }

    /**
     * Save generated DS descriptor and report changes to Eclipse.
     * <p>
     * Descriptor file name convention:
     * <p>
     * from: com.carrotgarden.test.TestComp
     * <p>
     * into: com.carrotgarden.test.TestComp.xml
     */
    protected void saveDescriptor(final String name, final String text) throws Exception {

        final File file = new File(outputDirectorySCR(), outputFileSCR(name));

        FileUtils.writeStringToFile(absolute(file), text);

        contextRefresh(file);

    }

}