Skip to content
This repository has been archived by the owner on Apr 5, 2022. It is now read-only.

some refactorings and prevent possible nullpointer exception #6

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<spring-javaformat-maven-plugin.version>0.0.9</spring-javaformat-maven-plugin.version>
</properties>

<build>
Expand All @@ -89,6 +90,11 @@
<failOnNoGitDirectory>false</failOnNoGitDirectory>
</configuration>
</plugin>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
<version>${spring-javaformat-maven-plugin.version}</version>
</plugin>
</plugins>
</build>

Expand Down
31 changes: 19 additions & 12 deletions src/main/java/locksdemo/JdbcLockService.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@

/**
* @author Dave Syer
*
*/
public class JdbcLockService implements LockService {

Expand All @@ -42,10 +41,15 @@ public class JdbcLockService implements LockService {
private long expiry = 30000; // 30 seconds

private RowMapper<Lock> rowMapper = new LockRowMapper();

private String findAllQuery = "SELECT NAME,VALUE,EXPIRES FROM LOCKS";

private String createQuery = "INSERT INTO LOCKS (NAME,VALUE,EXPIRES) VALUES (?,?,?)";

private String deleteQuery = "DELETE FROM LOCKS WHERE NAME=? AND VALUE=?";

private String refreshQuery = "UPDATE LOCKS SET EXPIRES=? WHERE NAME=? AND VALUE=?";

private String findOneByNameQuery = "SELECT NAME,VALUE,EXPIRES FROM LOCKS WHERE NAME=?";

public JdbcLockService(DataSource dataSource) {
Expand All @@ -69,8 +73,8 @@ public Lock create(String name) throws LockExistsException {
throw new LockExistsException();
}
}
lock = new Lock(name, UUID.randomUUID().toString(), new Date(
System.currentTimeMillis() + expiry));
lock = new Lock(name, UUID.randomUUID().toString(),
new Date(System.currentTimeMillis() + expiry));
jdbcTemplate.update(createQuery, lock.getName(), lock.getValue(),
lock.getExpires());
return lock;
Expand All @@ -80,34 +84,37 @@ public Lock create(String name) throws LockExistsException {
@Transactional(isolation = Isolation.REPEATABLE_READ)
public boolean release(String name, String value) throws LockNotHeldException {
Lock lock = getLock(name);
if (lock!=null) {
if (lock != null) {
if (!lock.getValue().equals(value)) {
throw new LockNotHeldException();
}
if (lock.isExpired()) {
throw new LockNotHeldException();
}
int changes = jdbcTemplate.update(deleteQuery, lock.getName(),
lock.getValue());
return changes > 0;
}
int changes = jdbcTemplate.update(deleteQuery, lock.getName(), lock.getValue());
return changes > 0;
return false;
}

@Override
@Transactional(isolation = Isolation.REPEATABLE_READ)
public Lock refresh(String name, String value) throws LockNotHeldException {
Lock lock = getLock(name);
if (lock!=null) {
if (lock != null) {
if (!lock.getValue().equals(value)) {
throw new LockNotHeldException();
}
if (lock.isExpired()) {
throw new LockNotHeldException();
}
}
int changes = jdbcTemplate.update(refreshQuery, lock.getExpires(),
lock.getName(), lock.getValue());
if (changes > 0) {
return lock;

int changes = jdbcTemplate.update(refreshQuery, lock.getExpires(),
lock.getName(), lock.getValue());
if (changes > 0) {
return lock;
}
}
throw new LockNotHeldException();
}
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/locksdemo/Lock.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

/**
* A value object representing a named lock, with a globally unique value and an expiry.
*
* @author Dave Syer
*
*/
Expand All @@ -33,16 +34,18 @@ public class Lock implements Comparable<Lock> {
* The name of the lock.
*/
private final String name;

/**
* The value of the lock (globally unique, or at least different for locks with the
* same name and different expiry).
*/
private final String value;

/**
* The expiry of the lock expressed as a point in time.
*/
private final Date expires;

public boolean isExpired() {
return expires.before(new Date());
}
Expand Down
6 changes: 1 addition & 5 deletions src/main/java/locksdemo/LockService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@
* holder to prove that he holds the lock. The value is thus unique per lock and per
* expiry period (i.e. 2 locks held at different times with the same name will have
* different values)..
*
*
* @author Dave Syer
*
*/
public interface LockService {

/**
* Iterate the existing locks.
*
* @return an iterable of all locks
*/
Iterable<Lock> findAll();
Expand All @@ -42,7 +41,6 @@ public interface LockService {
* hold the lock with this name at any given time. Locks expire and can also be
* released by the owner, so after either of those events the lock can be acquired by
* the same or a different process.
*
* @param name the name identifying the lock
* @return a Lock containing a value that can be used to release or refresh the lock
* @throws LockExistsException
Expand All @@ -52,7 +50,6 @@ public interface LockService {
/**
* Release a lock before it expires. Only the holder of a lock can release it, and the
* holder must have the correct unique value to prove that he holds it.
*
* @param name the name of the lock
* @param value the value of the lock (which has to match the value when it was
* acquired)
Expand All @@ -66,7 +63,6 @@ public interface LockService {
* hold the lock there will be an exception, but the implementation may not be able to
* tell if it was because he formerly held the lock and it expired, or if it simply
* was never held.
*
* @param name the name of the lock
* @param value the value of the lock (which has to match the value when it was
* acquired)
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/locksdemo/LocksApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,49 @@ public class LocksApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(LocksApplication.class, args);
}

@Bean
public LocksController locksController(LockService lockService) {
return new LocksController(lockService);
}

@ConditionalOnClass(RedisConnectionFactory.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@Configuration
protected static class RedisLockServiceConfiguration {

@Bean
@ConditionalOnMissingBean(LockService.class)
public RedisLockService lockService(RedisConnectionFactory connectionFactory) {
return new RedisLockService(connectionFactory);
}

}

@ConditionalOnClass(RedisConnectionFactory.class)
@ConditionalOnMissingBean(RedisConnectionFactory.class)
@Configuration
protected static class FallbackSimpleLockServiceConfiguration {

@Bean
@ConditionalOnMissingBean(LockService.class)
public SimpleLockService lockService() {
return new SimpleLockService();
}

}

@ConditionalOnMissingClass(name="org.springframework.data.redis.connection.RedisConnectionFactory")
@ConditionalOnMissingClass(
name = "org.springframework.data.redis.connection.RedisConnectionFactory")
@Configuration
protected static class SimpleLockServiceConfiguration {

@Bean
@ConditionalOnMissingBean(LockService.class)
public SimpleLockService lockService() {
return new SimpleLockService();
}

}

}
28 changes: 14 additions & 14 deletions src/main/java/locksdemo/LocksController.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,63 +33,63 @@

/**
* @author Dave Syer
*
*/
@RestController
@RequestMapping("/")
@RequiredArgsConstructor(onConstructor=@_(@Autowired))
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class LocksController {

private final LockService service;

@RequestMapping(method=RequestMethod.GET)
@RequestMapping(method = RequestMethod.GET)
public Iterable<Lock> locks() {
return service.findAll();
}

@RequestMapping(value="{name}", method=RequestMethod.POST)
@RequestMapping(value = "{name}", method = RequestMethod.POST)
public Lock create(@PathVariable String name) {
return service.create(name);
}

@RequestMapping(value="{name}/{value}", method=RequestMethod.DELETE)
public Map<String, Object> release(@PathVariable String name, @PathVariable String value) {
@RequestMapping(value = "{name}/{value}", method = RequestMethod.DELETE)
public Map<String, Object> release(@PathVariable String name,
@PathVariable String value) {
if (!service.release(name, value)) {
throw new NoSuchLockException();
}
return Collections.singletonMap("status", (Object) "OK");
}

@RequestMapping(value="{name}/{value}", method=RequestMethod.PUT)
@RequestMapping(value = "{name}/{value}", method = RequestMethod.PUT)
public Lock refresh(@PathVariable String name, @PathVariable String value) {
return service.refresh(name, value);
}

@ExceptionHandler(LockExistsException.class)
@ResponseBody
public ResponseEntity<Map<String, Object>> lockExists() {
Map<String, Object> body = new HashMap<String, Object>();
body.put("status", "INVALID");
body.put("description", "Lock already exists");
return new ResponseEntity<Map<String, Object>>(body, HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(NoSuchLockException.class)
@ResponseBody
public ResponseEntity<Map<String, Object>> noSuchLock() {
Map<String, Object> body = new HashMap<String, Object>();
Map<String, Object> body = new HashMap<>();
body.put("status", "INVALID");
body.put("description", "Lock not found");
return new ResponseEntity<Map<String, Object>>(body, HttpStatus.NOT_FOUND);
return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
}

@ExceptionHandler(LockNotHeldException.class)
@ResponseBody
public ResponseEntity<Map<String, Object>> lockNotHeld() {
Map<String, Object> body = new HashMap<String, Object>();
Map<String, Object> body = new HashMap<>();
body.put("status", "INVALID");
body.put("description", "Lock not held (values do not match)");
return new ResponseEntity<Map<String, Object>>(body, HttpStatus.NOT_FOUND);
return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
}

}
Loading