Skip to content

Commit 686aa1e

Browse files
GH-37 Make StoredProcedure immutable
1 parent db73d59 commit 686aa1e

File tree

3 files changed

+95
-76
lines changed

3 files changed

+95
-76
lines changed

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,10 @@ public Map<Method, StoredProcedure> handle(Class c, SProcServiceAnnotationHandle
122122

123123
RowMapper<?> resultMapper = this.getRowMapper(scA);
124124

125-
boolean useValidation = this.isValidationActive(scA, handlerResult);
126-
final StoredProcedure storedProcedure = this.getStoredProcedure(scA, handlerResult, method, name, sprocStrategy, resultMapper, useValidation);
125+
final boolean useValidation = this.isValidationActive(scA, handlerResult);
126+
127+
final List<ShardKeyParameter> shardKeyParameters = new ArrayList<>();
128+
final List<StoredProcedureParameter> params = new ArrayList<>();
127129

128130
int pos = 0;
129131
for (final Annotation[] as : method.getParameterAnnotations()) {
@@ -140,7 +142,7 @@ public Map<Method, StoredProcedure> handle(Class c, SProcServiceAnnotationHandle
140142
}
141143

142144
if (a instanceof ShardKey) {
143-
storedProcedure.addShardKeyParameter(pos, clazz);
145+
shardKeyParameters.add(new ShardKeyParameter(pos, clazz));
144146
}
145147

146148
if (a instanceof SProcParam) {
@@ -149,7 +151,7 @@ public Map<Method, StoredProcedure> handle(Class c, SProcServiceAnnotationHandle
149151
final String dbTypeName = sParam.type();
150152

151153
try {
152-
storedProcedure.addParam(StoredProcedureParameter.createParameter(clazz, genericType,
154+
params.add(StoredProcedureParameter.createParameter(clazz, genericType,
153155
method, dbTypeName, sParam.sqlType(), pos, sParam.sensitive()));
154156
} catch (final InstantiationException | IllegalAccessException e) {
155157
LOG.error("Could not instantiate StoredProcedureParameter. ABORTING.", e);
@@ -160,22 +162,27 @@ public Map<Method, StoredProcedure> handle(Class c, SProcServiceAnnotationHandle
160162

161163
pos++;
162164
}
165+
final StoredProcedure storedProcedure = createStoredProcedure(scA, handlerResult, method, name, params, sprocStrategy, shardKeyParameters, resultMapper, useValidation);
166+
163167
result.put(method, storedProcedure);
164168
}
165169
return result;
166170
}
167171

168-
private StoredProcedure getStoredProcedure(SProcCall scA, SProcServiceAnnotationHandler.HandlerResult handlerResult, Method method, String name, VirtualShardKeyStrategy sprocStrategy, RowMapper<?> resultMapper, boolean useValidation) {
172+
private StoredProcedure createStoredProcedure(SProcCall scA, SProcServiceAnnotationHandler.HandlerResult handlerResult,
173+
Method method, String name, List<StoredProcedureParameter> params,
174+
VirtualShardKeyStrategy sprocStrategy, List<ShardKeyParameter> shardKeyParameters,
175+
RowMapper<?> resultMapper, boolean useValidation) {
169176
try {
170177
SProcService.WriteTransaction writeTransaction = mapSprocWriteTransactionToServiceWriteTransaction(scA.shardedWriteTransaction(), handlerResult);
171178

172-
StoredProcedure storedProcedure = new StoredProcedure(name, method.getGenericReturnType(), sprocStrategy,
179+
String query = !"".equals(scA.sql()) ? scA.sql() : null;
180+
181+
StoredProcedure storedProcedure = new StoredProcedure(name, query, params, method.getGenericReturnType(), sprocStrategy, shardKeyParameters,
173182
scA.runOnAllShards(), scA.searchShards(), scA.parallel(), resultMapper,
174183
scA.timeoutInMilliSeconds(), new SProcCall.AdvisoryLock(scA.adivsoryLockName(),scA.adivsoryLockId()), useValidation, scA.readOnly(),
175184
writeTransaction);
176-
if (!"".equals(scA.sql())) {
177-
storedProcedure.setQuery(scA.sql());
178-
}
185+
179186
return storedProcedure;
180187
} catch (final InstantiationException | IllegalAccessException e) {
181188
LOG.error("Could not instantiate StoredProcedure. ABORTING.", e);
Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
package de.zalando.sprocwrapper.proxy;
22

33
/**
4-
* @author jmussler
4+
* @author jmussler
55
*/
6-
public class ShardKeyParameter {
7-
public int javaPos;
6+
class ShardKeyParameter {
87

9-
public ShardKeyParameter(final int j) {
10-
javaPos = j;
8+
private final int pos;
9+
private final Class<?> type;
10+
11+
public ShardKeyParameter(final int pos, final Class<?> type) {
12+
this.pos = pos;
13+
this.type = type;
14+
}
15+
16+
public int getPos() {
17+
return pos;
18+
}
19+
20+
public Class<?> getType() {
21+
return type;
1122
}
1223
}

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

Lines changed: 63 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -55,35 +55,36 @@
5555
/**
5656
* @author jmussler
5757
*/
58+
@Immutable
5859
class StoredProcedure {
5960

6061
private static final int TRUNCATE_DEBUG_PARAMS_MAX_LENGTH = 1024;
6162
private static final String TRUNCATE_DEBUG_PARAMS_ELLIPSIS = " ...";
6263

6364
private static final Logger LOG = LoggerFactory.getLogger(StoredProcedure.class);
6465

65-
private final List<StoredProcedureParameter> params = new ArrayList<StoredProcedureParameter>();
66-
6766
private final String name;
68-
private String query = null;
69-
private Class<?> returnType = null;
67+
private final List<StoredProcedureParameter> params;
68+
private final int[] types;
69+
70+
private final String sqlParameterList;
71+
private final String query;
72+
73+
private final Class<?> returnType;
7074

7175
// whether the result type is a collection (List)
72-
private boolean collectionResult = false;
76+
private final boolean collectionResult;
7377
private final boolean runOnAllShards;
7478
private final boolean searchShards;
75-
private boolean autoPartition;
79+
private final boolean autoPartition;
7680
private final boolean parallel;
7781
private final boolean readOnly;
7882
private final WriteTransaction writeTransaction;
7983

80-
private Executor executor = null;
84+
private final Executor executor;
8185

82-
private VirtualShardKeyStrategy shardStrategy;
83-
private List<ShardKeyParameter> shardKeyParameters = null;
84-
private final RowMapper<?> resultMapper;
85-
86-
private int[] types = null;
86+
private final VirtualShardKeyStrategy shardStrategy;
87+
private final List<ShardKeyParameter> shardKeyParameters;
8788

8889
private static final Executor MULTI_ROW_SIMPLE_TYPE_EXECUTOR = new MultiRowSimpleTypeExecutor();
8990
private static final Executor MULTI_ROW_TYPE_MAPPER_EXECUTOR = new MultiRowTypeMapperExecutor();
@@ -93,26 +94,34 @@ class StoredProcedure {
9394
private final long timeout;
9495
private final AdvisoryLock adivsoryLock;
9596

96-
public StoredProcedure(final String name, final java.lang.reflect.Type genericType,
97-
final VirtualShardKeyStrategy sStrategy, final boolean runOnAllShards, final boolean searchShards,
97+
public StoredProcedure(final String name, final String query, final List<StoredProcedureParameter> params, final java.lang.reflect.Type genericType,
98+
final VirtualShardKeyStrategy sStrategy, final List<ShardKeyParameter> shardKeyParameters, final boolean runOnAllShards, final boolean searchShards,
9899
final boolean parallel, final RowMapper<?> resultMapper, final long timeout,
99100
final AdvisoryLock advisoryLock, final boolean useValidation, final boolean readOnly,
100101
final WriteTransaction writeTransaction) throws InstantiationException, IllegalAccessException {
101102
this.name = name;
103+
this.params = new ArrayList<>(params);
104+
this.types = createTypes(params);
105+
106+
this.sqlParameterList = createSqlParameterList(params);
107+
this.query = (query != null ? query : defaultQuery(name, sqlParameterList));
108+
102109
this.runOnAllShards = runOnAllShards;
103110
this.searchShards = searchShards;
104111
this.parallel = parallel;
105112
this.readOnly = readOnly;
106-
this.resultMapper = resultMapper;
107113
this.writeTransaction = writeTransaction;
108114

109115
this.adivsoryLock = advisoryLock;
110116
this.timeout = timeout;
111117

112-
shardStrategy = sStrategy;
118+
this.shardStrategy = sStrategy;
119+
this.shardKeyParameters = new ArrayList<>(shardKeyParameters);
113120

114-
ValueTransformer<?, ?> valueTransformerForClass = null;
121+
this.autoPartition = isAutoPartition(shardKeyParameters);
115122

123+
ValueTransformer<?, ?> valueTransformerForClass = null;
124+
Executor exec;
116125
if (genericType instanceof ParameterizedType) {
117126
final ParameterizedType pType = (ParameterizedType) genericType;
118127

@@ -125,70 +134,53 @@ public StoredProcedure(final String name, final java.lang.reflect.Type genericTy
125134

126135
if (valueTransformerForClass != null
127136
|| SingleRowSimpleTypeExecutor.SIMPLE_TYPES.containsKey(returnType)) {
128-
executor = MULTI_ROW_SIMPLE_TYPE_EXECUTOR;
137+
exec = MULTI_ROW_SIMPLE_TYPE_EXECUTOR;
129138
} else {
130-
executor = MULTI_ROW_TYPE_MAPPER_EXECUTOR;
139+
exec = MULTI_ROW_TYPE_MAPPER_EXECUTOR;
131140
}
132141

133142
collectionResult = true;
134143
} else {
135-
executor = SINGLE_ROW_TYPE_MAPPER_EXECUTOR;
144+
collectionResult = false;
145+
exec = SINGLE_ROW_TYPE_MAPPER_EXECUTOR;
136146
returnType = (Class<?>) pType.getRawType();
137147
}
138148

139149
} else {
150+
collectionResult = false;
140151
returnType = (Class<?>) genericType;
141152

142153
// check if we have a value transformer (and initialize the registry):
143154
valueTransformerForClass = GlobalValueTransformerLoader.getValueTransformerForClass(returnType);
144155

145156
if (valueTransformerForClass != null || SingleRowSimpleTypeExecutor.SIMPLE_TYPES.containsKey(returnType)) {
146-
executor = SINGLE_ROW_SIMPLE_TYPE_EXECUTOR;
157+
exec = SINGLE_ROW_SIMPLE_TYPE_EXECUTOR;
147158
} else {
148159
if (resultMapper != null) {
149-
executor = new SingleRowCustomMapperExecutor(resultMapper);
160+
exec = new SingleRowCustomMapperExecutor(resultMapper);
150161
} else {
151-
executor = SINGLE_ROW_TYPE_MAPPER_EXECUTOR;
162+
exec = SINGLE_ROW_TYPE_MAPPER_EXECUTOR;
152163
}
153164
}
154165
}
155166

156167
if (this.timeout > 0 || (this.adivsoryLock != null && !(this.adivsoryLock.equals(AdvisoryLock.NoLock.LOCK)))) {
157168

158169
// Wrapper provides locking and changing of session settings functionality
159-
this.executor = new ExecutorWrapper(executor, this.timeout, this.adivsoryLock);
170+
exec = new ExecutorWrapper(exec, this.timeout, this.adivsoryLock);
160171
}
161172

162173
if (useValidation) {
163-
this.executor = new ValidationExecutorWrapper(this.executor);
174+
exec = new ValidationExecutorWrapper(exec);
164175
}
165176

166177
if (valueTransformerForClass != null) {
167178

168179
// we need to transform the return value by the global value transformer.
169180
// add the transformation to the as a transformerExecutor
170-
this.executor = new GlobalTransformerExecutorWrapper(this.executor);
181+
exec = new GlobalTransformerExecutorWrapper(exec);
171182
}
172-
}
173-
174-
public void addParam(final StoredProcedureParameter p) {
175-
params.add(p);
176-
}
177-
178-
public void setVirtualShardKeyStrategy(final VirtualShardKeyStrategy s) {
179-
shardStrategy = s;
180-
}
181-
182-
public void addShardKeyParameter(final int jp, final Class<?> clazz) {
183-
if (shardKeyParameters == null) {
184-
shardKeyParameters = new ArrayList<ShardKeyParameter>(1);
185-
}
186-
187-
if (List.class.isAssignableFrom(clazz)) {
188-
autoPartition = true;
189-
}
190-
191-
shardKeyParameters.add(new ShardKeyParameter(jp));
183+
this.executor = exec;
192184
}
193185

194186
public String getName() {
@@ -217,15 +209,15 @@ public Object[] getParams(final Object[] origParams, final Connection connection
217209
}
218210

219211
public int[] getTypes() {
220-
if (types == null) {
221-
types = new int[params.size()];
212+
return types;
213+
}
222214

223-
int i = 0;
224-
for (final StoredProcedureParameter p : params) {
225-
types[i++] = p.getType();
226-
}
215+
private static int[] createTypes(final List<StoredProcedureParameter> params) {
216+
int[] types = new int[params.size()];
217+
int i = 0;
218+
for (final StoredProcedureParameter p : params) {
219+
types[i++] = p.getType();
227220
}
228-
229221
return types;
230222
}
231223

@@ -238,7 +230,7 @@ public int getShardId(final Object[] objs) {
238230
int i = 0;
239231
Object obj;
240232
for (final ShardKeyParameter p : shardKeyParameters) {
241-
obj = objs[p.javaPos];
233+
obj = objs[p.getPos()];
242234
if (obj instanceof ShardedObject) {
243235
obj = ((ShardedObject) obj).getShardKey();
244236
}
@@ -251,6 +243,10 @@ public int getShardId(final Object[] objs) {
251243
}
252244

253245
public String getSqlParameterList() {
246+
return sqlParameterList;
247+
}
248+
249+
private static String createSqlParameterList(final List<StoredProcedureParameter> params) {
254250
String s = "";
255251
boolean first = true;
256252
for (int i = 1; i <= params.size(); ++i) {
@@ -266,18 +262,14 @@ public String getSqlParameterList() {
266262
return s;
267263
}
268264

269-
public void setQuery(final String sql) {
270-
query = sql;
271-
}
272-
273265
public String getQuery() {
274-
if (query == null) {
275-
query = "SELECT * FROM " + name + " ( " + getSqlParameterList() + " )";
276-
}
277-
278266
return query;
279267
}
280268

269+
private static String defaultQuery(final String name, final String sqlParameterList) {
270+
return "SELECT * FROM " + name + " ( " + sqlParameterList + " )";
271+
}
272+
281273
/**
282274
* build execution string like create_or_update_multiple_objects({"(a,b)","(c,d)" }).
283275
*
@@ -384,6 +376,15 @@ private Map<Integer, Object[]> partitionArguments(final DataSourceProvider dataS
384376
return argumentsByShardId;
385377
}
386378

379+
private boolean isAutoPartition(final List<ShardKeyParameter> shardKeyParameters) {
380+
for (ShardKeyParameter p : shardKeyParameters) {
381+
if (List.class.isAssignableFrom(p.getType())) {
382+
return true;
383+
}
384+
}
385+
return false;
386+
}
387+
387388
@Immutable
388389
private static final class Call implements Callable<Object> {
389390

0 commit comments

Comments
 (0)