Skip to content
Permalink
Browse files
Created clockoffset endpoint and persisted per tenant.
  • Loading branch information
myrle-krantz committed Dec 16, 2017
1 parent eefbf8e commit a3c200e9b14cc47df34881b87b6805aeb5e34f21
Showing 15 changed files with 680 additions and 1 deletion.
@@ -17,6 +17,7 @@

import io.mifos.core.api.util.CustomFeignClientsConfiguration;
import io.mifos.rhythm.api.v1.domain.Beat;
import io.mifos.rhythm.api.v1.domain.ClockOffset;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
@@ -31,6 +32,21 @@
@SuppressWarnings("unused")
@FeignClient(value="rhythm-v1", path="/rhythm/v1", configuration = CustomFeignClientsConfiguration.class)
public interface RhythmManager {
@RequestMapping(
value = "/clockoffset",
method = RequestMethod.PUT,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE
)
void setClockOffset(ClockOffset clockOffset);

@RequestMapping(
value = "/clockoffset",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE
)
ClockOffset getClockOffset();

@RequestMapping(
value = "/applications/{applicationidentifier}",
@@ -0,0 +1,101 @@
/*
* Copyright 2017 Kuelap, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.mifos.rhythm.api.v1.domain;

import org.hibernate.validator.constraints.Range;

import java.util.Objects;

/**
* @author Myrle Krantz
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public class ClockOffset {
@Range(min = 0, max = 23)
private Integer hours;

@Range(min = 0, max = 59)
private Integer minutes;

@Range(min = 0, max = 59)
private Integer seconds;

public ClockOffset() {
this.hours = 0;
this.minutes = 0;
this.seconds = 0;
}

public ClockOffset(Integer hours, Integer minutes) {
this.hours = hours;
this.minutes = minutes;
this.seconds = 0;
}

public ClockOffset(Integer hours, Integer minutes, Integer seconds) {
this.hours = hours;
this.minutes = minutes;
this.seconds = seconds;
}

public Integer getHours() {
return hours;
}

public void setHours(Integer hours) {
this.hours = hours;
}

public Integer getMinutes() {
return minutes;
}

public void setMinutes(Integer minutes) {
this.minutes = minutes;
}

public Integer getSeconds() {
return seconds;
}

public void setSeconds(Integer seconds) {
this.seconds = seconds;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClockOffset that = (ClockOffset) o;
return Objects.equals(hours, that.hours) &&
Objects.equals(minutes, that.minutes) &&
Objects.equals(seconds, that.seconds);
}

@Override
public int hashCode() {
return Objects.hash(hours, minutes, seconds);
}

@Override
public String toString() {
return "ClockOffset{" +
"hours=" + hours +
", minutes=" + minutes +
", seconds=" + seconds +
'}';
}
}
@@ -27,8 +27,10 @@ public interface EventConstants {
String POST_BEAT = "post-beat";
String DELETE_APPLICATION = "delete-application";
String DELETE_BEAT = "delete-beat";
String PUT_CLOCKOFFSET = "put-clockoffset";
String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
String SELECTOR_POST_BEAT = SELECTOR_NAME + " = '" + POST_BEAT + "'";
String SELECTOR_DELETE_APPLICATION = SELECTOR_NAME + " = '" + DELETE_APPLICATION + "'";
String SELECTOR_DELETE_BEAT = SELECTOR_NAME + " = '" + DELETE_BEAT + "'";
String SELECTOR_PUT_CLOCKOFFSET = SELECTOR_NAME + " = '" + PUT_CLOCKOFFSET + "'";
}
@@ -0,0 +1,67 @@
/*
* Copyright 2017 Kuelap, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.mifos.rhythm.api.v1.domain;

import io.mifos.core.test.domain.ValidationTest;
import io.mifos.core.test.domain.ValidationTestCase;
import org.junit.runners.Parameterized;

import java.util.ArrayList;
import java.util.Collection;

/**
* @author Myrle Krantz
*/
public class ClockOffsetTest extends ValidationTest<ClockOffset> {
public ClockOffsetTest(final ValidationTestCase<ClockOffset> testCase) {
super(testCase);
}

@Override
protected ClockOffset createValidTestSubject() {
return new ClockOffset();
}

@Parameterized.Parameters
public static Collection testCases() {
final Collection<ValidationTestCase> ret = new ArrayList<>();
ret.add(new ValidationTestCase<ClockOffset>("basicCase")
.adjustment(x -> {})
.valid(true));
ret.add(new ValidationTestCase<ClockOffset>("everythingMidRange")
.adjustment(x -> {x.setHours(12); x.setMinutes(30); x.setSeconds(30);})
.valid(true));
ret.add(new ValidationTestCase<ClockOffset>("negativeHours")
.adjustment(x -> x.setHours(-1))
.valid(false));
ret.add(new ValidationTestCase<ClockOffset>("outOfDayHours")
.adjustment(x -> x.setHours(24))
.valid(false));
ret.add(new ValidationTestCase<ClockOffset>("negativeMinutes")
.adjustment(x -> x.setMinutes(-1))
.valid(false));
ret.add(new ValidationTestCase<ClockOffset>("outOfRangeMinutes")
.adjustment(x -> x.setMinutes(60))
.valid(false));
ret.add(new ValidationTestCase<ClockOffset>("negativeSeconds")
.adjustment(x -> x.setMinutes(-1))
.valid(false));
ret.add(new ValidationTestCase<ClockOffset>("outOfRangeSeconds")
.adjustment(x -> x.setMinutes(60))
.valid(false));
return ret;
}
}
@@ -17,6 +17,7 @@

import io.mifos.core.api.util.NotFoundException;
import io.mifos.rhythm.api.v1.domain.Beat;
import io.mifos.rhythm.api.v1.domain.ClockOffset;
import io.mifos.rhythm.api.v1.events.BeatEvent;
import io.mifos.rhythm.api.v1.events.EventConstants;
import io.mifos.rhythm.service.internal.repository.BeatEntity;
@@ -28,6 +29,7 @@
import org.springframework.beans.factory.annotation.Autowired;

import javax.transaction.Transactional;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
@@ -130,6 +132,23 @@ public void twentyFourBeats() throws InterruptedException {
beats.forEach(x -> Assert.assertTrue(allEntities.contains(x)));
}

@Test
public void shouldChangeTheTenantClockOffset() throws InterruptedException {
final ClockOffset initialClockOffset = this.testSubject.getClockOffset();
Assert.assertEquals(Integer.valueOf(0), initialClockOffset.getHours());
Assert.assertEquals(Integer.valueOf(0), initialClockOffset.getMinutes());
Assert.assertEquals(Integer.valueOf(0), initialClockOffset.getSeconds());

final LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
final ClockOffset offsetToNow = new ClockOffset(now.getHour(), now.getMinute(), now.getSecond());
this.testSubject.setClockOffset(offsetToNow);

Assert.assertTrue(this.eventRecorder.wait(EventConstants.PUT_CLOCKOFFSET, offsetToNow));

final ClockOffset changedClockOffset = this.testSubject.getClockOffset();
Assert.assertEquals(offsetToNow, changedClockOffset);
}

@Test
public void shouldBeatForMissingDays() throws InterruptedException {
final String applicationIdentifier = "funnybusiness-v6";
@@ -0,0 +1,51 @@
/*
* Copyright 2017 Kuelap, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.mifos.rhythm.listener;

import io.mifos.core.lang.config.TenantHeaderFilter;
import io.mifos.core.test.listener.EventRecorder;
import io.mifos.rhythm.api.v1.domain.ClockOffset;
import io.mifos.rhythm.api.v1.events.EventConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

/**
* @author Myrle Krantz
*/
@SuppressWarnings("unused")
@Component
public class ClockOffsetEventListener {
private final EventRecorder eventRecorder;

@Autowired
public ClockOffsetEventListener(@SuppressWarnings("SpringJavaAutowiringInspection") final EventRecorder eventRecorder) {
super();
this.eventRecorder = eventRecorder;
}

@JmsListener(
subscription = EventConstants.DESTINATION,
destination = EventConstants.DESTINATION,
selector = EventConstants.SELECTOR_PUT_CLOCKOFFSET
)
public void onChangeClockOffset(
@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
final String payload) {
this.eventRecorder.event(tenant, EventConstants.PUT_CLOCKOFFSET, payload, ClockOffset.class);
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2017 Kuelap, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.mifos.rhythm.service.internal.command;

import io.mifos.rhythm.api.v1.domain.ClockOffset;

/**
* @author Myrle Krantz
*/
public class ChangeClockOffsetCommand {
private final String tenantIdentifier;

private final ClockOffset instance;

public ChangeClockOffsetCommand(
final String tenantIdentifier,
final ClockOffset instance) {
this.tenantIdentifier = tenantIdentifier;
this.instance = instance;
}

public String getTenantIdentifier() {
return tenantIdentifier;
}

public ClockOffset getInstance() {
return instance;
}

@Override
public String toString() {
return "ChangeClockOffsetCommand{" +
"tenantIdentifier='" + tenantIdentifier + '\'' +
", instance=" + instance +
'}';
}
}

0 comments on commit a3c200e

Please sign in to comment.