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