1 /*
   2  * Copyright (c) 2016, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.jdeprscan;
  27 
  28 import java.io.BufferedReader;
  29 import java.io.IOException;
  30 import java.nio.file.Files;
  31 import java.nio.file.Paths;
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.Formatter;
  35 import java.util.HashMap;
  36 import java.util.List;
  37 import java.util.Locale;
  38 import java.util.Map;
  39 import java.util.Set;
  40 
  41 import javax.lang.model.element.ElementKind;
  42 
  43 /**
  44  * A database of deprecations (APIs declared to be deprecated),
  45  * loaded from a JDK or from a class library.
  46  */
  47 public class DeprDB {
  48     /**
  49      * Deprecated types.
  50      * A map from deprecated type names to DeprData values.
  51      * Types include classes, interfaces, enums, and annotation types.
  52      */
  53     final Map<String, DeprData> types = new HashMap<>();
  54 
  55     /**
  56      * Deprecated methods. Key is type name, value is map from method
  57      * signatures in the form "methodname(parms)ret" to DeprData value.
  58      */
  59     final Map<String, Map<String, DeprData>> methods = new HashMap<>();
  60 
  61     /**
  62      * Deprecated fields. Key is type name, value is map from field name
  63      * to forRemoval value.
  64      */
  65     final Map<String, Map<String, DeprData>> fields = new HashMap<>();
  66 
  67     /**
  68      * Set of valid ElementKind strings.
  69      */
  70     static final Set<String> validElementKinds =
  71         Set.of(Arrays.stream(ElementKind.values())
  72                      .map(ElementKind::toString)
  73                      .toArray(String[]::new));
  74 
  75 
  76     private DeprDB() { }
  77 
  78     public static List<DeprData> loadFromFile(String filename) throws IOException {
  79         List<DeprData> list = new ArrayList<>();
  80 
  81         exit:
  82         try (final BufferedReader br = Files.newBufferedReader(Paths.get(filename))) {
  83             String line = br.readLine();
  84             if (line == null || !line.equals("#jdepr1")) {
  85                 System.out.printf("ERROR: invalid first line %s%n", line);
  86                 break exit;
  87             }
  88             while ((line = br.readLine()) != null) {
  89                 if (line.startsWith("#")) {
  90                     continue;
  91                 }
  92                 List<String> tokens = CSV.split(line);
  93                 if (tokens.size() != 5) {
  94                     System.out.printf("ERROR: %s%n", line);
  95                     continue;
  96                 }
  97                 // kind,typeName,descOrName,since,forRemoval
  98                 String kindStr = tokens.get(0);
  99                 String type = tokens.get(1);
 100                 String detail = tokens.get(2);
 101                 String since = tokens.get(3);
 102                 boolean forRemoval = Boolean.parseBoolean(tokens.get(4));
 103                 ElementKind kind;
 104 
 105                 if (validElementKinds.contains(kindStr)) {
 106                     kind = ElementKind.valueOf(kindStr);
 107                 } else {
 108                     System.out.printf("ERROR: invalid element kind %s%n", kindStr);
 109                     continue;
 110                 }
 111 
 112                 DeprData data = new DeprData(kind, /*TypeElement*/null, type, detail, since, forRemoval);
 113                 list.add(data);
 114             }
 115         }
 116         return list;
 117     }
 118 
 119     public static DeprDB loadFromList(List<DeprData> deprList) {
 120         DeprDB db = new DeprDB();
 121 
 122         for (DeprData dd : deprList) {
 123             switch (dd.kind) {
 124                 case CLASS:
 125                 case INTERFACE:
 126                 case ENUM:
 127                 case ANNOTATION_TYPE:
 128                     db.types.put(dd.typeName, dd);
 129                     break;
 130                 case METHOD:
 131                 case CONSTRUCTOR:
 132                     db.methods.computeIfAbsent(dd.typeName, k -> new HashMap<>())
 133                               .put(dd.nameSig, dd);
 134                     break;
 135                 case ENUM_CONSTANT:
 136                 case FIELD:
 137                     db.fields.computeIfAbsent(dd.typeName, k -> new HashMap<>())
 138                              .put(dd.nameSig, dd);
 139                     break;
 140             }
 141         }
 142 
 143         return db;
 144     }
 145 
 146     @Override
 147     public String toString() {
 148         StringBuilder sb = new StringBuilder();
 149         Formatter f = new Formatter(sb, Locale.US);
 150         f.format("=== Types ===%n");
 151         f.format("%s%n", types.toString());
 152         f.format("=== Methods ===%n");
 153         f.format("%s%n", methods.toString());
 154         f.format("=== Fields ===%n");
 155         f.format("%s%n", fields.toString());
 156         return sb.toString();
 157     }
 158 
 159     public DeprData getTypeDeprecated(String typeName) {
 160         return types.get(typeName);
 161     }
 162 
 163     public DeprData getMethodDeprecated(String typeName, String methodName, String type) {
 164         Map<String, DeprData> m = methods.get(typeName);
 165         if (m == null) {
 166             return null;
 167         }
 168         return m.get(methodName + type);
 169     }
 170 
 171     public DeprData getFieldDeprecated(String typeName, String fieldName) {
 172         Map<String, DeprData> f = fields.get(typeName);
 173         if (f == null) {
 174             return null;
 175         }
 176         return f.get(fieldName);
 177     }
 178 }