001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.utils; 018 019import static org.apache.juneau.common.utils.IOUtils.*; 020 021import java.io.*; 022import java.net.*; 023import java.nio.file.*; 024import java.util.jar.*; 025 026import org.apache.juneau.collections.*; 027import org.apache.juneau.common.utils.*; 028 029/** 030 * Utility class for working with Jar manifest files. 031 * 032 * <p> 033 * Copies the contents of a {@link Manifest} into an {@link JsonMap} so that the various convenience methods on that 034 * class can be used to retrieve values. 035 * 036 * <h5 class='section'>See Also:</h5><ul> 037 038 * </ul> 039 * 040 * @serial exclude 041 */ 042public class ManifestFile extends JsonMap { 043 044 private static final long serialVersionUID = 1L; 045 046 /** 047 * Create an instance of this class from a manifest file on the file system. 048 * 049 * @param f The manifest file. 050 * @throws IOException If a problem occurred while trying to read the manifest file. 051 */ 052 public ManifestFile(File f) throws IOException { 053 Manifest mf = new Manifest(); 054 try (FileInputStream fis = new FileInputStream(f)) { 055 mf.read(fis); 056 load(mf); 057 } catch (IOException e) { 058 throw new IOException("Problem detected in MANIFEST.MF. Contents below:\n"+read(f), e); 059 } 060 } 061 062 /** 063 * Create an instance of this class from a manifest path on the file system. 064 * 065 * @param path The manifest path. 066 * @throws IOException If a problem occurred while trying to read the manifest path. 067 */ 068 public ManifestFile(Path path) throws IOException { 069 Manifest mf = new Manifest(); 070 try (InputStream fis = Files.newInputStream(path)) { 071 mf.read(fis); 072 load(mf); 073 } catch (IOException e) { 074 throw new IOException("Problem detected in MANIFEST.MF. Contents below:\n"+read(path), e); 075 } 076 } 077 078 /** 079 * Create an instance of this class from a {@link Manifest} object. 080 * 081 * @param f The manifest to read from. 082 */ 083 public ManifestFile(Manifest f) { 084 load(f); 085 } 086 087 /** 088 * Finds and loads the manifest file of the jar file that the specified class is contained within. 089 * 090 * @param c The class to get the manifest file of. 091 * @throws IOException If a problem occurred while trying to read the manifest file. 092 */ 093 public ManifestFile(Class<?> c) throws IOException { 094 String className = c.getSimpleName() + ".class"; 095 String classPath = c.getResource(className).toString(); 096 if (! classPath.startsWith("jar")) { 097 return; 098 } 099 String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF"; 100 try { 101 Manifest mf = new Manifest(new URL(manifestPath).openStream()); 102 load(mf); 103 } catch (MalformedURLException e) { 104 throw ThrowableUtils.cast(IOException.class, e); 105 } catch (IOException e) { 106 e.printStackTrace(); 107 } 108 } 109 110 /** 111 * Create an instance of this class loaded from the contents of a reader. 112 * 113 * <p> 114 * Note that the input must end in a newline to pick up the last line! 115 * 116 * @param r The manifest file contents. 117 * @throws IOException If a problem occurred while trying to read the manifest file. 118 */ 119 public ManifestFile(Reader r) throws IOException { 120 load(new Manifest(new ByteArrayInputStream(read(r).getBytes(UTF8)))); 121 } 122 123 /** 124 * Create an instance of this class loaded from the contents of an input stream. 125 * 126 * <p> 127 * Note that the input must end in a newline to pick up the last line! 128 * 129 * @param is The manifest file contents. 130 * @throws IOException If a problem occurred while trying to read the manifest file. 131 */ 132 public ManifestFile(InputStream is) throws IOException { 133 load(new Manifest(is)); 134 } 135 136 private void load(Manifest mf) { 137 mf.getMainAttributes().forEach((k,v) -> put(k.toString(), v.toString())); 138 } 139 140 @Override /* Object */ 141 public String toString() { 142 StringBuilder sb = new StringBuilder(); 143 forEach((k,v) -> sb.append(k).append(": ").append(v)); 144 return sb.toString(); 145 } 146}