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  * @author Mandy Chung
  40  */
  41 public class ResourceFile implements Comparable<ResourceFile> {
  42 
  43     private final String pathname;
  44     private Module module;
  45 
  46     ResourceFile(String pathname) {
  47         this.pathname = pathname.replace(File.separatorChar, '/');
  48     }
  49 
  50     Module getModule() {
  51         return module;
  52     }
  53 
  54     void setModule(Module m) {
  55         if (module != null) {
  56             throw new RuntimeException("Module for " + this + " already set");
  57         }
  58         this.module = m;
  59     }
  60 
  61     String getName() {
  62         return pathname;
  63     }
  64 
  65     String getPathname() {
  66         return pathname;
  67     }
  68 
  69     @Override
  70     public String toString() {
  71         return pathname;
  72     }
  73 
  74     @Override
  75     public int compareTo(ResourceFile o) {
  76         return pathname.compareTo(o.pathname);
  77     }
  78     static Set<ResourceFile> resources = new TreeSet<ResourceFile>();
  79 
  80     static boolean isResource(String pathname) {
  81         String name = pathname.replace(File.separatorChar, '/');
  82 
  83         if (name.endsWith("META-INF/MANIFEST.MF")) {
  84             return false;
  85         }
  86         if (name.contains("META-INF/JCE_RSA.")) {
  87             return false;
  88         }
  89 
  90         return true;
  91     }
  92 
  93     static void addResource(String name, InputStream in) {
  94         ResourceFile res;
  95         name = name.replace(File.separatorChar, '/');
  96         if (name.startsWith("META-INF/services")) {
  97             res = new ServiceProviderConfigFile(name, in);
  98         } else {
  99             res = new ResourceFile(name);
 100         }
 101         resources.add(res);
 102     }
 103 
 104     static Set<ResourceFile> getAllResources() {
 105         return Collections.unmodifiableSet(resources);
 106     }
 107 
 108     static class ServiceProviderConfigFile extends ResourceFile {
 109 
 110         private final List<String> providers = new ArrayList<String>();
 111         private final String service;
 112         ServiceProviderConfigFile(String pathname, InputStream in) {
 113             super(pathname);
 114             readServiceConfiguration(in, providers);
 115             this.service = pathname.substring("META-INF/services".length() + 1, pathname.length());
 116         }
 117 
 118         @Override
 119         String getName() {
 120             if (providers.isEmpty()) {
 121                 return service;
 122             } else {
 123                 // just use the first one for matching
 124                 return providers.get(0);
 125             }
 126         }
 127 
 128         @SuppressWarnings("empty-statement")
 129         void readServiceConfiguration(InputStream in, List<String> names) {
 130             BufferedReader br = null;
 131             try {
 132                 if (in != null) {
 133                     // Properties doesn't perserve the order of the input file
 134                     br = new BufferedReader(new InputStreamReader(in, "utf-8"));
 135                     int lc = 1;
 136                     while ((lc = parseLine(br, lc, names)) >= 0);
 137                 }
 138             } catch (IOException ex) {
 139                 throw new RuntimeException(ex);
 140             } finally {
 141                 if (br != null) {
 142                     try {
 143                         br.close();
 144                     } catch (IOException ex) {
 145                         throw new RuntimeException(ex);
 146                     }
 147                 }
 148             }
 149         }
 150 
 151         // Parse a single line from the given configuration file, adding the name
 152         // on the line to the names list.
 153         //
 154         private int parseLine(BufferedReader r, int lc, List<String> names) throws IOException {
 155             String ln = r.readLine();
 156             if (ln == null) {
 157                 return -1;
 158             }
 159             int ci = ln.indexOf('#');
 160             if (ci >= 0) {
 161                 ln = ln.substring(0, ci);
 162             }
 163             ln = ln.trim();
 164             int n = ln.length();
 165             if (n != 0) {
 166                 if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) {
 167                     throw new RuntimeException("Illegal configuration-file syntax");
 168                 }
 169                 int cp = ln.codePointAt(0);
 170                 if (!Character.isJavaIdentifierStart(cp)) {
 171                     throw new RuntimeException("Illegal provider-class name: " + ln);
 172                 }
 173                 for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
 174                     cp = ln.codePointAt(i);
 175                     if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {
 176                         throw new RuntimeException("Illegal provider-class name: " + ln);
 177                     }
 178                 }
 179                 if (!names.contains(ln)) {
 180                     names.add(ln);
 181                 }
 182             }
 183             return lc + 1;
 184         }
 185     }
 186 }