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