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 boolean isService() { 80 return pathname.startsWith("META-INF/services") ? true : false; 81 } 82 83 @Override 84 public String toString() { 85 return name; 86 } 87 88 @Override 89 public int compareTo(ResourceFile o) { 90 return name.compareTo(o.name); 91 } 92 93 private static Set<ResourceFile> resources = new TreeSet<ResourceFile>(); 94 95 static boolean isResource(String pathname) { 96 // skip these files 97 String name = pathname.replace(File.separatorChar, '/'); 98 if (name.endsWith("META-INF/MANIFEST.MF")) { 99 return false; 100 } 101 if (name.contains("META-INF/JCE_RSA.")) { 102 return false; 103 } 104 if (name.contains("META-INF/") && 105 (name.endsWith(".RSA") || name.endsWith(".SF"))) { 106 return false; 107 } 108 109 return true; 110 } 111 112 static ResourceFile getResource(String fname, InputStream in, long size) { 113 ResourceFile res; 114 fname = fname.replace(File.separatorChar, '/'); 115 if (fname.startsWith("META-INF/services")) { 116 res = new ServiceProviderConfigFile(fname, in, size); 117 } else { 118 res = new ResourceFile(fname, size); 119 } 120 return res; 121 } 122 123 static ResourceFile addResource(String fname, InputStream in, long size) { 124 ResourceFile res = getResource(fname, in, size); 125 resources.add(res); 126 return res; 127 } 128 129 130 static Set<ResourceFile> getAllResources() { 131 return Collections.unmodifiableSet(resources); 132 } 133 134 static class ServiceProviderConfigFile extends ResourceFile { 135 final List<String> providers = new ArrayList<String>(); 136 final String service; 137 138 ServiceProviderConfigFile(String fname, InputStream in) { 139 this(fname, in, 0); 140 } 141 142 ServiceProviderConfigFile(String fname, InputStream in, long size) { 143 super(fname, size); 144 readServiceConfiguration(in, providers); 145 this.service = name.substring("META-INF/services".length() + 1, name.length()); 146 } 147 148 @Override 149 boolean isService() { 150 return true; 151 } 152 153 @Override 154 String getName() { 155 if (providers.isEmpty()) { 156 return service; 157 } else { 158 // just use the first one for matching 159 return providers.get(0); 160 } 161 } 162 163 @Override 164 public boolean equals(Object o) { 165 if (o instanceof ServiceProviderConfigFile) { 166 ServiceProviderConfigFile sp = (ServiceProviderConfigFile) o; 167 if (service.equals(sp.service) && providers.size() == sp.providers.size()) { 168 List<String> tmp = new ArrayList<String>(providers); 169 if (tmp.removeAll(sp.providers)) { 170 return tmp.size() == 0; 171 } 172 } 173 } 174 return false; 175 } 176 177 public int hashCode() { 178 int hash = 7; 179 hash = 73 * hash + (this.providers != null ? this.providers.hashCode() : 0); 180 hash = 73 * hash + (this.service != null ? this.service.hashCode() : 0); 181 return hash; 182 } 183 184 @Override 185 public int compareTo(ResourceFile o) { 186 if (this.equals(o)) { 187 return 0; 188 } else { 189 if (getName().compareTo(o.getName()) < 0) { 190 return -1; 191 } else { 192 return 1; 193 } 194 } 195 } 196 197 @SuppressWarnings("empty-statement") 198 void readServiceConfiguration(InputStream in, List<String> names) { 199 BufferedReader br = null; 200 try { 201 if (in != null) { 202 // Properties doesn't perserve the order of the input file 203 br = new BufferedReader(new InputStreamReader(in, "utf-8")); 204 int lc = 1; 205 while ((lc = parseLine(br, lc, names)) >= 0); 206 } 207 } catch (IOException ex) { 208 throw new RuntimeException(ex); 209 } finally { 210 if (br != null) { 211 try { 212 br.close(); 213 } catch (IOException ex) { 214 throw new RuntimeException(ex); 215 } 216 } 217 } 218 } 219 220 // Parse a single line from the given configuration file, adding the name 221 // on the line to the names list. 222 // 223 private int parseLine(BufferedReader r, int lc, List<String> names) throws IOException { 224 String ln = r.readLine(); 225 if (ln == null) { 226 return -1; 227 } 228 int ci = ln.indexOf('#'); 229 if (ci >= 0) { 230 ln = ln.substring(0, ci); 231 } 232 ln = ln.trim(); 233 int n = ln.length(); 234 if (n != 0) { 235 if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) { 236 throw new RuntimeException("Illegal configuration-file syntax"); 237 } 238 int cp = ln.codePointAt(0); 239 if (!Character.isJavaIdentifierStart(cp)) { 240 throw new RuntimeException("Illegal provider-class name: " + ln); 241 } 242 for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { 243 cp = ln.codePointAt(i); 244 if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) { 245 throw new RuntimeException("Illegal provider-class name: " + ln); 246 } 247 } 248 if (!names.contains(ln)) { 249 names.add(ln); 250 } 251 } 252 return lc + 1; 253 } 254 } 255 }