1 /* 2 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 package com.sun.classanalyzer; 25 26 import java.io.BufferedReader; 27 import java.io.File; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.InputStreamReader; 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.List; 34 import java.util.Set; 35 import java.util.TreeSet; 36 37 /** 38 * 39 */ 40 public class ResourceFile implements Comparable<ResourceFile> { 41 private final String pathname; 42 private final long filesize; 43 protected final String name; 44 private Module module; 45 46 ResourceFile(String fname) { 47 this(fname, 0); 48 } 49 50 ResourceFile(String fname, long size) { 51 this.pathname = fname.replace('/', File.separatorChar); 52 this.name = fname.replace(File.separatorChar, '/'); 53 this.filesize = size; 54 } 55 56 Module getModule() { 57 return module; 58 } 59 60 void setModule(Module m) { 61 if (module != null) { 62 throw new RuntimeException("Module for " + this + " already set"); 63 } 64 this.module = m; 65 } 66 67 String getName() { 68 return name; 69 } 70 71 String getPathname() { 72 return pathname; 73 } 74 75 long getFileSize() { 76 return filesize; 77 } 78 79 @Override 80 public String toString() { 81 return name; 82 } 83 84 @Override 85 public int compareTo(ResourceFile o) { 86 return name.compareTo(o.name); 87 } 88 89 private static Set<ResourceFile> resources = new TreeSet<ResourceFile>(); 90 91 static boolean isResource(String pathname) { 92 // skip these files 93 String name = pathname.replace(File.separatorChar, '/'); 94 if (name.endsWith("META-INF/MANIFEST.MF")) { 95 return false; 96 } 97 if (name.contains("META-INF/JCE_RSA.")) { 98 return false; 99 } 100 if (name.contains("META-INF/") && 101 (name.endsWith(".RSA") || name.endsWith(".SF"))) { 102 return false; 103 } 104 105 return true; 106 } 107 108 static ResourceFile addResource(String fname, InputStream in, long size) { 109 ResourceFile res; 110 fname = fname.replace(File.separatorChar, '/'); 111 if (fname.startsWith("META-INF/services")) { 112 res = new ServiceProviderConfigFile(fname, in, size); 113 } else { 114 res = new ResourceFile(fname, size); 115 } 116 resources.add(res); 117 return res; 118 } 119 120 static Set<ResourceFile> getAllResources() { 121 return Collections.unmodifiableSet(resources); 122 } 123 124 static class ServiceProviderConfigFile extends ResourceFile { 125 final List<String> providers = new ArrayList<String>(); 126 final String service; 127 128 ServiceProviderConfigFile(String fname, InputStream in) { 129 this(fname, in, 0); 130 } 131 132 ServiceProviderConfigFile(String fname, InputStream in, long size) { 133 super(fname, size); 134 readServiceConfiguration(in, providers); 135 this.service = name.substring("META-INF/services".length() + 1, name.length()); 136 } 137 138 @Override 139 String getName() { 140 if (providers.isEmpty()) { 141 return service; 142 } else { 143 // just use the first one for matching 144 return providers.get(0); 145 } 146 } 147 148 @Override 149 public boolean equals(Object o) { 150 if (o instanceof ServiceProviderConfigFile) { 151 ServiceProviderConfigFile sp = (ServiceProviderConfigFile) o; 152 if (service.equals(sp.service) && providers.size() == sp.providers.size()) { 153 List<String> tmp = new ArrayList<String>(providers); 154 if (tmp.removeAll(sp.providers)) { 155 return tmp.size() == 0; 156 } 157 } 158 } 159 return false; 160 } 161 162 public int hashCode() { 163 int hash = 7; 164 hash = 73 * hash + (this.providers != null ? this.providers.hashCode() : 0); 165 hash = 73 * hash + (this.service != null ? this.service.hashCode() : 0); 166 return hash; 167 } 168 169 @Override 170 public int compareTo(ResourceFile o) { 171 if (this.equals(o)) { 172 return 0; 173 } else { 174 if (getName().compareTo(o.getName()) < 0) { 175 return -1; 176 } else { 177 return 1; 178 } 179 } 180 } 181 182 @SuppressWarnings("empty-statement") 183 void readServiceConfiguration(InputStream in, List<String> names) { 184 BufferedReader br = null; 185 try { 186 if (in != null) { 187 // Properties doesn't perserve the order of the input file 188 br = new BufferedReader(new InputStreamReader(in, "utf-8")); 189 int lc = 1; 190 while ((lc = parseLine(br, lc, names)) >= 0); 191 } 192 } catch (IOException ex) { 193 throw new RuntimeException(ex); 194 } finally { 195 if (br != null) { 196 try { 197 br.close(); 198 } catch (IOException ex) { 199 throw new RuntimeException(ex); 200 } 201 } 202 } 203 } 204 205 // Parse a single line from the given configuration file, adding the name 206 // on the line to the names list. 207 // 208 private int parseLine(BufferedReader r, int lc, List<String> names) throws IOException { 209 String ln = r.readLine(); 210 if (ln == null) { 211 return -1; 212 } 213 int ci = ln.indexOf('#'); 214 if (ci >= 0) { 215 ln = ln.substring(0, ci); 216 } 217 ln = ln.trim(); 218 int n = ln.length(); 219 if (n != 0) { 220 if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) { 221 throw new RuntimeException("Illegal configuration-file syntax"); 222 } 223 int cp = ln.codePointAt(0); 224 if (!Character.isJavaIdentifierStart(cp)) { 225 throw new RuntimeException("Illegal provider-class name: " + ln); 226 } 227 for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { 228 cp = ln.codePointAt(i); 229 if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) { 230 throw new RuntimeException("Illegal provider-class name: " + ln); 231 } 232 } 233 if (!names.contains(ln)) { 234 names.add(ln); 235 } 236 } 237 return lc + 1; 238 } 239 } 240 }