From 008f40dcd76f7eedc0360f94dd42d2d12e3a8793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kjetil=20=C3=98rbekk?= Date: Fri, 13 Jan 2012 12:12:37 +0100 Subject: Add support for JSON state. Use Jackson for serialization and deserialization of JSON objects. --- .../java/com/orbekk/same/MasterServiceImpl.java | 21 ++- same/src/main/java/com/orbekk/same/State.java | 179 ++++++++++++--------- .../com/orbekk/same/MasterServiceImplTest.java | 22 ++- 3 files changed, 146 insertions(+), 76 deletions(-) (limited to 'same') diff --git a/same/src/main/java/com/orbekk/same/MasterServiceImpl.java b/same/src/main/java/com/orbekk/same/MasterServiceImpl.java index 64cde2f..50a5607 100644 --- a/same/src/main/java/com/orbekk/same/MasterServiceImpl.java +++ b/same/src/main/java/com/orbekk/same/MasterServiceImpl.java @@ -1,5 +1,7 @@ package com.orbekk.same; +import java.util.List; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,9 +14,22 @@ public class MasterServiceImpl implements MasterService, UrlReceiver { } @Override - public void joinNetworkRequest(String networkName, String clientUrl) { - // TODO Auto-generated method stub - + public synchronized void joinNetworkRequest(String networkName, String clientUrl) { + if (networkName.equals(state.getDataOf(".networkName"))) { + List participants = state.getList(".participants"); + if (!participants.contains(clientUrl)) { + participants.add(clientUrl); + } else { + logger.warn("Client {} already part of network. " + + "Ignoring participation request", clientUrl); + } + state.updateFromObject(".participants", participants, + state.getRevision(".participants")); + } else { + logger.warn("Client {} tried to join {}, but network name is {}", + new Object[]{ clientUrl, networkName, + state.getDataOf(".networkName") }); + } } @Override diff --git a/same/src/main/java/com/orbekk/same/State.java b/same/src/main/java/com/orbekk/same/State.java index 6b7c824..303caca 100644 --- a/same/src/main/java/com/orbekk/same/State.java +++ b/same/src/main/java/com/orbekk/same/State.java @@ -1,17 +1,29 @@ package com.orbekk.same; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.HashMap; +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class State { + private Logger logger = LoggerFactory.getLogger(getClass()); private Map state = new HashMap(); - - private long stateIteration = 0; - private Map participants = new HashMap(); - private String networkName = ""; - private String masterId = ""; - private String data = ""; + private ObjectMapper mapper = new ObjectMapper(); + public State(String networkName) { + update(".networkName", networkName, 0); + updateFromObject(".participants", new ArrayList(), 0); + } + public boolean update(String componentName, String data, long revision) { Component component = null; if (!state.containsKey(componentName)) { @@ -39,6 +51,65 @@ public class State { } } + public long getRevision(String componentName) { + Component component = state.get(componentName); + if (component != null) { + return component.getRevision(); + } else { + logger.warn("getRevision: Unknown component {}. Returning 0", + componentName); + return 0; + } + } + + /** + * Parses a JSON value using Jackson ObjectMapper. + */ + public T getParsedData(String componentName, TypeReference type) { + String data = getDataOf(componentName); + if (data != null) { + try { + return mapper.readValue(data, type); + } catch (JsonParseException e) { + logger.warn("Failed to parse value {} ", data); + logger.warn("Parse exception: {}", e); + } catch (JsonMappingException e) { + logger.warn("Failed to parse value {} ", data); + logger.warn("Parse exception: {}", e); + + } catch (IOException e) { + logger.warn("Failed to parse value {} ", data); + logger.warn("Parse exception: {}", e); + } + } + return null; + } + + public List getList(String componentName) { + return getParsedData(componentName, + new TypeReference>(){}); + } + + public boolean updateFromObject(String componentName, Object data, long revision) { + String dataS; + try { + dataS = mapper.writeValueAsString(data); + return update(componentName, dataS, revision); + } catch (JsonGenerationException e) { + logger.warn("Failed to convert to JSON: {} ", data); + logger.warn("Parse exception: {}", e); + return false; + } catch (JsonMappingException e) { + logger.warn("Failed to convert to JSON: {} ", data); + logger.warn("Parse exception: {}", e); + return false; + } catch (IOException e) { + logger.warn("Failed to convert to JSON: {} ", data); + logger.warn("Parse exception: {}", e); + return false; + } + } + public static class Component { private long revision; private String data; @@ -66,70 +137,34 @@ public class State { return this.data + " @" + revision; } } - - public long getStateIteration() { - return stateIteration; - } - - public void setStateIteration(long stateIteration) { - this.stateIteration = stateIteration; - } - - public Map getParticipants() { - return participants; - } - - public String getNetworkName() { - return networkName; - } - - public void setNetworkName(String networkName) { - this.networkName = networkName; - } - - public String getMasterId() { - return masterId; - } - - public void setMasterId(String masterId) { - this.masterId = masterId; - } - - public String getData() { - return data; - } - - public void setData(String data) { - this.data = data; - } - - @Override - public String toString() { - StringBuilder participantsString = new StringBuilder(); - participantsString.append("["); - boolean first = true; - for (Map.Entry e : participants.entrySet()) { - if (!first) { - participantsString.append(", "); - } - first = false; - participantsString.append(e.getKey()) - .append("(") - .append(e.getValue()) - .append(")"); - String clientId = e.getKey(); - String url = e.getValue(); - } - participantsString.append("]"); - - return String.format( - "State( \n" + - " stateIteration = %d,\n" + - " networkName = %s,\n" + - " masterId = %s,\n" + - " data = %s,\n" + - " participants = %s\n" + - ")", stateIteration, networkName, masterId, data, - participantsString); - } +// +// @Override +// public String toString() { +// StringBuilder participantsString = new StringBuilder(); +// participantsString.append("["); +// boolean first = true; +// for (Map.Entry e : participants.entrySet()) { +// if (!first) { +// participantsString.append(", "); +// } +// first = false; +// participantsString.append(e.getKey()) +// .append("(") +// .append(e.getValue()) +// .append(")"); +// String clientId = e.getKey(); +// String url = e.getValue(); +// } +// participantsString.append("]"); +// +// return String.format( +// "State( \n" + +// " stateIteration = %d,\n" + +// " networkName = %s,\n" + +// " masterId = %s,\n" + +// " data = %s,\n" + +// " participants = %s\n" + +// ")", stateIteration, networkName, masterId, data, +// participantsString); +// } } diff --git a/same/src/test/java/com/orbekk/same/MasterServiceImplTest.java b/same/src/test/java/com/orbekk/same/MasterServiceImplTest.java index 826471e..9d8a134 100644 --- a/same/src/test/java/com/orbekk/same/MasterServiceImplTest.java +++ b/same/src/test/java/com/orbekk/same/MasterServiceImplTest.java @@ -2,10 +2,13 @@ package com.orbekk.same; import static org.junit.Assert.*; +import java.util.List; + +import org.codehaus.jackson.type.TypeReference; import org.junit.Test; public class MasterServiceImplTest { - private State state = new State(); + private State state = new State("TestNetwork"); private MasterServiceImpl master = new MasterServiceImpl(state); @Test @@ -14,4 +17,21 @@ public class MasterServiceImplTest { assertEquals("http://10.0.0.54:10050/MasterService.json", state.getDataOf(".masterUrl")); } + + @Test + public void testJsonState() { + List participants = + state.getParsedData(".participants", + new TypeReference>() { }); + assertEquals(participants.size(), 0); + participants.add("http://SomeUrl/"); + state.updateFromObject(".participants", participants, 1); + } + + @Test + public void joinNetworkAddsClient() { + master.joinNetworkRequest("TestNetwork", "http://clientUrl"); + List participants = state.getList(".participants"); + assertTrue(participants.contains("http://clientUrl")); + } } -- cgit v1.2.3