Skip to content

Commit 03e752c

Browse files
author
Maciej Rosiek
committed
Refactored AdvisoryLock to more extendable form
1 parent 90600d7 commit 03e752c

File tree

7 files changed

+106
-21
lines changed

7 files changed

+106
-21
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ To use SProcWrapper, add the following lines to your pom.xml:
1717
<dependency>
1818
<groupId>de.zalando</groupId>
1919
<artifactId>zalando-sprocwrapper</artifactId>
20-
<version>1.2.4</version>
20+
<version>1.3.0</version>
2121
</dependency>
2222
```
2323

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<groupId>de.zalando</groupId>
66
<artifactId>zalando-sprocwrapper</artifactId>
7-
<version>1.2.4</version>
7+
<version>1.3.0</version>
88
<packaging>jar</packaging>
99
<name>Stored Procedure Wrapper</name>
1010
<description>Library to make PostgreSQL stored procedures available through simple Java "*SProcService" interfaces including automatic object serialization and deserialization (using typemapper and convention-over-configuration). Supports sharding, advisory locking, statement timeouts and PostgreSQL types such as enums and hstore.</description>

src/main/java/de/zalando/sprocwrapper/SProcCall.java

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,87 @@
66
import java.lang.annotation.RetentionPolicy;
77
import java.lang.annotation.Target;
88

9+
import java.util.Objects;
10+
11+
import com.google.common.base.Preconditions;
12+
913
/**
1014
* @author jmussler
1115
*/
12-
@Retention(RetentionPolicy.RUNTIME)
16+
@Retention(RetentionPolicy.SOURCE)
1317
@Target(ElementType.METHOD)
1418
@Inherited
1519
public @interface SProcCall {
1620

17-
public static enum AdvisoryLock {
18-
NO_LOCK(0L),
19-
LOCK_ONE(1L);
21+
public static class AdvisoryLock {
2022

21-
/*
22-
* Add more values to this enum if you need additional types of locks
23-
*/
23+
public static class NoLock {
24+
public static final String NAME = "NO_LOCK";
25+
public static final long SPROC_ID = 0L;
26+
public static final AdvisoryLock LOCK = new AdvisoryLock(NAME, SPROC_ID);
27+
}
2428

25-
private AdvisoryLock(final long sprocId) {
26-
this.sprocId = sprocId;
29+
public static class LockOne {
30+
public static final String NAME = "LOCK_ONE";
31+
public static final long SPROC_ID = 1L;
32+
public static final AdvisoryLock LOCK = new AdvisoryLock(NAME, SPROC_ID);
2733
}
2834

35+
private final String name;
2936
private final long sprocId;
3037

38+
public AdvisoryLock(final String name, final long sprocId) {
39+
Preconditions.checkNotNull(name, "Name parameter cannot be null.");
40+
Preconditions.checkArgument(sprocId == NoLock.SPROC_ID && Objects.equals(name, NoLock.NAME)
41+
|| sprocId != NoLock.SPROC_ID && !Objects.equals(name, NoLock.NAME),
42+
"SprocId parameter is different than %s (%s) but the name parameter was not changed: [name: %s, sprocId: %s]",
43+
NoLock.SPROC_ID, NoLock.NAME, name, sprocId);
44+
this.name = name;
45+
this.sprocId = sprocId;
46+
}
47+
48+
public String getName() {
49+
return name;
50+
}
51+
3152
public long getSprocId() {
3253
return sprocId;
3354
}
3455

56+
@Override
57+
public boolean equals(final Object o) {
58+
if (this == o) {
59+
return true;
60+
}
61+
62+
if (o == null || getClass() != o.getClass()) {
63+
return false;
64+
}
65+
66+
final AdvisoryLock that = (AdvisoryLock) o;
67+
68+
if (sprocId != that.sprocId) {
69+
return false;
70+
}
71+
72+
if (!name.equals(that.name)) {
73+
return false;
74+
}
75+
76+
return true;
77+
}
78+
79+
@Override
80+
public int hashCode() {
81+
int result = name.hashCode();
82+
result = 31 * result + (int) (sprocId ^ (sprocId >>> 32));
83+
return result;
84+
}
85+
86+
@Override
87+
public String toString() {
88+
return "AdvisoryLock{" + "name='" + name + '\'' + ", sprocId=" + sprocId + '}';
89+
}
3590
}
3691

3792
public static enum Validate {
@@ -94,7 +149,10 @@ public static enum WriteTransaction {
94149

95150
long timeoutInMilliSeconds() default 0;
96151

97-
AdvisoryLock adivsoryLockType() default AdvisoryLock.NO_LOCK;
152+
long adivsoryLockSprocId() default AdvisoryLock.NoLock.SPROC_ID;
153+
154+
String adivsoryLockName() default AdvisoryLock.NoLock.NAME;
98155

99156
Validate validate() default Validate.AS_DEFINED_IN_SERVICE;
157+
100158
}

src/main/java/de/zalando/sprocwrapper/proxy/SProcProxyBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,9 @@ public static <T> T build(final DataSourceProvider d, final Class<T> c) {
136136

137137
storedProcedure = new StoredProcedure(name, method.getGenericReturnType(), sprocStrategy,
138138
scA.runOnAllShards(), scA.searchShards(), scA.parallel(), resultMapper,
139-
scA.timeoutInMilliSeconds(), scA.adivsoryLockType(), useValidation, scA.readOnly(),
140-
writeTransaction);
139+
scA.timeoutInMilliSeconds(),
140+
new SProcCall.AdvisoryLock(scA.adivsoryLockName(), scA.adivsoryLockSprocId()), useValidation,
141+
scA.readOnly(), writeTransaction);
141142
if (!"".equals(scA.sql())) {
142143
storedProcedure.setQuery(scA.sql());
143144
}

src/main/java/de/zalando/sprocwrapper/proxy/StoredProcedure.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public StoredProcedure(final String name, final java.lang.reflect.Type genericTy
152152
}
153153
}
154154

155-
if (this.timeout > 0 || this.adivsoryLock != AdvisoryLock.NO_LOCK) {
155+
if (this.timeout > 0 || (this.adivsoryLock != null && !(this.adivsoryLock.equals(AdvisoryLock.NoLock.LOCK)))) {
156156

157157
// Wrapper provides locking and changing of session settings functionality
158158
this.executor = new ExecutorWrapper(executor, this.timeout, this.adivsoryLock);

src/main/java/de/zalando/sprocwrapper/proxy/executors/ExecutorWrapper.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ private void resetTimeout(final Connection conn) throws SQLException {
6060
}
6161

6262
private boolean lockAdvisoryLock(final Connection conn) throws SQLException {
63-
if (lock == AdvisoryLock.NO_LOCK) {
63+
if (lock == null || lock.equals(AdvisoryLock.NoLock.LOCK)) {
6464
return true;
6565
}
6666

6767
final Statement st = conn.createStatement();
68-
final ResultSet rs = st.executeQuery("SELECT pg_advisory_lock(" + lock.getSprocId() + ") AS \"" + lock.name()
69-
+ "\";");
68+
final ResultSet rs = st.executeQuery("SELECT pg_advisory_lock(" + lock.getSprocId() + ") AS \"" + lock
69+
.getName() + "\";");
7070

7171
boolean b = false;
7272
if (rs.next()) {
@@ -79,7 +79,7 @@ private boolean lockAdvisoryLock(final Connection conn) throws SQLException {
7979
}
8080

8181
private boolean unlockAdvisoryLock(final Connection conn) throws SQLException {
82-
if (lock == AdvisoryLock.NO_LOCK) {
82+
if (lock == null || lock.equals(AdvisoryLock.NoLock.LOCK)) {
8383
return true;
8484
}
8585

@@ -108,7 +108,7 @@ public Object executeSProc(final DataSource ds, final String sql, final Object[]
108108
setTimeout(sameConnDs.getConnection());
109109

110110
if (!lockAdvisoryLock(sameConnDs.getConnection())) {
111-
throw new RuntimeException("Could not acquire AdvisoryLock " + lock.name());
111+
throw new RuntimeException("Could not acquire AdvisoryLock " + lock.getName());
112112
}
113113

114114
return executor.executeSProc(sameConnDs, sql, args, types, invocationContext, returnType);
@@ -130,7 +130,7 @@ public Object executeSProc(final DataSource ds, final String sql, final Object[]
130130
}
131131

132132
// unlock in all cases, locks not owned by this session cannot be unlocked
133-
if (lock != AdvisoryLock.NO_LOCK) {
133+
if (lock != null && !lock.equals(AdvisoryLock.NoLock.LOCK)) {
134134
try {
135135
unlockAdvisoryLock(sameConnDs.getConnection());
136136
} catch (final SQLException ex) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package de.zalando.sprocwrapper;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
6+
public class AdvisoryLockTest {
7+
8+
@Test(expected = IllegalArgumentException.class)
9+
public void shouldNotCreateAdvisoryLockWithWrongName() {
10+
new SProcCall.AdvisoryLock(SProcCall.AdvisoryLock.NoLock.NAME, SProcCall.AdvisoryLock.NoLock.SPROC_ID + 1);
11+
}
12+
13+
@Test
14+
public void shouldCreateAdvisoryLockWithCorrectName() {
15+
new SProcCall.AdvisoryLock("TEST_LOCK", 100L);
16+
}
17+
18+
@Test
19+
public void shouldCompareLocksCorrectly() {
20+
Assert.assertEquals(SProcCall.AdvisoryLock.NoLock.LOCK,
21+
new SProcCall.AdvisoryLock(SProcCall.AdvisoryLock.NoLock.NAME, SProcCall.AdvisoryLock.NoLock.SPROC_ID));
22+
Assert.assertNotEquals(SProcCall.AdvisoryLock.LockOne.LOCK,
23+
new SProcCall.AdvisoryLock(SProcCall.AdvisoryLock.NoLock.NAME, SProcCall.AdvisoryLock.NoLock.SPROC_ID));
24+
}
25+
26+
}

0 commit comments

Comments
 (0)