ScopedException.java revision fd8342a51a96282df315cd27055ba539e89a8c9e
1/* 2 * Copyright (C) 2015 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 17package android.databinding.tool.processing; 18 19import org.apache.commons.lang3.StringUtils; 20 21import android.databinding.tool.store.Location; 22import android.databinding.tool.util.L; 23 24import java.util.ArrayList; 25import java.util.List; 26import java.util.regex.Matcher; 27import java.util.regex.Pattern; 28 29/** 30 * An exception that contains scope information. 31 */ 32public class ScopedException extends RuntimeException { 33 public static final String ERROR_LOG_PREFIX = "****/ data binding error ****"; 34 public static final String ERROR_LOG_SUFFIX = "****\\ data binding error ****"; 35 public static final String MSG_KEY = "msg:"; 36 public static final String LOCATION_KEY = "loc:"; 37 public static final String FILE_KEY = "file:"; 38 private static boolean sEncodeOutput = false; 39 private ScopedErrorReport mScopedErrorReport; 40 private String mScopeLog; 41 42 public ScopedException(String message, Object... args) { 43 super(message == null ? "unknown data binding exception" : 44 args.length == 0 ? message : String.format(message, args)); 45 mScopedErrorReport = Scope.createReport(); 46 mScopeLog = L.isDebugEnabled() ? Scope.produceScopeLog() : null; 47 } 48 49 ScopedException(String message, ScopedErrorReport scopedErrorReport) { 50 super(message); 51 mScopedErrorReport = scopedErrorReport; 52 } 53 54 public String getBareMessage() { 55 return super.getMessage(); 56 } 57 58 @Override 59 public String getMessage() { 60 return sEncodeOutput ? createEncodedMessage() : createHumanReadableMessage(); 61 } 62 63 private String createHumanReadableMessage() { 64 ScopedErrorReport scopedError = getScopedErrorReport(); 65 StringBuilder sb = new StringBuilder(); 66 sb.append(super.getMessage()).append("\n") 67 .append("file://").append(scopedError.getFilePath()); 68 if (scopedError.getLocations() != null && scopedError.getLocations().size() > 0) { 69 sb.append(" Line:"); 70 sb.append(scopedError.getLocations().get(0).startLine); 71 } 72 sb.append("\n"); 73 return sb.toString(); 74 } 75 76 private String createEncodedMessage() { 77 ScopedErrorReport scopedError = getScopedErrorReport(); 78 StringBuilder sb = new StringBuilder(); 79 sb.append(ERROR_LOG_PREFIX) 80 .append(MSG_KEY).append(super.getMessage()).append("\n") 81 .append(FILE_KEY).append(scopedError.getFilePath()).append("\n"); 82 if (scopedError.getLocations() != null) { 83 for (Location location : scopedError.getLocations()) { 84 sb.append(LOCATION_KEY).append(location.toUserReadableString()).append("\n"); 85 } 86 } 87 sb.append(ERROR_LOG_SUFFIX); 88 return StringUtils.join(StringUtils.split(sb.toString(), System.lineSeparator()), " "); 89 } 90 91 public ScopedErrorReport getScopedErrorReport() { 92 return mScopedErrorReport; 93 } 94 95 public boolean isValid() { 96 return mScopedErrorReport.isValid(); 97 } 98 99 public static ScopedException createFromOutput(String output) { 100 String message = ""; 101 String file = ""; 102 List<Location> locations = new ArrayList<>(); 103 int msgStart = output.indexOf(MSG_KEY); 104 if (msgStart < 0) { 105 message = output; 106 } else { 107 int fileStart = output.indexOf(FILE_KEY, msgStart + MSG_KEY.length()); 108 if (fileStart < 0) { 109 message = output; 110 } else { 111 message = output.substring(msgStart + MSG_KEY.length(), fileStart); 112 int locStart = output.indexOf(LOCATION_KEY, fileStart + FILE_KEY.length()); 113 if (locStart < 0) { 114 file = output.substring(fileStart + FILE_KEY.length()); 115 } else { 116 file = output.substring(fileStart + FILE_KEY.length(), locStart); 117 int nextLoc = 0; 118 while(nextLoc >= 0) { 119 nextLoc = output.indexOf(LOCATION_KEY, locStart + LOCATION_KEY.length()); 120 Location loc; 121 if (nextLoc < 0) { 122 loc = Location.fromUserReadableString( 123 output.substring(locStart + LOCATION_KEY.length())); 124 } else { 125 loc = Location.fromUserReadableString( 126 output.substring(locStart + LOCATION_KEY.length(), nextLoc)); 127 } 128 if (loc != null && loc.isValid()) { 129 locations.add(loc); 130 } 131 locStart = nextLoc; 132 } 133 } 134 } 135 } 136 return new ScopedException(message.trim(), 137 new ScopedErrorReport(StringUtils.isEmpty(file) ? null : file.trim(), locations)); 138 } 139 140 public static List<ScopedException> extractErrors(String output) { 141 List<ScopedException> errors = new ArrayList<>(); 142 int index = output.indexOf(ERROR_LOG_PREFIX); 143 final int limit = output.length(); 144 while (index >= 0 && index < limit) { 145 int end = output.indexOf(ERROR_LOG_SUFFIX, index + ERROR_LOG_PREFIX.length()); 146 if (end == -1) { 147 errors.add(createFromOutput(output.substring(index + ERROR_LOG_PREFIX.length()))); 148 break; 149 } else { 150 errors.add(createFromOutput(output.substring(index + ERROR_LOG_PREFIX.length(), 151 end))); 152 index = output.indexOf(ERROR_LOG_PREFIX, end + ERROR_LOG_SUFFIX.length()); 153 } 154 } 155 return errors; 156 } 157 158 public static void encodeOutput(boolean encodeOutput) { 159 sEncodeOutput = encodeOutput; 160 } 161} 162