Skip to content

Commit

Permalink
refactor: standardize Seata Exception (#6269)
Browse files Browse the repository at this point in the history
  • Loading branch information
slievrly authored Feb 21, 2024
1 parent c08345e commit ed41072
Show file tree
Hide file tree
Showing 10 changed files with 551 additions and 0 deletions.
3 changes: 3 additions & 0 deletions changes/en-us/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#6356](https://github.com/apache/incubator-seata/pull/6356)] remove authentication from the health check page
- [[#6360](https://github.com/apache/incubator-seata/pull/6360)] optimize 401 issues for some links

### refactor:
- [[#6269](https://github.com/apache/incubator-seata/pull/6269)] standardize Seata Exception

### security:
- [[#6069](https://github.com/apache/incubator-seata/pull/6069)] Upgrade Guava dependencies to fix security vulnerabilities
- [[#6145](https://github.com/apache/incubator-seata/pull/6145)] upgrade jettison to 1.5.4
Expand Down
3 changes: 3 additions & 0 deletions changes/zh-cn/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@
- [[#6350](https://github.com/apache/incubator-seata/pull/6350)] 移除 enableDegrade 配置


### refactor:
- [[#6269](https://github.com/apache/incubator-seata/pull/6269)] 统一Seata异常规范

### security:
- [[#6069](https://github.com/apache/incubator-seata/pull/6069)] 升级Guava依赖版本,修复安全漏洞
- [[#6144](https://github.com/apache/incubator-seata/pull/6144)] 升级Nacos依赖版本至1.4.6
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.seata.common.exception;

import java.util.ResourceBundle;

public abstract class AbstractRemoteResourceBundle extends ResourceBundle {

}
102 changes: 102 additions & 0 deletions common/src/main/java/org/apache/seata/common/exception/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.seata.common.exception;

/**
* The enum Error code.
*/
public enum ErrorCode {

/**
* 0001 ~ 0099 Configuration related errors
*/
ERR_CONFIG(ErrorType.Config, 0001);
/**
* The error code of the transaction exception.
*/

private int code;
private ErrorType type;

ErrorCode(ErrorType type, int code) {
this.code = code;
this.type = type;
}

/**
* Gets code.
*
* @return the code
*/
public int getCode() {
return code;
}

/**
* Gets type.
*
* @return the type
*/
public String getType() {
return type.name();
}

/**
* Gets message.
*
* @param params the params
* @return the message
*/
public String getMessage(String... params) {
return ResourceBundleUtil.getInstance().getMessage(this.name(), this.getCode(), this.getType(), params);
}

/**
* The enum Error type.
*/
enum ErrorType {
/**
* Config error type.
*/
Config,
/**
* Network error type.
*/
Network,
/**
* Tm error type.
*/
TM,
/**
* Rm error type.
*/
RM,
/**
* Tc error type.
*/
TC,
/**
* Datasource error type.
*/
Datasource,
/**
* Other error type.
*/
Other;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* The enum Framework error code.
*
*/
@Deprecated
public enum FrameworkErrorCode {
/**
* 0001 ~ 0099 Configuration related errors
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.seata.common.exception;

import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.seata.common.loader.EnhancedServiceLoader;

public class ResourceBundleUtil {

private static final Locale LOCALE = new Locale("en", "US");
private static final ResourceBundleUtil INSTANCE = new ResourceBundleUtil("error/ErrorCode", LOCALE);
private ResourceBundle localBundle;
private AbstractRemoteResourceBundle remoteBundle;

public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";

public static ResourceBundleUtil getInstance() {
return INSTANCE;
}

public ResourceBundleUtil(String bundleName, Locale local) {

this.localBundle = ResourceBundle.getBundle(bundleName, local);
try {
this.remoteBundle = EnhancedServiceLoader.load(AbstractRemoteResourceBundle.class);
} catch (Throwable e) {
//ignore
}
}

public String getMessage(String key, String... params) {
if (StringUtils.isBlank(key)) {
return null;
}
StringBuilder sb = new StringBuilder();
sb.append(getFormattedMessage(key));
String msg = parseStringValue(sb.toString(), new HashSet<String>());
if (params == null || params.length == 0) {
return msg;
}
if (StringUtils.isBlank(msg)) {
return msg;
}
return MessageFormat.format(msg, (Object[])params);
}

public String getMessage(String key, int code, String type, String... params) {
if (StringUtils.isBlank(key)) {
return null;
}
StringBuilder sb = new StringBuilder();

sb.append(getFormattedMessage("ERR_PREFIX")).append(" ").append(getFormattedMessage(key)).append(" ").append(
getFormattedMessage("ERR_POSTFIX"));
String msg = sb.toString();
msg = parseStringValue(msg, new HashSet<String>());
msg = StringUtils.replace(msg, "{code}", String.valueOf(code));
msg = StringUtils.replace(msg, "{type}", String.valueOf(type));
msg = StringUtils.replace(msg, "{key}", key);

if (params == null || params.length == 0) {
return msg;
}
if (StringUtils.isBlank(msg)) {
return msg;
}
return MessageFormat.format(msg, (Object[])params);
}

protected String getFormattedMessage(String key) {
String value = StringUtils.EMPTY;
if (remoteBundle != null && remoteBundle.containsKey(key)) {
value = remoteBundle.getString(key);
}
if (StringUtils.isEmpty(value)) {
value = localBundle.getString(key);
}
return value;
}

protected String parseStringValue(String strVal, Set<String> visitedPlaceholders) {
StringBuffer buf = new StringBuffer(strVal);
int startIndex = strVal.indexOf(DEFAULT_PLACEHOLDER_PREFIX);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(buf, startIndex);
if (endIndex != -1) {
String placeholder = buf.substring(startIndex + DEFAULT_PLACEHOLDER_PREFIX.length(), endIndex);
if (!visitedPlaceholders.add(placeholder)) {
throw new SeataRuntimeException(ErrorCode.ERR_CONFIG,
"Duplicate placeholders exist '" + placeholder + "' in bundle.");
}
placeholder = parseStringValue(placeholder, visitedPlaceholders);
try {
String propVal = resolvePlaceholder(placeholder);
if (propVal != null) {
propVal = parseStringValue(propVal, visitedPlaceholders);
buf.replace(startIndex, endIndex + DEFAULT_PLACEHOLDER_SUFFIX.length(), propVal);
startIndex = buf.indexOf(DEFAULT_PLACEHOLDER_PREFIX, startIndex + propVal.length());
} else {
throw new SeataRuntimeException(ErrorCode.ERR_CONFIG,
"Could not resolve placeholder '" + placeholder + "'");
}
} catch (Exception ex) {
throw new SeataRuntimeException(ErrorCode.ERR_CONFIG,
"Could not resolve placeholder '" + placeholder + "'");
}
visitedPlaceholders.remove(placeholder);
} else {
startIndex = -1;
}
}

return buf.toString();
}

private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + DEFAULT_PLACEHOLDER_PREFIX.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (matchSubString(buf, index, DEFAULT_PLACEHOLDER_SUFFIX)) {
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;
index = index + DEFAULT_PLACEHOLDER_SUFFIX.length();
} else {
return index;
}
} else if (matchSubString(buf, index, DEFAULT_PLACEHOLDER_PREFIX)) {
withinNestedPlaceholder++;
index = index + DEFAULT_PLACEHOLDER_PREFIX.length();
} else {
index++;
}
}
return -1;
}

private boolean matchSubString(CharSequence str, int index, CharSequence substring) {
for (int j = 0; j < substring.length(); j++) {
int i = index + j;
if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {
return false;
}
}
return true;
}

private String resolvePlaceholder(String placeholder) {
return getFormattedMessage(placeholder);
}

}
Loading

0 comments on commit ed41072

Please sign in to comment.