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