private int writeStackTrace(final DataOutput output, final StackTraceElement[] stackTrace, final IdentityIntMap<Object> seen, final HashMap<String, String> stringCache, int cnt) throws IOException { // don't bother recording in seen because stack traces are always copied final int length = stackTrace.length; writePackedInt(output, length); for (StackTraceElement element : stackTrace) { cnt = writeStackElement(output, element, seen, stringCache, cnt); } return cnt; }
private int writeToStream(DataOutput output, IdentityIntMap<Object> seen, HashMap<String, String> stringCache, int cnt) throws IOException { // register in cycle map seen.put(this, cnt++); // write the header byte output.writeByte(ST_NEW_EXCEPTION_CAUSE); // first write class name cnt = writeString(output, exceptionClassName, seen, stringCache, cnt); // null or message cnt = writeString(output, getMessage(), seen, stringCache, cnt); // stack trace cnt = writeStackTrace(output, getStackTrace(), seen, stringCache, cnt); // fields cnt = writeFields(output, fields, seen, stringCache, cnt); // caused-by cnt = writeThrowable(output, getCause(), seen, stringCache, cnt); // suppressed final Throwable[] suppressed = getSuppressed(); writePackedInt(output, suppressed.length); for (final Throwable t : suppressed) { cnt = writeThrowable(output, t, seen, stringCache, cnt); } return cnt; }
/** * 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<>()); }
Object writeReplace() { final Throwable[] origSuppressed = getSuppressed(); final int length = origSuppressed.length; final RemoteExceptionCause[] suppressed; if (length == 0) { suppressed = NO_REMOTE_EXCEPTION_CAUSES; } else { suppressed = new RemoteExceptionCause[length]; for (int i = 0; i < length; i ++) { suppressed[i] = of(origSuppressed[i]); } } String[] fieldArray; final int size = fields.size(); if (size == 0) { fieldArray = NO_STRINGS; } else { fieldArray = new String[size << 1]; int i = 0; for (Map.Entry<String, String> entry : fields.entrySet()) { fieldArray[i++] = entry.getKey(); fieldArray[i++] = entry.getValue(); } } return new Serialized(getMessage(), exceptionClassName, of(getCause()), suppressed, getStackTrace(), fieldArray); }
String exClassName = readObject(input, String.class, cache, false); String exMessage = readObject(input, String.class, cache, true); int length = readPackedInt(input); StackTraceElement[] stackTrace; if (length == 0) { stackTrace = new StackTraceElement[length]; for (int i = 0; i < length; i++) { stackTrace[i] = readObject(input, StackTraceElement.class, cache, false); length = readPackedInt(input); if (length == 0) { fields = Collections.emptyMap(); } else if (length == 1) { fields = Collections.singletonMap(readObject(input, String.class, cache, false), readObject(input, String.class, cache, false)); } else { fields = new HashMap<>(length); for (int i = 0; i < length; i++) { fields.put(readObject(input, String.class, cache, false), readObject(input, String.class, cache, false)); final RemoteExceptionCause result = new RemoteExceptionCause(exMessage, null, exClassName, fields, false); cache.set(idx, result); RemoteExceptionCause causedBy = readObject(input, RemoteExceptionCause.class, cache, true); result.initCause(causedBy); length = readPackedInt(input); result.setStackTrace(stackTrace); for (int i = 0; i < length; i++) { result.addSuppressed(readObject(input, RemoteExceptionCause.class, cache, false));
private static RemoteExceptionCause of(Throwable t, IdentityHashMap<Throwable, RemoteExceptionCause> 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; } }
private int writeThrowable(final DataOutput output, final Throwable throwable, final IdentityIntMap<Object> seen, final HashMap<String, String> stringCache, final int cnt) throws IOException { if (throwable == null) { output.write(ST_NULL); return cnt; } else { final int idx = seen.get(throwable, - 1); final int distance = cnt - idx; if (idx == - 1 || distance >= 0x4000) { RemoteExceptionCause nested; if (throwable instanceof RemoteExceptionCause) { nested = (RemoteExceptionCause) throwable; } else { seen.put(throwable, cnt); // do not increment yet nested = of(throwable); } return nested.writeToStream(output, seen, stringCache, cnt); // this will increment it } else { if (distance < 127) { output.writeByte(ST_BACKREF_NEAR | distance); } else { assert distance <= 0x3fff; output.writeByte(ST_BACKREF_FAR | distance >> 8); output.writeByte(distance); } return cnt; } } }
/** * 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; }
private int writeStackElement(final DataOutput output, final StackTraceElement element, final IdentityIntMap<Object> seen, final HashMap<String, String> stringCache, int cnt) throws IOException { final int idx = seen.get(element, - 1); final int distance = cnt - idx; if (idx == -1 || distance > (1 << 14) - 1) { output.write(ST_NEW_STACK_ELEMENT_V8); cnt = writeString(output, element.getClassName(), seen, stringCache, cnt); cnt = writeString(output, element.getMethodName(), seen, stringCache, cnt); cnt = writeString(output, element.getFileName(), seen, stringCache, cnt); writePackedInt(output, element.getLineNumber()); seen.put(element, cnt++); return cnt; } else { if (distance < 127) { output.writeByte(ST_BACKREF_NEAR | distance); } else { assert distance <= 0x3fff; output.writeByte(ST_BACKREF_FAR | distance >> 8); output.writeByte(distance); } return cnt; } }
private void writeExceptionResponse(final int msgId, final int invId, final int exceptionKind, final Exception e, int errorCode) { try (final MessageOutputStream outputStream = messageTracker.openMessageUninterruptibly()) { outputStream.writeShort(invId); outputStream.writeByte(msgId); writeInt8(outputStream, exceptionKind); final RemoteExceptionCause remoteExceptionCause = RemoteExceptionCause.of(e); final ByteArrayOutputStream os = new ByteArrayOutputStream(); final DataOutputStream dos = new DataOutputStream(os); dos.writeInt(errorCode); remoteExceptionCause.writeToStream(dos); dos.flush(); writePackedUnsignedInt31(outputStream, os.size()); os.writeTo(outputStream); } catch (IOException ioe) { log.outboundException(ioe); } }
Object readResolve() { final Map<String, String> fields; if (f == null) { fields = Collections.emptyMap(); } else { final int fl = f.length; if ((fl & 1) != 0) { throw CommonMessages.msg.invalidOddFields(); } else if (fl == 0) { fields = Collections.emptyMap(); } else if (fl == 2) { fields = Collections.singletonMap(f[0], f[1]); } else { final TreeMap<String, String> map = new TreeMap<>(); for (int i = 0; i < fl; i += 2) { map.put(f[i], f[i + 1]); } fields = Collections.unmodifiableMap(map); } } final RemoteExceptionCause ex = new RemoteExceptionCause(m, c, cn, fields, false); ex.setStackTrace(st); final RemoteExceptionCause[] suppressed = s; if (suppressed != null) for (RemoteExceptionCause c : suppressed) { ex.addSuppressed(c); } return ex; } }
/** * 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<Object>(), new HashMap<String,String>(), 0); }
private int writeFields(final DataOutput output, final Map<String, String> fields, final IdentityIntMap<Object> seen, final HashMap<String, String> stringCache, int cnt) throws IOException { writePackedInt(output, fields.size()); for (Map.Entry<String, String> entry : fields.entrySet()) { cnt = writeString(output, entry.getKey(), seen, stringCache, cnt); cnt = writeString(output, entry.getValue(), seen, stringCache, cnt); } return cnt; }
private int writeString(final DataOutput output, String string, final IdentityIntMap<Object> seen, final HashMap<String, String> stringCache, final int cnt) throws IOException { if (string == null) { output.write(ST_NULL); return cnt; } // make sure we never duplicate a string string = stringCache.computeIfAbsent(string, Function.identity()); final int idx = seen.get(string, - 1); final int distance = cnt - idx; if (idx == -1 || distance > (1 << 14) - 1) { seen.put(string, cnt); output.write(ST_NEW_STRING); output.writeUTF(string); return cnt + 1; } else { if (distance < 127) { output.writeByte(ST_BACKREF_NEAR | distance); } else { assert distance <= 0x3fff; output.writeByte(ST_BACKREF_FAR | distance >> 8); output.writeByte(distance); } return cnt; } }
public static RemoteExceptionCause readFromStream(DataInput input) throws IOException { return readObject(input, RemoteExceptionCause.class, new ArrayList<>(), false); }
/** * Put a value into the map. Any previous mapping is discarded silently. * * @param key the key * @param value the value to store */ public void put(T key, int value) { final Object[] keys = this.keys; final int mask = keys.length - 1; final int[] values = this.values; Object v; int hc = System.identityHashCode(key) & mask; for (int idx = hc;; idx = hc++ & mask) { v = keys[idx]; if (v == null) { keys[idx] = key; values[idx] = value; if (++count > resizeCount) { resize(); } return; } if (v == key) { values[idx] = value; return; } } }
public Object writeReplace(final Object original) { if (original instanceof URIAffinity) { if (peerUriAffinity != null && original.equals(peerUriAffinity) && peerNodeAffinity != null) { return peerNodeAffinity; } return Affinity.NONE; } else if (original == Affinity.LOCAL && selfNodeAffinity != null) { // Swap a local affinity with a node affinity with the name of this node return selfNodeAffinity; } else if (original instanceof AbstractEJBMetaData) { return new EJBMetaDataImpl((AbstractEJBMetaData<?, ?>) original); } else if (original instanceof RemoteExceptionCause) { // old clients will not have this class return ((RemoteExceptionCause) original).toPlainThrowable(); } return super.writeReplace(original); } }
/** * 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<Map.Entry<String, String>> iterator = fields.entrySet().iterator(); if (iterator.hasNext()) { b.append("\n\tPublic fields:"); do { final Map.Entry<String, String> 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; }
RemoteExceptionCause(final String msg, final RemoteExceptionCause cause, final String exceptionClassName, final Map<String, String> fields, boolean cloneFields) { super(msg); if (cause != null) { initCause(cause);
private void writeExceptionResponse(final int msgId, final int invId, final int exceptionKind, final Exception e) { try (final MessageOutputStream outputStream = messageTracker.openMessageUninterruptibly()) { outputStream.writeShort(invId); outputStream.writeByte(msgId); writeInt8(outputStream, exceptionKind); final RemoteExceptionCause remoteExceptionCause = RemoteExceptionCause.of(e); final ByteArrayOutputStream os = new ByteArrayOutputStream(); final DataOutputStream dos = new DataOutputStream(os); remoteExceptionCause.writeToStream(dos); dos.flush(); writePackedUnsignedInt31(outputStream, os.size()); os.writeTo(outputStream); } catch (IOException ioe) { log.outboundException(ioe); } }