Skip to content

Commit

Permalink
Deprecated old MemoryValuesStore, replaced by DbValuesStore
Browse files Browse the repository at this point in the history
Added story error on html
Added values filtering
  • Loading branch information
dutoitc committed Sep 30, 2017
1 parent 5fb2a3e commit d953478
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 40 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Version v1.2.0
==============
New:
- Added database store in replacement of memory datastore, with data historization and querying

Version v1.1.0
==============
- copper.properties support "serverPort" properties, default 30400
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/ch/mno/copper/CopperMediator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.mno.copper;

import ch.mno.copper.data.MemoryValuesStore;
import ch.mno.copper.data.DbValuesStore;
import ch.mno.copper.data.ValuesStore;

import java.io.FileInputStream;
import java.util.Properties;
Expand All @@ -12,23 +13,24 @@ public class CopperMediator {


private static final CopperMediator instance = new CopperMediator();
private final MemoryValuesStore valuesStore;
private final ValuesStore valuesStore;
private CopperDaemon daemon;
private Properties properties;

public CopperMediator() {
try {
properties = new Properties();
properties.load(new FileInputStream("copper.properties"));
this.valuesStore = MemoryValuesStore.getInstance();
//this.valuesStore = MemoryValuesStore.getInstance();
this.valuesStore = DbValuesStore.getInstance();
}catch (Exception e) {
throw new RuntimeException(e);
}
}

public static CopperMediator getInstance() { return instance; }

public MemoryValuesStore getValuesStore() {
public ValuesStore getValuesStore() {
return valuesStore;
}

Expand Down
66 changes: 40 additions & 26 deletions src/main/java/ch/mno/copper/data/MemoryValuesStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
* Put will erase data. get will return null or -1 if not found.
* Created by dutoitc on 29.01.2016.
*/
@Deprecated
public class MemoryValuesStore implements ValuesStore {

// TODO: dependency graph, with temporized triggers and quiet time
Expand All @@ -50,10 +51,10 @@ public static MemoryValuesStore getInstance() {
@Override
public void put(String key, String value) {
if (map.containsKey(key)) {
if (value==null && map.get(key)==null) return;
if (value == null && map.get(key) == null) return;
// commented: always store, as store date = last check date. TODO: implement from... to dates
//if (map.get(key)!=null && map.get(key).getValue().equals(value)) return;
if (map.get(key)!=null && !map.get(key).getValue().equals(value)) {
if (map.get(key) != null && !map.get(key).getValue().equals(value)) {
map.put(key, new StoreValue(-1, key, value, Instant.now(), null));
}
return; // Otehrwise same value
Expand All @@ -68,21 +69,21 @@ public Map<String, StoreValue> getValues() {
}



public void save(OutputStream os) throws IOException {
PrintWriter pw = new PrintWriter(os);
pw.write("1\n");
pw.write(map.size()+"\n");
map.forEach((k,v)->{
pw.write(map.size() + "\n");
map.forEach((k, v) -> {
StringBuilder sb = new StringBuilder();
sb.append(k);
// TODO: read/write à revoir (stocker toutes les valeurs)
sb.append('|');
sb.append(v==null||v.getValue()==null?null:v.getValue().replace("|", "£").replace("\n","¢"));
sb.append(v == null || v.getValue() == null ? null : v.getValue().replace("|", "£").replace("\n", "¢"));
sb.append('|');
sb.append(v==null?null:v.getTimestampFrom().getEpochSecond());
sb.append(v == null ? null : v.getTimestampFrom().getEpochSecond());
sb.append('|');
sb.append(v==null?null:v.getTimestampTo().getEpochSecond());
Instant timestampTo = v.getTimestampTo();
sb.append(v == null || timestampTo == null ? null : timestampTo.getEpochSecond());
sb.append('\n');
pw.write(sb.toString());
});
Expand Down Expand Up @@ -110,29 +111,30 @@ public void load(InputStream is) throws IOException {

// Version
int version = Integer.parseInt(reader.readLine());
if (version!=1) throw new RuntimeException("Unsupported version: " + version);
if (version != 1) throw new RuntimeException("Unsupported version: " + version);

// Size
int mapSize = Integer.parseInt(reader.readLine());
map = new HashMap<>(mapSize*4/3);
map = new HashMap<>(mapSize * 4 / 3);

// Map
for (int noLine=0; noLine<mapSize; noLine++) {
for (int noLine = 0; noLine < mapSize; noLine++) {
try {
String line = reader.readLine();
int p = line.indexOf('|');
String key = line.substring(0,p);
line = line.substring(p+1);
String key = line.substring(0, p);
line = line.substring(p + 1);

int p2 = line.lastIndexOf('|');
String timestampTo = line.substring(p2+1);
String timestampTo = line.substring(p2 + 1);
line = line.substring(0, p2);
p2 = line.lastIndexOf('|');
String timestampFrom = line.substring(p2+1);
String timestampFrom = line.substring(p2 + 1);
line = line.substring(0, p2);

String content = line.replaceAll("£", "|").replace("¢", "\n");
StoreValue sv = new StoreValue(-1, key, content, Instant.ofEpochSecond(Long.parseLong(timestampFrom)), Instant.ofEpochSecond(Long.parseLong(timestampTo)));
Instant timestampTo1 = timestampTo == null || "null".equals(timestampTo) ? null : Instant.ofEpochSecond(Long.parseLong(timestampTo));
StoreValue sv = new StoreValue(-1, key, content, Instant.ofEpochSecond(Long.parseLong(timestampFrom)), timestampTo1);

map.put(key, sv);
} catch (Exception e) {
Expand Down Expand Up @@ -191,23 +193,22 @@ public Instant getTimestampTo(String key) {
}

/**
*
* @param desc key1,key2...
* @param desc key1,key2...
* @param values values for keys, ordered
*/
public void putAll(String desc, List<String> values) {
String[] keys = desc.split(",");
if (keys.length!=values.size()) throw new RuntimeException("Wrong number of parameters");
for (int i=0; i<keys.length; i++) {
put(keys[i],values.get(i));
if (keys.length != values.size()) throw new RuntimeException("Wrong number of parameters");
for (int i = 0; i < keys.length; i++) {
put(keys[i], values.get(i));
}
}

@Override
public Map<String, String> getValuesMapString() {
// FIXME make it Java8
Map<String, String> values = new HashMap<>();
map.forEach((k,v)->values.put(k,v.getValue()));
map.forEach((k, v) -> values.put(k, v.getValue()));
return values;
}

Expand All @@ -219,11 +220,24 @@ public void clear() {
@Override
public Collection<String> queryValues(Instant from, Instant to) {
List<String> keys = new ArrayList<>();
for (Map.Entry<String, StoreValue> entry: map.entrySet()) {
if ((from==null || !entry.getValue().getTimestampFrom().isBefore(from)) &&
(to==null || !entry.getValue().getTimestampTo().isAfter(to)))
for (Map.Entry<String, StoreValue> entry : map.entrySet()) {
/*if ((from==null || entry.getValue().getTimestampFrom().isBefore(from)) &&
(to==null || entry.getValue().getTimestampTo()==null || entry.getValue().getTimestampTo().equals(Instant.MAX) || !entry.getValue().getTimestampTo().isAfter(to)))
{
keys.add(entry.getKey());
}*/

Instant tsFrom = entry.getValue().getTimestampFrom();
Instant tsTo = entry.getValue().getTimestampTo();
if (tsTo==null) tsTo = Instant.MAX;
if (
(tsFrom.isBefore(from) && (tsTo.isAfter(to)))
||
(!tsFrom.isBefore(from) && tsFrom.isBefore(to))
||
(tsTo.isAfter(from) && !tsTo.isAfter(to))
) {
keys.add(entry.getKey());
}
}
return keys;
Expand All @@ -233,7 +247,7 @@ public Collection<String> queryValues(Instant from, Instant to) {
public List<List<String>> queryValues(Instant from, Instant to, String columns) {
Collection<String> keys = queryValues(from, to);
List<List<String>> values = new ArrayList<>();
for (String key: keys) {
for (String key : keys) {
List<String> line = new ArrayList<>();
StoreValue sv = map.get(key);
line.add(sv.getKey());
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/ch/mno/copper/stories/Story.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ private boolean matchWhen(String storedValue, String operator, String expectedVa
}
}

public String getError() {
return error;
}


private class When {
private final String variable;
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/ch/mno/copper/web/CopperServices.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ public void write(JsonWriter writer, T obj) throws IOException {
writer.value(story.getCron());
writer.name("storyText");
writer.value(story.getStoryText());
writer.name("hasError");
writer.value(story.hasError());
writer.name("error");
writer.value(story.getError());
// writer.endArray();

writer.endObject();
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/WEB-INF/app/controllers/stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ angular.module('copperApp.stories', ['ngRoute'])
}
}



$scope.refreshStories();


Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/WEB-INF/app/controllers/values.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ angular.module('copperApp.values', ['ngRoute'])
$scope.values=data;
});

$scope.filter = function(object, field, filter) {
if (!object) return {};
if (!filter) return object;

var filteredObject = {};
Object.keys(object).forEach(function(key) {
if (object[key][field].includes(filter)) {
filteredObject[key] = object[key];
}
});

return filteredObject;
};

/*
$http.get('data/routes.json')
Expand Down
7 changes: 6 additions & 1 deletion src/main/resources/WEB-INF/app/views/stories.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ <h1>Stories</h1>
<table class="table-striped table-bordered" style="width: 100%; border: 1px outset silver">
<thead>
<th style="text-align:right;padding: 5px;">Name</th>
<th>Notes</th>
<th style="text-align:left; padding-left: 10px">Cron</th>
<th style="text-align:left; padding-left: 10px">Actions</th>
</thead>
<tbody>
<tr ng-repeat="story in stories | filter:searchText | orderBy:'name'">
<td style="text-align:right;padding: 5px;font-weight:bold"><a title="{{story.storyText}}">{{story.name}}</a></td>
<td style="text-align:left; padding-left: 10px">
<div class="glyphicon glyphicon-exclamation-sign" style="color:red" title="{{story.error}}" ng-show="story.hasError"></div>
</td>
<td style="text-align:left; padding-left: 10px">{{story.cron}}</td>
<td>
<button class="btn btn-primary" ng-click="runStory(story.name)">Run</button>
Expand All @@ -23,4 +27,5 @@ <h1>Stories</h1>

</table>
<br/>
<a href="#/story/new" type="submit" class="btn btn-success"><span class="glyphicon glyphicon-add"></span> Create a story</a>
<a href="#/story/new" type="submit" class="btn btn-success"><span class="glyphicon glyphicon-add"></span> Create a story</a>

5 changes: 5 additions & 0 deletions src/main/resources/WEB-INF/app/views/story.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ <h1>Story {{originalStoryName}}</h1>
<label for="storyText">Text</label>
<textarea class="form-control" rows="10" ng-model="story.storyText" id="storyText" name="storyText"></textarea>
</div>
<div class="form-group">
<label for="storyText">Errors</label>
<textarea class="form-control" readonly="true" rows="10" ng-model="story.error" id="storyError" name="storyError"></textarea>
</div>

<button type="button" class="btn btn-primary glyphicon glyphicon-ok" ng-click="submit()" ng-show="storyForm.$dirty">Save changes</button>
<a href="#/stories" type="submit" class="btn btn-success"><span class="glyphicon glyphicon-arrow-left"></span> Cancel</a>
</form>
11 changes: 7 additions & 4 deletions src/main/resources/WEB-INF/app/views/values.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ <h1>Values</h1>
<div class="row">


<label>Search: <input ng-model="searchText"></label>
<table class="table-striped" style="width: 80%; margin: auto; border: 1px outset silver">
<thead>
<th style="text-align:right;padding: 5px">Key</th>
<th style="text-align:left; padding-left: 10px">Value</th>
<th style="text-align:center">Date</th>
<th style="text-align:center">Date from</th>
<th style="text-align:center">Date to</th>
</thead>
<tbody>
<tr ng-repeat="(k,v) in values">
<td style="text-align:right;padding: 5px;font-weight:bold">{{k}}</td>
<tr ng-repeat="(k,v) in filter(values, 'key', searchText)">
<td style="text-align:right;padding: 5px;font-weight:bold"><a href="history?key={{k}}">{{k}}</a></td>
<td style="text-align:left; padding-left: 10px">{{v.value}}</td>
<td style="text-align:center;width: 150px">{{v.timestamp | date : 'yyyy-MM-dd HH:mm:ss'}}</td>
<td style="text-align:center;width: 150px">{{v.timestampFrom.seconds*1000 | date : 'yyyy-MM-dd HH:mm:ss'}}</td>
<td style="text-align:center;width: 150px">{{v.timestampTo.seconds*1000 | date : 'yyyy-MM-dd HH:mm:ss'}}</td>
</tr>
</tbody>
</table>
Expand Down
7 changes: 4 additions & 3 deletions src/test/java/ch/mno/copper/MemoryValuesStoreTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ public void testX() throws InterruptedException {
Assert.assertEquals(1, st.queryValues(t, Instant.MAX).size());
t = Instant.now();
Collection<String> strings = st.queryValues(t, Instant.MAX);
Assert.assertEquals(0, strings.size());
Assert.assertEquals(1, strings.size());
Assert.assertTrue(System.currentTimeMillis()-st.getTimestampFrom("key1").toEpochMilli()<1000);
st.put("key1", "value2");
Assert.assertEquals(1, st.queryValues(t, Instant.MAX).size());
Assert.assertEquals("value2", st.getValue("key1"));
Thread.sleep(1);
t = Instant.now();
st.put("key1", "value2");
Assert.assertEquals(0, st.queryValues(t, Instant.MAX).size()); // Same values
Assert.assertEquals(1, st.queryValues(t, Instant.MAX).size()); // Same values
}

@Test
Expand Down Expand Up @@ -69,7 +69,8 @@ public void testPutAll() {
Map<String, String> map = st.getValuesMapString();
Assert.assertEquals("v1", map.get("key1"));
Assert.assertEquals("v3", map.get("key3"));
Assert.assertTrue(st.getValues().get("key1").toString().startsWith("StoreValue{value='v1', timestamp="));
String str = st.getValues().get("key1").toString();
Assert.assertTrue(str, str.startsWith("StoreValue{key='key1', value='v1', timestampFrom="));
}

@Test
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/ch/mno/copper/WebServer4TestsTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package ch.mno.copper;

import ch.mno.copper.data.MemoryValuesStore;
import ch.mno.copper.data.DbValuesStore;
import ch.mno.copper.web.WebServer;
import org.apache.commons.io.IOUtils;
import org.junit.AfterClass;
Expand All @@ -26,7 +26,7 @@ public static void init() throws InterruptedException {
thread = new Thread(srv);
thread.start();
Thread.sleep(2000);
MemoryValuesStore.getInstance().put("aKey", "aValue");
DbValuesStore.getInstance().put("aKey", "aValue");
}

@AfterClass
Expand Down

0 comments on commit d953478

Please sign in to comment.