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.cli.archive;
018
019import java.net.URL;
020import java.net.URLClassLoader;
021import java.util.Enumeration;
022import java.util.jar.Attributes;
023import java.util.jar.Manifest;
024
025import org.springframework.boot.cli.app.SpringApplicationLauncher;
026
027/**
028 * A launcher for a CLI application that has been compiled and packaged as a jar file.
029 *
030 * @author Andy Wilkinson
031 * @author Phillip Webb
032 */
033public final class PackagedSpringApplicationLauncher {
034
035        /**
036         * The entry containing the source class.
037         */
038        public static final String SOURCE_ENTRY = "Spring-Application-Source-Classes";
039
040        /**
041         * The entry containing the start class.
042         */
043        public static final String START_CLASS_ENTRY = "Start-Class";
044
045        private PackagedSpringApplicationLauncher() {
046        }
047
048        private void run(String[] args) throws Exception {
049                URLClassLoader classLoader = (URLClassLoader) Thread.currentThread()
050                                .getContextClassLoader();
051                new SpringApplicationLauncher(classLoader).launch(getSources(classLoader), args);
052        }
053
054        private Object[] getSources(URLClassLoader classLoader) throws Exception {
055                Enumeration<URL> urls = classLoader.getResources("META-INF/MANIFEST.MF");
056                while (urls.hasMoreElements()) {
057                        URL url = urls.nextElement();
058                        Manifest manifest = new Manifest(url.openStream());
059                        if (isCliPackaged(manifest)) {
060                                String sources = manifest.getMainAttributes().getValue(SOURCE_ENTRY);
061                                return loadClasses(classLoader, sources.split(","));
062                        }
063                }
064                throw new IllegalStateException(
065                                "Cannot locate " + SOURCE_ENTRY + " in MANIFEST.MF");
066        }
067
068        private boolean isCliPackaged(Manifest manifest) {
069                Attributes attributes = manifest.getMainAttributes();
070                String startClass = attributes.getValue(START_CLASS_ENTRY);
071                return getClass().getName().equals(startClass);
072        }
073
074        private Class<?>[] loadClasses(ClassLoader classLoader, String[] names)
075                        throws ClassNotFoundException {
076                Class<?>[] classes = new Class<?>[names.length];
077                for (int i = 0; i < names.length; i++) {
078                        classes[i] = classLoader.loadClass(names[i]);
079                }
080                return classes;
081        }
082
083        public static void main(String[] args) throws Exception {
084                new PackagedSpringApplicationLauncher().run(args);
085        }
086
087}