• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.build.backportedfixes.common;
17 
18 import static com.google.common.base.Preconditions.checkNotNull;
19 
20 import com.android.build.backportedfixes.BackportedFix;
21 import com.android.build.backportedfixes.BackportedFixes;
22 
23 import com.google.common.base.Throwables;
24 import com.google.common.collect.ImmutableList;
25 
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.util.BitSet;
32 import java.util.Comparator;
33 import java.util.List;
34 import java.util.stream.Collector;
35 import java.util.stream.Collectors;
36 
37 
38 /** Static utilities for working with {@link BackportedFixes}. */
39 public final class Parser {
40 
41     /** Creates list of FileInputStreams for a list of files. */
getFileInputStreams(List<File> fixFiles)42     public static ImmutableList<FileInputStream> getFileInputStreams(List<File> fixFiles) throws
43             FileNotFoundException {
44         var streams = ImmutableList.<FileInputStream>builder();
45         for (var f : fixFiles) {
46             streams.add(new FileInputStream(f));
47         }
48         return streams.build();
49     }
50 
51     /** Converts a list of backported fix aliases into a long array representing a {@link BitSet} */
getBitSetArray(int[] aliases)52     public static long[] getBitSetArray(int[] aliases) {
53         BitSet bs = new BitSet();
54         for (int a : aliases) {
55             bs.set(a);
56         }
57         return bs.toLongArray();
58     }
59 
60     /**
61      * Creates a {@link BackportedFixes} from a list of {@link BackportedFix} binary proto streams.
62      */
parseBackportedFixFiles(List<File> fixFiles)63     public static BackportedFixes parseBackportedFixFiles(List<File> fixFiles)
64             throws IOException {
65         try {
66             return fixFiles.stream().map(Parser::tunelFileInputStream)
67                     .map(Parser::tunnelParse)
68                     .sorted(Comparator.comparing(BackportedFix::getKnownIssue))
69                     .collect(fixCollector());
70 
71         } catch (TunnelException e) {
72             throw e.rethrow(FileNotFoundException.class, IOException.class);
73         }
74     }
75 
76 
fixCollector()77     private static Collector<BackportedFix, ?, BackportedFixes> fixCollector() {
78         return Collectors.collectingAndThen(Collectors.toList(), fixList -> {
79             var result = BackportedFixes.newBuilder();
80             result.addAllFixes(fixList);
81             return result.build();
82         });
83     }
84 
tunelFileInputStream(File file)85     private static FileInputStream tunelFileInputStream(File file) throws TunnelException {
86         try {
87             return new FileInputStream(file);
88         } catch (FileNotFoundException e) {
89             throw new TunnelException(e);
90         }
91     }
92 
tunnelParse(InputStream s)93     private static BackportedFix tunnelParse(InputStream s) throws TunnelException {
94         try {
95             var fix = BackportedFix.parseFrom(s);
96             s.close();
97             return fix;
98         } catch (IOException e) {
99             throw new TunnelException(e);
100         }
101     }
102 
103     private static class TunnelException extends RuntimeException {
TunnelException(Exception cause)104         TunnelException(Exception cause) {
105             super("If you see this TunnelException something went wrong.  It should always be rethrown as the cause.", cause);
106         }
107 
rethrow(Class<X> exceptionClazz)108         <X extends Exception> RuntimeException rethrow(Class<X> exceptionClazz) throws X {
109             checkNotNull(exceptionClazz);
110             Throwables.throwIfInstanceOf(getCause(), exceptionClazz);
111             throw exception(
112                     getCause(),
113                     "rethrow(%s) doesn't match underlying exception", exceptionClazz);
114         }
115 
rethrow( Class<X1> exceptionClazz1, Class<X2> exceptionClazz2)116         public <X1 extends Exception, X2 extends Exception> RuntimeException rethrow(
117                 Class<X1> exceptionClazz1, Class<X2> exceptionClazz2) throws X1, X2 {
118             checkNotNull(exceptionClazz1);
119             checkNotNull(exceptionClazz2);
120             Throwables.throwIfInstanceOf(getCause(), exceptionClazz1);
121             Throwables.throwIfInstanceOf(getCause(), exceptionClazz2);
122             throw exception(
123                     getCause(),
124                     "rethrow(%s, %s) doesn't match underlying exception",
125                     exceptionClazz1,
126                     exceptionClazz2);
127         }
128 
exception( Throwable cause, String message, Object... formatArgs)129         private static ClassCastException exception(
130                 Throwable cause, String message, Object... formatArgs) {
131             ClassCastException result = new ClassCastException(String.format(message, formatArgs));
132             result.initCause(cause);
133             return result;
134         }
135 
136     }
137 
Parser()138     private Parser() {
139     }
140 }
141