1515import java .sql .SQLFeatureNotSupportedException ;
1616import java .util .Properties ;
1717import java .util .UUID ;
18+ import java .util .concurrent .Executor ;
19+ import java .util .function .Consumer ;
1820import java .util .logging .Logger ;
1921
2022public final class XerialConformanceDriver implements Driver {
@@ -43,7 +45,7 @@ public Connection connect(String url, Properties info) throws SQLException {
4345 try {
4446 connection = delegate .connect (target .url (), info );
4547 } catch (SQLException e ) {
46- XerialTestServer . releaseNamespace (target .namespace ());
48+ releaseAfterConnectFailure (target .namespace (), e );
4749 throw e ;
4850 }
4951 if (connection == null ) {
@@ -57,7 +59,11 @@ public Connection connect(String url, Properties info) throws SQLException {
5759 new Class <?>[] {Connection .class },
5860 new NamespaceClosingHandler (connection , target .namespace ()));
5961 } catch (RuntimeException e ) {
60- XerialTestServer .releaseNamespace (target .namespace ());
62+ try {
63+ XerialTestServer .releaseNamespace (target .namespace ());
64+ } catch (RuntimeException cleanup ) {
65+ e .addSuppressed (cleanup );
66+ }
6167 throw e ;
6268 }
6369 }
@@ -95,6 +101,14 @@ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
95101 return delegate .getParentLogger ();
96102 }
97103
104+ private static void releaseAfterConnectFailure (String namespace , SQLException failure ) {
105+ try {
106+ XerialTestServer .releaseNamespace (namespace );
107+ } catch (RuntimeException cleanup ) {
108+ failure .addSuppressed (cleanup );
109+ }
110+ }
111+
98112 private static Target rewrite (String url ) {
99113 String target = url .substring (PREFIX .length ());
100114 String namespace ;
@@ -112,15 +126,22 @@ private static Target rewrite(String url) {
112126
113127 private record Target (String url , String namespace ) {}
114128
115- private static final class NamespaceClosingHandler implements InvocationHandler {
129+ static final class NamespaceClosingHandler implements InvocationHandler {
116130
117131 private final Connection connection ;
118132 private final String namespace ;
133+ private final Consumer <String > release ;
119134 private boolean closed ;
120135
121- private NamespaceClosingHandler (Connection connection , String namespace ) {
136+ NamespaceClosingHandler (Connection connection , String namespace ) {
137+ this (connection , namespace , XerialTestServer ::releaseNamespace );
138+ }
139+
140+ NamespaceClosingHandler (
141+ Connection connection , String namespace , Consumer <String > release ) {
122142 this .connection = connection ;
123143 this .namespace = namespace ;
144+ this .release = release ;
124145 }
125146
126147 @ Override
@@ -129,6 +150,16 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
129150 close ();
130151 return null ;
131152 }
153+ if ("abort" .equals (method .getName ()) && method .getParameterCount () == 1 ) {
154+ abort ((Executor ) args [0 ]);
155+ return null ;
156+ }
157+ if ("unwrap" .equals (method .getName ()) && method .getParameterCount () == 1 ) {
158+ Class <?> iface = (Class <?>) args [0 ];
159+ if (iface != null && iface .isInstance (proxy )) {
160+ return proxy ;
161+ }
162+ }
132163 try {
133164 return method .invoke (connection , args );
134165 } catch (InvocationTargetException e ) {
@@ -143,8 +174,42 @@ private synchronized void close() throws SQLException {
143174 closed = true ;
144175 try {
145176 connection .close ();
146- } finally {
147- XerialTestServer .releaseNamespace (namespace );
177+ } catch (SQLException e ) {
178+ releaseWithSuppressed (e );
179+ throw e ;
180+ } catch (RuntimeException e ) {
181+ releaseWithSuppressed (e );
182+ throw e ;
183+ }
184+ releaseNamespace ();
185+ }
186+
187+ private synchronized void abort (Executor executor ) throws SQLException {
188+ if (closed ) {
189+ return ;
190+ }
191+ closed = true ;
192+ try {
193+ connection .abort (executor );
194+ } catch (SQLException e ) {
195+ releaseWithSuppressed (e );
196+ throw e ;
197+ } catch (RuntimeException e ) {
198+ releaseWithSuppressed (e );
199+ throw e ;
200+ }
201+ releaseNamespace ();
202+ }
203+
204+ private void releaseNamespace () {
205+ release .accept (namespace );
206+ }
207+
208+ private void releaseWithSuppressed (Throwable failure ) {
209+ try {
210+ releaseNamespace ();
211+ } catch (RuntimeException cleanup ) {
212+ failure .addSuppressed (cleanup );
148213 }
149214 }
150215 }
0 commit comments