• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.timezone.location.common;
17 
18 import androidx.annotation.NonNull;
19 import androidx.annotation.Nullable;
20 
21 import java.util.Arrays;
22 import java.util.Objects;
23 import java.util.function.Function;
24 
25 /** Utility methods to support {@link PiiLoggable}. */
26 public final class PiiLoggables {
27 
28     static final String NULL_STRING = "null";
29     static final String REDACTED_STRING = "<redacted>";
30 
PiiLoggables()31     private PiiLoggables() {}
32 
33     /**
34      * Returns a null-safe function that calls {@link PiiLoggable#toPiiString(PiiLoggable)} when the
35      * function's argument is not {@code null}.
36      */
37     @NonNull
toPiiStringFunction()38     public static <V extends PiiLoggable> Function<V, String> toPiiStringFunction() {
39         return x -> PiiLoggable.toPiiString(x);
40     }
41 
42     /**
43      * An adapter / wrapper for objects that output PII as part of their normal {@link #toString()}.
44      * The referenced value can be {@code null}.
45      *
46      * <p>The implementation contract:
47      * <ul>
48      * <li>{@link #toPiiString()} must print {@code "null"} if the value is null, and may delegate
49      * to the value's {@link #toString()}.</li>
50      * <li>{@link #toString()} must print {@code "null"} if the value is null, or a PII safe string,
51      * e.g. "&lt;redacted&gt;", or just non-PII information.
52      * <li>Implementations may implement {@link #equals(Object)} and {@link #hashCode()}.</li>
53      * </ul>
54      *
55      * <p>See {@link #fromPiiValue(Object)} for a method that returns objects that implement a
56      * minimal contract.
57      */
58     public interface PiiLoggableValue<V> extends PiiLoggable {
59         /** Returns the held value. */
get()60         @Nullable V get();
61     }
62 
63     /**
64      * Wraps a nullable reference in a {@link PiiLoggableValue}. {@link Object#toString()}
65      * returns the string {@code "<redacted>"}. {@link Object#equals(Object)} and {@link
66      * Object#hashCode()} delegate to {@code value} when not {@code null}.
67      */
68     @NonNull
fromPiiValue(@ullable V value)69     public static <V> PiiLoggableValue<V> fromPiiValue(@Nullable V value) {
70         class PiiLoggableValueImpl<V> implements PiiLoggableValue<V> {
71 
72             private final V mValue;
73 
74             PiiLoggableValueImpl(V value) {
75                 mValue = value;
76             }
77 
78             @Override
79             public V get() {
80                 return mValue;
81             }
82 
83             @Override
84             public String toPiiString() {
85                 return String.valueOf(mValue);
86             }
87 
88             @Override
89             public String toString() {
90                 return mValue == null ? NULL_STRING : REDACTED_STRING;
91             }
92 
93             @Override
94             public boolean equals(Object o) {
95                 if (this == o) {
96                     return true;
97                 }
98                 if (o == null || getClass() != o.getClass()) {
99                     return false;
100                 }
101                 PiiLoggableValueImpl<?> that = (PiiLoggableValueImpl<?>) o;
102                 return Objects.equals(mValue, that.mValue);
103             }
104 
105             @Override
106             public int hashCode() {
107                 return Objects.hash(mValue);
108             }
109         }
110         return new PiiLoggableValueImpl<V>(value);
111     }
112 
113     /**
114      * A convenience method for creating a {@link PiiLoggable} from a {@link String} that doesn't
115      * contain PII. Both {@link PiiLoggable#toString()} and {@link PiiLoggable#toPiiString()} will
116      * return {@code "null"} if the string is {@code null}, or the result of calling {@link
117      * Object#toString()} if the string is not {@code null}.
118      */
119     @NonNull
fromString(@ullable String s)120     public static PiiLoggable fromString(@Nullable String s) {
121         class PiiLoggableString implements PiiLoggable {
122 
123             private final String mString;
124 
125             public PiiLoggableString(String string) {
126                 mString = string;
127             }
128 
129             @Override
130             public String toPiiString() {
131                 return toString();
132             }
133 
134             @Override
135             public String toString() {
136                 return String.valueOf(mString);
137             }
138 
139             @Override
140             public boolean equals(Object o) {
141                 if (this == o) {
142                     return true;
143                 }
144                 if (o == null || getClass() != o.getClass()) {
145                     return false;
146                 }
147                 PiiLoggableString that = (PiiLoggableString) o;
148                 return Objects.equals(mString, that.mString);
149             }
150 
151             @Override
152             public int hashCode() {
153                 return Objects.hash(mString);
154             }
155         }
156         return new PiiLoggableString(s);
157     }
158 
159     /**
160      * Creates a {@link PiiLoggable} that generates strings using the supplied template. The
161      * resulting object uses {@link String#format(String, Object...)} for {@link
162      * PiiLoggable#toString()} and {@link PiiLoggables#formatPiiString(String, PiiLoggable...)} for
163      * {@link PiiLoggable#toPiiString()}.
164      */
165     @NonNull
fromTemplate(@onNull String template, PiiLoggable... piiLoggables)166     public static PiiLoggable fromTemplate(@NonNull String template, PiiLoggable... piiLoggables) {
167         class TemplatedPiiLoggable implements PiiLoggable {
168             @NonNull private final String mTemplate;
169             @NonNull private final PiiLoggable[] mLoggables;
170 
171             public TemplatedPiiLoggable(String template, PiiLoggable... loggables) {
172                 mTemplate = Objects.requireNonNull(template);
173                 mLoggables = Objects.requireNonNull(loggables);
174             }
175 
176             @Override
177             public String toString() {
178                 return String.format(mTemplate, (Object[]) mLoggables);
179             }
180 
181             @Override
182             public String toPiiString() {
183                 return PiiLoggables.formatPiiString(mTemplate, mLoggables);
184             }
185 
186             @Override
187             public boolean equals(Object o) {
188                 if (this == o) {
189                     return true;
190                 }
191                 if (o == null || getClass() != o.getClass()) {
192                     return false;
193                 }
194                 TemplatedPiiLoggable that = (TemplatedPiiLoggable) o;
195                 return mTemplate.equals(that.mTemplate) &&
196                         Arrays.equals(mLoggables, that.mLoggables);
197             }
198 
199             @Override
200             public int hashCode() {
201                 int result = Objects.hash(mTemplate);
202                 result = 31 * result + Arrays.hashCode(mLoggables);
203                 return result;
204             }
205         }
206 
207         return new TemplatedPiiLoggable(template, piiLoggables);
208     }
209 
210     /**
211      * Formats a templated string. This method operates like {@link
212      * String#format(String, Object...)} except {@code %s} will be replaced with the result of
213      * {@link PiiLoggable#toPiiString(PiiLoggable)} instead of {@link String#valueOf(Object)}.
214      */
215     @NonNull
formatPiiString(@onNull String format, PiiLoggable... piiLoggables)216     public static String formatPiiString(@NonNull String format, PiiLoggable... piiLoggables) {
217         String[] strings = new String[piiLoggables.length];
218         for (int i = 0; i < strings.length; i++) {
219             PiiLoggable piiLoggable = piiLoggables[i];
220             strings[i] = PiiLoggable.toPiiString(piiLoggable);
221         }
222         return String.format(format, (Object[]) strings);
223     }
224 }
225