2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mybmw.internal.handler.backend;
15 import java.util.regex.Pattern;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
22 * anonymizes all occurrencies of locations and vins
24 * @author Bernd Weymann - Initial contribution
25 * @author Martin Grassl - refactoring & extension for any occurrence
26 * @author Mark Herwege - extended log anonymization
29 public interface ResponseContentAnonymizer {
31 static final String ANONYMOUS_VIN = "anonymousVin";
32 static final String VIN_PATTERN = "\"vin\":";
33 static final String VEHICLE_CHARGING_LOCATION_PATTERN = "\"subtitle\":";
34 static final String VEHICLE_LOCATION_PATTERN = "\"location\":";
35 static final String VEHICLE_LOCATION_LATITUDE_PATTERN = "latitude";
36 static final String VEHICLE_LOCATION_LONGITUDE_PATTERN = "longitude";
37 static final String VEHICLE_LOCATION_FORMATTED_PATTERN = "formatted";
38 static final String VEHICLE_LOCATION_HEADING_PATTERN = "heading";
39 static final String VEHICLE_LOCATION_LATITUDE = "1.1";
40 static final String VEHICLE_LOCATION_LONGITUDE = "2.2";
41 static final String ANONYMOUS_ADDRESS = "anonymousAddress";
42 static final String VEHICLE_LOCATION_HEADING = "-1";
43 static final String RAW_VEHICLE_LOCATION_PATTERN_START = "\\\"location\\\"";
44 static final String RAW_VEHICLE_LOCATION_PATTERN_END = "\\\"heading\\\"";
45 static final String RAW_VEHICLE_LOCATION_PATTERN_REPLACER = "\"location\":{\"coordinates\":{\"latitude\":"
46 + VEHICLE_LOCATION_LATITUDE + ",\"longitude\":" + VEHICLE_LOCATION_LONGITUDE
47 + "},\"address\":{\"formatted\":\"" + ANONYMOUS_ADDRESS + "\"},";
49 static final String CLOSING_BRACKET = "}";
50 static final String QUOTE = "\"";
51 static final String CLOSE_VALUE = "\":";
52 static final String COMMA = ",";
55 * anonymizes the responseContent
63 * @param responseContent
66 public static String anonymizeResponseContent(@Nullable String responseContent) {
67 if (responseContent == null) {
71 String anonymizedVinString = replaceVins(responseContent);
73 String anonymizedLocationString = replaceLocations(anonymizedVinString);
75 String anonymizedRawLocationString = replaceRawLocations(anonymizedLocationString);
77 String anonymizedChargingLocationString = replaceChargingLocations(anonymizedRawLocationString);
79 return anonymizedChargingLocationString;
82 static String replaceChargingLocations(String stringToBeReplaced) {
83 String[] locationStrings = stringToBeReplaced.split(VEHICLE_CHARGING_LOCATION_PATTERN);
85 StringBuffer replacedString = new StringBuffer();
86 replacedString.append(locationStrings[0]);
87 for (int i = 1; locationStrings.length > 0 && i < locationStrings.length && locationStrings[i] != null; i++) {
88 replacedString.append(VEHICLE_CHARGING_LOCATION_PATTERN);
89 replacedString.append(replaceChargingLocation(locationStrings[i]));
92 return replacedString.toString();
95 static String replaceChargingLocation(String responseContent) {
96 String[] subtitleStrings = responseContent.split(" • ", 2);
98 StringBuffer replacedString = new StringBuffer();
100 replacedString.append("\"");
101 replacedString.append(ANONYMOUS_ADDRESS);
102 if (subtitleStrings.length > 1) {
103 replacedString.append(" • ");
104 replacedString.append(subtitleStrings[1]);
107 return replacedString.toString();
110 static String replaceRawLocations(String stringToBeReplaced) {
111 String[] locationStrings = stringToBeReplaced.split(Pattern.quote(RAW_VEHICLE_LOCATION_PATTERN_START));
113 StringBuffer replacedString = new StringBuffer();
114 replacedString.append(locationStrings[0]);
115 for (int i = 1; locationStrings.length > 0 && i < locationStrings.length && locationStrings[i] != null; i++) {
116 replacedString.append(replaceRawLocation(locationStrings[i]));
119 return replacedString.toString();
123 * this just replaces a string
128 static String replaceRawLocation(String stringToBeReplaced) {
129 String[] stringParts = stringToBeReplaced.split(Pattern.quote(RAW_VEHICLE_LOCATION_PATTERN_END));
131 StringBuffer replacedString = new StringBuffer();
132 replacedString.append(RAW_VEHICLE_LOCATION_PATTERN_REPLACER);
133 replacedString.append(RAW_VEHICLE_LOCATION_PATTERN_END);
134 replacedString.append(stringParts[1]);
135 return replacedString.toString();
138 static String replaceLocations(String stringToBeReplaced) {
139 String[] locationStrings = stringToBeReplaced.split(VEHICLE_LOCATION_PATTERN);
141 StringBuffer replacedString = new StringBuffer();
142 replacedString.append(locationStrings[0]);
143 for (int i = 1; locationStrings.length > 0 && i < locationStrings.length && locationStrings[i] != null; i++) {
144 replacedString.append(VEHICLE_LOCATION_PATTERN);
145 replacedString.append(replaceLocation(locationStrings[i]));
148 return replacedString.toString();
151 static String replaceLocation(String responseContent) {
152 String stringToBeReplaced = responseContent;
154 StringBuffer replacedString = new StringBuffer();
156 stringToBeReplaced = replaceNumberValue(stringToBeReplaced, replacedString, VEHICLE_LOCATION_LATITUDE_PATTERN,
157 VEHICLE_LOCATION_LATITUDE);
160 stringToBeReplaced = replaceNumberValue(stringToBeReplaced, replacedString, VEHICLE_LOCATION_LONGITUDE_PATTERN,
161 VEHICLE_LOCATION_LONGITUDE);
164 stringToBeReplaced = replaceStringValue(stringToBeReplaced, replacedString, VEHICLE_LOCATION_FORMATTED_PATTERN,
168 stringToBeReplaced = replaceNumberValue(stringToBeReplaced, replacedString, VEHICLE_LOCATION_HEADING_PATTERN,
169 VEHICLE_LOCATION_HEADING);
171 replacedString.append(stringToBeReplaced);
173 return replacedString.toString();
176 static String replaceNumberValue(String stringToBeReplaced, StringBuffer replacedString, String replacerPattern,
177 String replacerValue) {
178 int startIndex = stringToBeReplaced.indexOf(replacerPattern, 1)
179 + (replacerPattern.length() + CLOSE_VALUE.length());
182 // in an object, the comma comes after the value or a closing bracket
183 if (stringToBeReplaced.indexOf(COMMA, startIndex) < stringToBeReplaced.indexOf(CLOSING_BRACKET, startIndex)) {
184 endIndex = stringToBeReplaced.indexOf(COMMA, startIndex);
186 endIndex = stringToBeReplaced.indexOf(CLOSING_BRACKET, startIndex);
189 replacedString.append(stringToBeReplaced.substring(0, startIndex));
190 replacedString.append(replacerValue);
192 return stringToBeReplaced.substring(endIndex);
195 static String replaceStringValue(String stringToBeReplaced, StringBuffer replacedString, String replacerPattern,
196 String replacerValue) {
197 // the startIndex is the String after the first quote of the value after the key
199 int startIndex = stringToBeReplaced.indexOf(replacerPattern, 1)
200 + (replacerPattern.length() + CLOSE_VALUE.length());
201 // detect start of value
202 startIndex = stringToBeReplaced.indexOf(QUOTE, startIndex) + 1;
204 // detect end of value
205 int endIndex = stringToBeReplaced.indexOf(QUOTE, startIndex);
207 replacedString.append(stringToBeReplaced.substring(0, startIndex));
208 replacedString.append(replacerValue);
210 return stringToBeReplaced.substring(endIndex);
213 static String replaceVins(String stringToBeReplaced) {
214 String[] vinStrings = stringToBeReplaced.split(VIN_PATTERN);
216 StringBuffer replacedString = new StringBuffer();
217 replacedString.append(vinStrings[0]);
218 for (int i = 1; vinStrings.length > 0 && i < vinStrings.length; i++) {
219 replacedString.append(VIN_PATTERN);
220 replacedString.append(replaceVin(vinStrings[i]));
223 return replacedString.toString();
226 static String replaceVin(String stringToBeReplaced) {
227 // the vin is between two quotes
228 int startIndex = stringToBeReplaced.indexOf(QUOTE) + 1;
229 int endIndex = stringToBeReplaced.indexOf(QUOTE, startIndex);
231 StringBuffer replacedString = new StringBuffer();
232 replacedString.append(stringToBeReplaced.substring(0, startIndex));
233 replacedString.append(ANONYMOUS_VIN);
234 replacedString.append(stringToBeReplaced.substring(endIndex));
236 return replacedString.toString();
239 static @Nullable String replaceVin(@Nullable String stringToBeReplaced, @Nullable String vin) {
240 if (stringToBeReplaced == null) {
243 return vin != null ? stringToBeReplaced.replace(vin, ANONYMOUS_VIN) : stringToBeReplaced;