001/*
002 * Copyright 2012-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.ant;
018
019import java.io.File;
020import java.io.IOException;
021import java.util.jar.JarFile;
022
023import org.apache.tools.ant.BuildException;
024import org.apache.tools.ant.Project;
025import org.apache.tools.ant.Task;
026
027import org.springframework.boot.loader.tools.MainClassFinder;
028import org.springframework.util.StringUtils;
029
030/**
031 * Ant task to find a main class.
032 *
033 * @author Matt Benson
034 * @since 1.3.0
035 */
036public class FindMainClass extends Task {
037
038        private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication";
039
040        private String mainClass;
041
042        private File classesRoot;
043
044        private String property;
045
046        public FindMainClass(Project project) {
047                setProject(project);
048        }
049
050        @Override
051        public void execute() throws BuildException {
052                String mainClass = this.mainClass;
053                if (!StringUtils.hasText(mainClass)) {
054                        mainClass = findMainClass();
055                        if (!StringUtils.hasText(mainClass)) {
056                                throw new BuildException(
057                                                "Could not determine main class given @classesRoot "
058                                                                + this.classesRoot);
059                        }
060                }
061                handle(mainClass);
062        }
063
064        private String findMainClass() {
065                if (this.classesRoot == null) {
066                        throw new BuildException(
067                                        "one of @mainClass or @classesRoot must be specified");
068                }
069                if (!this.classesRoot.exists()) {
070                        throw new BuildException(
071                                        "@classesRoot " + this.classesRoot + " does not exist");
072                }
073                try {
074                        if (this.classesRoot.isDirectory()) {
075                                return MainClassFinder.findSingleMainClass(this.classesRoot,
076                                                SPRING_BOOT_APPLICATION_CLASS_NAME);
077                        }
078                        return MainClassFinder.findSingleMainClass(new JarFile(this.classesRoot), "/",
079                                        SPRING_BOOT_APPLICATION_CLASS_NAME);
080                }
081                catch (IOException ex) {
082                        throw new BuildException(ex);
083                }
084        }
085
086        private void handle(String mainClass) {
087                if (StringUtils.hasText(this.property)) {
088                        getProject().setProperty(this.property, mainClass);
089                }
090                else {
091                        log("Found main class " + mainClass);
092                }
093        }
094
095        /**
096         * Set the main class, which will cause the search to be bypassed.
097         * @param mainClass the main class name
098         */
099        public void setMainClass(String mainClass) {
100                this.mainClass = mainClass;
101        }
102
103        /**
104         * Set the root location of classes to be searched.
105         * @param classesRoot the root location
106         */
107        public void setClassesRoot(File classesRoot) {
108                this.classesRoot = classesRoot;
109        }
110
111        /**
112         * Set the ANT property to set (if left unset, result will be printed to the log).
113         * @param property the ANT property to set
114         */
115        public void setProperty(String property) {
116                this.property = property;
117        }
118
119}