Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed 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.wildfly.common.rpc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;
import org.wildfly.common.Assert;
import org.wildfly.common._private.CommonMessages;
/**
* A remote exception cause. Instances of this class are intended to aid with diagnostics and are not intended to be
* directly thrown. They may be added to other exception types as a cause or suppressed throwable.
*
* @author David M. Lloyd
*/
public final class RemoteExceptionCause extends Throwable {
private static final long serialVersionUID = 7849011228540958997L;
private static final ClassValue>> fieldGetterValue = new ClassValue>>() {
protected Function> computeValue(final Class> type) {
final Field[] fields = type.getFields();
final int length = fields.length;
int i, j;
for (i = 0, j = 0; i < length; i ++) {
if ((fields[i].getModifiers() & (Modifier.STATIC | Modifier.PUBLIC)) == Modifier.PUBLIC) {
fields[j ++] = fields[i];
}
}
final int finalLength = j;
final Field[] finalFields;
if (j < i) {
finalFields = Arrays.copyOf(fields, j);
} else {
finalFields = fields;
}
if (finalLength == 0) {
return t -> Collections.emptyMap();
} else if (finalLength == 1) {
final Field field = finalFields[0];
return t -> {
try {
return Collections.singletonMap(field.getName(), String.valueOf(field.get(t)));
} catch (IllegalAccessException e) {
// impossible
throw new IllegalStateException(e);
}
};
}
return t -> {
Map map = new TreeMap<>();
for (Field field : finalFields) {
try {
map.put(field.getName(), String.valueOf(field.get(t)));
} catch (IllegalAccessException e) {
// impossible
throw new IllegalStateException(e);
}
}
return Collections.unmodifiableMap(map);
};
}
};
private static final StackTraceElement[] EMPTY_STACK = new StackTraceElement[0];
private final String exceptionClassName;
private final Map fields;
private transient String toString;
RemoteExceptionCause(final String msg, final RemoteExceptionCause cause, final String exceptionClassName, final Map fields, boolean cloneFields) {
super(msg);
if (cause != null) {
initCause(cause);
}
Assert.checkNotNullParam("exceptionClassName", exceptionClassName);
this.exceptionClassName = exceptionClassName;
if (cloneFields) {
final Iterator> iterator = fields.entrySet().iterator();
if (! iterator.hasNext()) {
this.fields = Collections.emptyMap();
} else {
final Map.Entry e1 = iterator.next();
final String name1 = e1.getKey();
final String value1 = e1.getValue();
if (name1 == null || value1 == null) {
throw CommonMessages.msg.cannotContainNullFieldNameOrValue();
}
if (! iterator.hasNext()) {
this.fields = Collections.singletonMap(name1, value1);
} else {
Map map = new TreeMap<>();
map.put(name1, value1);
do {
final Map.Entry next = iterator.next();
map.put(next.getKey(), next.getValue());
} while (iterator.hasNext());
this.fields = Collections.unmodifiableMap(map);
}
}
} else {
this.fields = fields;
}
}
/**
* Constructs a new {@code RemoteExceptionCause} instance with an initial message. No
* cause is specified.
*
* @param msg the message
* @param exceptionClassName the name of the exception's class (must not be {@code null})
*/
public RemoteExceptionCause(final String msg, final String exceptionClassName) {
this(msg, null, exceptionClassName, Collections.emptyMap(), false);
}
/**
* Constructs a new {@code RemoteExceptionCause} instance with an initial message and cause.
*
* @param msg the message
* @param cause the cause
* @param exceptionClassName the name of the exception's class (must not be {@code null})
*/
public RemoteExceptionCause(final String msg, final RemoteExceptionCause cause, final String exceptionClassName) {
this(msg, cause, exceptionClassName, Collections.emptyMap(), false);
}
/**
* Constructs a new {@code RemoteExceptionCause} instance with an initial message. No
* cause is specified.
*
* @param msg the message
* @param exceptionClassName the name of the exception's class (must not be {@code null})
* @param fields the public fields of the remote exception (must not be {@code null})
*/
public RemoteExceptionCause(final String msg, final String exceptionClassName, final Map fields) {
this(msg, null, exceptionClassName, fields, true);
}
/**
* Constructs a new {@code RemoteExceptionCause} instance with an initial message and cause.
*
* @param msg the message
* @param cause the cause
* @param exceptionClassName the name of the exception's class (must not be {@code null})
* @param fields the public fields of the remote exception (must not be {@code null})
*/
public RemoteExceptionCause(final String msg, final RemoteExceptionCause cause, final String exceptionClassName, final Map fields) {
this(msg, cause, exceptionClassName, fields, true);
}
/**
* Get a remote exception cause for the given {@link Throwable}. All of the cause and suppressed exceptions will
* also be converted.
*
* @param t the throwable, or {@code null}
* @return the remote exception cause, or {@code null} if {@code null} was passed in
*/
public static RemoteExceptionCause of(Throwable t) {
return of(t, new IdentityHashMap<>());
}
private static RemoteExceptionCause of(Throwable t, IdentityHashMap seen) {
if (t == null) return null;
if (t instanceof RemoteExceptionCause) {
return (RemoteExceptionCause) t;
} else {
final RemoteExceptionCause existing = seen.get(t);
if (existing != null) {
return existing;
}
final RemoteExceptionCause e = new RemoteExceptionCause(t.getMessage(), t.getClass().getName(), fieldGetterValue.get(t.getClass()).apply(t));
e.setStackTrace(t.getStackTrace());
seen.put(t, e);
final Throwable cause = t.getCause();
if (cause != null) e.initCause(of(cause, seen));
for (Throwable throwable : t.getSuppressed()) {
e.addSuppressed(of(throwable, seen));
}
return e;
}
}
/**
* Convert this remote exception cause to a plain throwable for sending to peers which use serialization and do not
* have this class present. Note that this does not recursively apply; normally, a serialization framework will
* handle the recursive application of this operation through object resolution.
*
* @return the throwable (not {@code null})
*/
public Throwable toPlainThrowable() {
final Throwable throwable = new Throwable(toString(), getCause());
throwable.setStackTrace(getStackTrace());
for (Throwable s : getSuppressed()) {
throwable.addSuppressed(s);
}
return throwable;
}
/**
* Get the original exception class name.
*
* @return the original exception class name (not {@code null})
*/
public String getExceptionClassName() {
return exceptionClassName;
}
/**
* Get the field names of the remote exception.
*
* @return the field names of the remote exception
*/
public Set getFieldNames() {
return fields.keySet();
}
/**
* Get the string value of the given field name.
*
* @param fieldName the name of the field (must not be {@code null})
* @return the string value of the given field name
*/
public String getFieldValue(String fieldName) {
Assert.checkNotNullParam("fieldName", fieldName);
return fields.get(fieldName);
}
/**
* Get a string representation of this exception. The representation will return an indication of the fact that
* this was a remote exception, the remote exception type, and optionally details of the exception content, followed
* by the exception message.
*
* @return the string representation of the exception
*/
public String toString() {
final String toString = this.toString;
if (toString == null) {
final String message = getMessage();
StringBuilder b = new StringBuilder();
b.append(message == null ? CommonMessages.msg.remoteException(exceptionClassName) : CommonMessages.msg.remoteException(exceptionClassName, message));
Iterator> iterator = fields.entrySet().iterator();
if (iterator.hasNext()) {
b.append("\n\tPublic fields:");
do {
final Map.Entry entry = iterator.next();
b.append('\n').append('\t').append('\t').append(entry.getKey()).append('=').append(entry.getValue());
} while (iterator.hasNext());
}
return this.toString = b.toString();
}
return toString;
}
// Format:
// class name
// null | message
// stack trace
// count ( field-name field-value )*
// null | caused-by
// count suppressed*
// Add new data to the end; old versions must ignore extra data
private static final int ST_NULL = 0;
private static final int ST_NEW_STRING = 1; // utf8 data follows
private static final int ST_NEW_STACK_ELEMENT_V8 = 2; // string string string int
private static final int ST_NEW_STACK_ELEMENT_V9 = 3; // string string string string string string int
private static final int ST_NEW_EXCEPTION_CAUSE = 4; // recurse
private static final int ST_INT8 = 5; // one byte
private static final int ST_INT16 = 6; // two bytes
private static final int ST_INT32 = 7; // four bytes
private static final int ST_INT_MINI = 0x20; // low 5 bits == signed value
private static final int ST_BACKREF_FAR = 0x40; // low 6 bits + next byte are distance
private static final int ST_BACKREF_NEAR = 0x80; // low 7 bits are distance
/**
* Write this remote exception cause to the given stream, without using serialization.
*
* @param output the output stream (must not be {@code null})
* @throws IOException if an error occurs writing the data
*/
public void writeToStream(DataOutput output) throws IOException {
Assert.checkNotNullParam("output", output);
writeToStream(output, new IdentityIntMap