/src/frontend/org/voltdb/exceptions/SerializableException.java

https://github.com/VoltDB/voltdb · Java · 283 lines · 184 code · 26 blank · 73 comment · 8 complexity · 908653f73a0a09cf8fde7650a2ce0f03 MD5 · raw file

  1. /* This file is part of VoltDB.
  2. * Copyright (C) 2008-2022 Volt Active Data Inc.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License as
  6. * published by the Free Software Foundation, either version 3 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Affero General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Affero General Public License
  15. * along with VoltDB. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. package org.voltdb.exceptions;
  18. import java.io.PrintStream;
  19. import java.io.PrintWriter;
  20. import java.io.StringWriter;
  21. import java.io.UnsupportedEncodingException;
  22. import java.nio.ByteBuffer;
  23. import org.json_voltpatches.JSONString;
  24. import org.json_voltpatches.JSONStringer;
  25. import org.voltdb.ClientResponseImpl;
  26. import org.voltdb.VoltProcedure;
  27. import org.voltdb.client.ClientResponse;
  28. /**
  29. * Base class for runtime exceptions that can be serialized to ByteBuffers without involving Java's
  30. * serialization mechanism
  31. *
  32. */
  33. public class SerializableException extends VoltProcedure.VoltAbortException implements JSONString {
  34. /**
  35. *
  36. */
  37. private static final long serialVersionUID = 1L;
  38. /**
  39. * Storage for the detailed message describing the error that generated this exception
  40. */
  41. private final String m_message;
  42. /**
  43. * Enum correlating the integer ordinals that are serialized as the type of an exception
  44. * with the class that deserializes that type.
  45. *
  46. */
  47. protected enum SerializableExceptions {
  48. None() {
  49. @Override
  50. protected SerializableException deserializeException(ByteBuffer b) {
  51. return null;
  52. }
  53. },
  54. EEException() {
  55. @Override
  56. protected SerializableException deserializeException(ByteBuffer b) {
  57. return new EEException(b);
  58. }
  59. },
  60. SQLException() {
  61. @Override
  62. protected SerializableException deserializeException(ByteBuffer b) {
  63. return new SQLException(b);
  64. }
  65. },
  66. ConstraintFailureException() {
  67. @Override
  68. protected SerializableException deserializeException(ByteBuffer b) {
  69. return new ConstraintFailureException(b);
  70. }
  71. },
  72. InterruptException() {
  73. @Override
  74. protected SerializableException deserializeException(ByteBuffer b) {
  75. return new InterruptException(b);
  76. }
  77. },
  78. TransactionRestartException() {
  79. @Override
  80. protected SerializableException deserializeException(ByteBuffer b) {
  81. return new TransactionRestartException(b);
  82. }
  83. },
  84. TransactionTerminationException() {
  85. @Override
  86. protected SerializableException deserializeException(ByteBuffer b) {
  87. return new TransactionTerminationException(b);
  88. }
  89. },
  90. SpecifiedException() {
  91. @Override
  92. protected SerializableException deserializeException(ByteBuffer b) {
  93. return new SpecifiedException(b);
  94. }
  95. },
  96. GenericSerializableException() {
  97. @Override
  98. protected SerializableException deserializeException(ByteBuffer b) {
  99. return new SerializableException(b);
  100. }
  101. },
  102. MispartitionedException() {
  103. @Override
  104. protected SerializableException deserializeException(ByteBuffer b) {
  105. return new MispartitionedException(b);
  106. }
  107. },
  108. ReplicatedTableException() {
  109. @Override
  110. protected SerializableException deserializeException(ByteBuffer b) {
  111. return new ReplicatedTableException(b);
  112. }
  113. },
  114. DrTableNotFoundException() {
  115. @Override
  116. protected SerializableException deserializeException(ByteBuffer b) {
  117. return new DRTableNotFoundException(b);
  118. }
  119. },
  120. InvalidMessage() {
  121. @Override
  122. protected SerializableException deserializeException(ByteBuffer b) {
  123. return new InvalidMessageException(b);
  124. }
  125. };
  126. abstract protected SerializableException deserializeException(ByteBuffer b);
  127. }
  128. public SerializableException() {
  129. m_message = null;
  130. }
  131. public SerializableException(String message) {
  132. m_message = message;
  133. }
  134. public SerializableException(Throwable t) {
  135. final StringWriter sw = new StringWriter();
  136. final PrintWriter pw = new PrintWriter(sw);
  137. t.printStackTrace(pw);
  138. pw.flush();
  139. m_message = sw.toString();
  140. }
  141. public SerializableException(ByteBuffer b) {
  142. final int messageLength = b.getInt();
  143. final byte messageBytes[] = new byte[messageLength];
  144. b.get(messageBytes);
  145. try {
  146. m_message = new String(messageBytes, "UTF-8");
  147. } catch (UnsupportedEncodingException e) {
  148. throw new RuntimeException(e);
  149. }
  150. }
  151. /**
  152. * Get the detailed message describing the error that generated this exception
  153. */
  154. @Override
  155. public String getMessage() { return m_message; }
  156. /**
  157. * Override this method if the ClientResponse sent back must contain
  158. * result rows with additional information.
  159. *
  160. * @param cr
  161. */
  162. public void setClientResponseResults(ClientResponseImpl cr) {
  163. // Does nothing by default
  164. }
  165. /**
  166. * Number of bytes necessary to store the serialized representation of this exception
  167. * @return Number of bytes
  168. */
  169. public int getSerializedSize() {
  170. // sizes: as near as I can tell,
  171. // 5 is sizeof(int) for buffer length and sizeof(byte) for exception type
  172. // 4 is sizeof(int) for message string length
  173. if (m_message == null) {
  174. return 5 + 4 + p_getSerializedSize();
  175. }
  176. return 5 + 4 + m_message.getBytes().length + p_getSerializedSize();//one byte ordinal and 4 byte length
  177. }
  178. /**
  179. * Method for subclasses to implement that returns the number of bytes necessary to store
  180. * subclass data
  181. * @return Number of bytes necessary to store subclass data
  182. */
  183. protected int p_getSerializedSize() {
  184. return 0;
  185. }
  186. /**
  187. * Serialize this exception to the supplied byte buffer
  188. * @param b ByteBuffer to serialize this exception to
  189. */
  190. public void serializeToBuffer(ByteBuffer b) {
  191. assert(getSerializedSize() <= b.remaining());
  192. b.putInt(getSerializedSize() - 4);
  193. b.put((byte)getExceptionType().ordinal());
  194. if (m_message != null) {
  195. final byte messageBytes[] = m_message.getBytes();
  196. b.putInt(messageBytes.length);
  197. b.put(messageBytes);
  198. } else {
  199. b.putInt(0);
  200. }
  201. p_serializeToBuffer(b);
  202. }
  203. /**
  204. * Method for subclasses to implement that serializes the subclass's contents to
  205. * the ByteBuffer
  206. * @param b ByteBuffer to serialize the subclass contents to
  207. */
  208. protected void p_serializeToBuffer(ByteBuffer b) {}
  209. /**
  210. * Method for subclasses to specify what constant from the SerializableExceptions enum
  211. * is defined for this type of exception
  212. * @return Type of exception
  213. */
  214. protected SerializableExceptions getExceptionType() {
  215. return SerializableExceptions.GenericSerializableException;
  216. }
  217. /**
  218. * Deserialize an exception (if any) from the ByteBuffer
  219. * @param b ByteBuffer containing the exception to be deserialized
  220. * @return A deserialized exception if one was serialized or null
  221. */
  222. public static SerializableException deserializeFromBuffer(ByteBuffer b) {
  223. final int length = b.getInt();
  224. if (length == 0) {
  225. return null;
  226. }
  227. final int ordinal = b.get();
  228. assert (ordinal != SerializableExceptions.None.ordinal());
  229. return SerializableExceptions.values()[ordinal].deserializeException(b);
  230. }
  231. @Override
  232. public byte getClientResponseStatus() {
  233. return ClientResponse.UNEXPECTED_FAILURE;
  234. }
  235. @Override
  236. public void printStackTrace(PrintStream s) {
  237. s.print(getMessage());
  238. }
  239. @Override
  240. public void printStackTrace(PrintWriter p) {
  241. p.print(getMessage());
  242. }
  243. @Override
  244. public String toJSONString() {
  245. try {
  246. JSONStringer js = new JSONStringer();
  247. js.object();
  248. js.keySymbolValuePair("type", getExceptionType().ordinal());
  249. js.keySymbolValuePair("message", m_message);
  250. js.endObject();
  251. return js.toString();
  252. }
  253. catch (Exception e) {
  254. return "{ error: \"Unable to serialize exception.\" }";
  255. }
  256. }
  257. }