001/* 002 * Copyright 2012-2017 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.loader; 018 019import java.util.ArrayList; 020import java.util.List; 021import java.util.jar.JarEntry; 022import java.util.jar.Manifest; 023 024import org.springframework.boot.loader.archive.Archive; 025 026/** 027 * Base class for executable archive {@link Launcher}s. 028 * 029 * @author Phillip Webb 030 * @author Andy Wilkinson 031 */ 032public abstract class ExecutableArchiveLauncher extends Launcher { 033 034 private final Archive archive; 035 036 public ExecutableArchiveLauncher() { 037 try { 038 this.archive = createArchive(); 039 } 040 catch (Exception ex) { 041 throw new IllegalStateException(ex); 042 } 043 } 044 045 protected ExecutableArchiveLauncher(Archive archive) { 046 this.archive = archive; 047 } 048 049 protected final Archive getArchive() { 050 return this.archive; 051 } 052 053 @Override 054 protected String getMainClass() throws Exception { 055 Manifest manifest = this.archive.getManifest(); 056 String mainClass = null; 057 if (manifest != null) { 058 mainClass = manifest.getMainAttributes().getValue("Start-Class"); 059 } 060 if (mainClass == null) { 061 throw new IllegalStateException( 062 "No 'Start-Class' manifest entry specified in " + this); 063 } 064 return mainClass; 065 } 066 067 @Override 068 protected List<Archive> getClassPathArchives() throws Exception { 069 List<Archive> archives = new ArrayList<>( 070 this.archive.getNestedArchives(this::isNestedArchive)); 071 postProcessClassPathArchives(archives); 072 return archives; 073 } 074 075 /** 076 * Determine if the specified {@link JarEntry} is a nested item that should be added 077 * to the classpath. The method is called once for each entry. 078 * @param entry the jar entry 079 * @return {@code true} if the entry is a nested item (jar or folder) 080 */ 081 protected abstract boolean isNestedArchive(Archive.Entry entry); 082 083 /** 084 * Called to post-process archive entries before they are used. Implementations can 085 * add and remove entries. 086 * @param archives the archives 087 * @throws Exception if the post processing fails 088 */ 089 protected void postProcessClassPathArchives(List<Archive> archives) throws Exception { 090 } 091 092}