package de.zalando.sprocwrapper;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Objects;
import com.google.common.base.Preconditions;
/**
* @author jmussler
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface SProcCall {
public static class AdvisoryLock {
public static class NoLock {
public static final String NAME = "NO_LOCK";
public static final long LOCK_ID = 0L;
public static final AdvisoryLock LOCK = new AdvisoryLock(NAME, LOCK_ID);
}
public static class LockOne {
public static final String NAME = "LOCK_ONE";
public static final long LOCK_ID = 1L;
public static final AdvisoryLock LOCK = new AdvisoryLock(NAME, LOCK_ID);
}
private final String name;
private final long lockId;
public AdvisoryLock(final String name, final long lockId) {
Preconditions.checkNotNull(name, "Name parameter cannot be null.");
Preconditions.checkArgument(lockId == NoLock.LOCK_ID && Objects.equals(name, NoLock.NAME)
|| lockId != NoLock.LOCK_ID && !Objects.equals(name, NoLock.NAME),
"LockId parameter is different than %s (%s) but the name parameter was not changed: [name: %s, lockId: %s]",
NoLock.LOCK_ID, NoLock.NAME, name, lockId);
this.name = name;
this.lockId = lockId;
}
public String getName() {
return name;
}
public long getLockId() {
return lockId;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final AdvisoryLock that = (AdvisoryLock) o;
if (lockId != that.lockId) {
return false;
}
if (!name.equals(that.name)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + (int) (lockId ^ (lockId >>> 32));
return result;
}
@Override
public String toString() {
return "AdvisoryLock{" + "name='" + name + '\'' + ", lockId=" + lockId + '}';
}
}
public static enum Validate {
AS_DEFINED_IN_SERVICE,
YES,
NO
}
public static enum WriteTransaction {
USE_FROM_SERVICE,
NONE,
ONE_PHASE,
TWO_PHASE
}
String name() default "";
String sql() default "";
Class<?> shardStrategy() default Void.class;
/**
* whether the stored procedure should be called on all shards --- results are concatenated together.
*
* @return
*/
boolean runOnAllShards() default false;
/**
* whether the stored procedure should be called on all shards --- return the first result found.
*
* @return
*/
boolean searchShards() default false;
/**
* run sproc on multiple shards in parallel?
*
* @return
*/
boolean parallel() default false;
/**
* flag this stored procedure call as read only: read only sprocs may run in cases were writing calls would not be
* allowed (maintenance, migration, ..)
*
* @return
*/
boolean readOnly() default true;
/**
* Defines how sharded writes will be handled. If set to {@link WriteTransaction#NONE}, no transaction context will
* be created. If set to {@link WriteTransaction#ONE_PHASE}, all errors during the sproc call will be rolled back.
* If set to {@link WriteTransaction#TWO_PHASE}, all errors during sproc call and "prepare transaction" are rolled
* back. In the last case, the Postgres instance must be configured to manage 2-phase-commits (XA).
*/
WriteTransaction shardedWriteTransaction() default WriteTransaction.USE_FROM_SERVICE;
Class<?> resultMapper() default Void.class;
long timeoutInMilliSeconds() default 0;
long adivsoryLockId() default AdvisoryLock.NoLock.LOCK_ID;
String adivsoryLockName() default AdvisoryLock.NoLock.NAME;
Validate validate() default Validate.AS_DEFINED_IN_SERVICE;
}