-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1359 from folio-org/OKAPI-1191-timer-NumberFormat…
…Exception OKAPI-1191: NumberFormatException in timerId halts Okapi
- Loading branch information
Showing
8 changed files
with
539 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
254 changes: 150 additions & 104 deletions
254
okapi-core/src/main/java/org/folio/okapi/managers/TimerManager.java
Large diffs are not rendered by default.
Oops, something went wrong.
103 changes: 103 additions & 0 deletions
103
okapi-core/src/main/java/org/folio/okapi/util/TenantProductSeq.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package org.folio.okapi.util; | ||
|
||
import java.util.Collection; | ||
import org.folio.okapi.bean.TimerDescriptor; | ||
|
||
/** | ||
* [tenant]_[product]_[seq] (like test_tenant_mod-foo_2) or [product]_[seq] (like mod-foo_2). | ||
* | ||
* <p>Used as {@link TimerDescriptor} id. | ||
*/ | ||
public class TenantProductSeq { | ||
private static final String TIMER_ENTRY_SEP = "_"; | ||
private final String tenantId; | ||
private final String product; | ||
private final int seq; | ||
|
||
/** | ||
* Constructor using the three components. | ||
*/ | ||
public TenantProductSeq(String tenantId, String product, int seq) { | ||
this.tenantId = tenantId; | ||
this.product = product; | ||
this.seq = seq; | ||
} | ||
|
||
/** | ||
* Like {@link #TenantProductSeq(String tenantProductSeq)} but the parameter | ||
* tenantId replaces the value from tenantProductSeq String. | ||
* | ||
* @param tenantId the replacement value; if null the value from | ||
* tenantProductSeq String is taken | ||
*/ | ||
public TenantProductSeq(String tenantId, String tenantProductSeq) { | ||
int pos2 = tenantProductSeq.lastIndexOf(TIMER_ENTRY_SEP); | ||
seq = Integer.parseInt(tenantProductSeq.substring(pos2 + 1)); | ||
int pos1 = tenantProductSeq.lastIndexOf(TIMER_ENTRY_SEP, pos2 - 1); | ||
product = tenantProductSeq.substring(pos1 + 1, pos2); | ||
if (tenantId != null) { | ||
this.tenantId = tenantId; | ||
return; | ||
} | ||
if (pos1 == -1) { | ||
this.tenantId = null; | ||
} else { | ||
this.tenantId = tenantProductSeq.substring(0, pos1); | ||
} | ||
} | ||
|
||
/** | ||
* Parse a String [tenant]_[product]_[seq] like test_tenant_mod-foo_2 | ||
* or [product]_[seq] like mod-foo_2. | ||
*/ | ||
public TenantProductSeq(String tenantProductSeq) { | ||
this(null, tenantProductSeq); | ||
} | ||
|
||
/** | ||
* The tenant id. | ||
*/ | ||
public String getTenantId() { | ||
return tenantId; | ||
} | ||
|
||
/** | ||
* The product, like mod-foo. | ||
*/ | ||
public String getProduct() { | ||
return product; | ||
} | ||
|
||
/** | ||
* The timer number in the timer array in the module descriptor, starting with 0. | ||
*/ | ||
public int getSeq() { | ||
return seq; | ||
} | ||
|
||
/** | ||
* Concatenation of the components, like mod-foo_2 or test_tenant_mod-foo_2. | ||
*/ | ||
public String toString() { | ||
if (tenantId == null) { | ||
return product + TIMER_ENTRY_SEP + seq; | ||
} else { | ||
return tenantId + TIMER_ENTRY_SEP + product + TIMER_ENTRY_SEP + seq; | ||
} | ||
} | ||
|
||
/** | ||
* For each TimerDescriptor alter the id by removing the tenant id from the String. | ||
* | ||
* <p>For example test_tenant_mod-foo_2 becomes mod-foo_2. | ||
*/ | ||
public static Collection<TimerDescriptor> stripTenantIdFromTimerId( | ||
Collection<TimerDescriptor> collection) { | ||
|
||
collection.forEach(timerDescriptor -> { | ||
var old = new TenantProductSeq(timerDescriptor.getId()); | ||
timerDescriptor.setId(old.getProduct() + TIMER_ENTRY_SEP + old.getSeq()); | ||
}); | ||
return collection; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
okapi-core/src/test/java/org/folio/okapi/service/impl/TimerStoreMemory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package org.folio.okapi.service.impl; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import org.folio.okapi.bean.TimerDescriptor; | ||
import org.folio.okapi.service.TimerStore; | ||
|
||
import io.vertx.core.Future; | ||
|
||
public class TimerStoreMemory implements TimerStore { | ||
|
||
private Map<String, TimerDescriptor> map = new HashMap<>(); | ||
|
||
public TimerStoreMemory() { | ||
} | ||
|
||
public TimerStoreMemory(TimerDescriptor timerDescriptor) { | ||
put(timerDescriptor); | ||
} | ||
|
||
@Override | ||
public Future<Void> init(boolean reset) { | ||
if (reset) { | ||
map.clear(); | ||
} | ||
return Future.succeededFuture(); | ||
} | ||
|
||
@Override | ||
public Future<List<TimerDescriptor>> getAll() { | ||
var list = new ArrayList<>(map.values()); | ||
return Future.succeededFuture(list); | ||
} | ||
|
||
@Override | ||
public Future<Void> put(TimerDescriptor timerDescriptor) { | ||
map.put(timerDescriptor.getId(), timerDescriptor); | ||
return Future.succeededFuture(); | ||
} | ||
|
||
@Override | ||
public Future<Boolean> delete(String id) { | ||
var timerDescriptor = map.remove(id); | ||
return Future.succeededFuture(timerDescriptor != null); | ||
} | ||
|
||
} |
62 changes: 62 additions & 0 deletions
62
okapi-core/src/test/java/org/folio/okapi/service/impl/TimerStorePostgresTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package org.folio.okapi.service.impl; | ||
|
||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.Matchers.empty; | ||
import static org.hamcrest.Matchers.hasSize; | ||
import static org.hamcrest.Matchers.is; | ||
|
||
import org.folio.okapi.bean.TimerDescriptor; | ||
import org.folio.okapi.util.PgTestBase; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
|
||
import io.vertx.core.Vertx; | ||
import io.vertx.core.json.JsonObject; | ||
import io.vertx.junit5.Timeout; | ||
import io.vertx.junit5.VertxExtension; | ||
import io.vertx.junit5.VertxTestContext; | ||
|
||
@Timeout(5000) | ||
@ExtendWith(VertxExtension.class) | ||
class TimerStorePostgresTest extends PgTestBase { | ||
|
||
static TimerStorePostgres timerStorePostgres; | ||
|
||
@BeforeAll | ||
static void beforeAll(Vertx vertx) { | ||
var conf = new JsonObject() | ||
.put("postgres_host", POSTGRESQL_CONTAINER.getHost()) | ||
.put("postgres_port", POSTGRESQL_CONTAINER.getFirstMappedPort() + "") | ||
.put("postgres_database", POSTGRESQL_CONTAINER.getDatabaseName()) | ||
.put("postgres_username", POSTGRESQL_CONTAINER.getUsername()) | ||
.put("postgres_password", POSTGRESQL_CONTAINER.getPassword()); | ||
var postgresHandle = new PostgresHandle(vertx, conf); | ||
timerStorePostgres = new TimerStorePostgres(postgresHandle); | ||
} | ||
|
||
@Test | ||
void test(VertxTestContext vtc) { | ||
timerStorePostgres.init(false) | ||
.compose(x -> timerStorePostgres.getAll()) | ||
.onComplete(vtc.succeeding(list -> assertThat(list, is(empty())))) | ||
.compose(x -> timerStorePostgres.put(timerDescriptor("test_tenant_mod-expire_0"))) | ||
.compose(x -> timerStorePostgres.getAll()) | ||
.onComplete(vtc.succeeding(list -> { | ||
assertThat(list, hasSize(1)); | ||
assertThat(list.get(0).getId(), is("test_tenant_mod-expire_0")); | ||
})) | ||
.compose(x -> timerStorePostgres.delete("test_tenant_mod-expire_0")) | ||
.compose(x -> timerStorePostgres.getAll()) | ||
.onComplete(vtc.succeeding(list -> { | ||
assertThat(list, is(empty())); | ||
vtc.completeNow(); | ||
})); | ||
} | ||
|
||
TimerDescriptor timerDescriptor(String id) { | ||
var timerDescriptor = new TimerDescriptor(); | ||
timerDescriptor.setId(id); | ||
return timerDescriptor; | ||
} | ||
} |
Oops, something went wrong.