package com.orbekk.same; import java.io.IOException; import org.codehaus.jackson.JsonGenerationException; 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; import com.orbekk.same.State.Component; /** * TODO: Use WeakReference in order to make variables GC-able. */ public class VariableFactory { private Logger logger = LoggerFactory.getLogger(getClass()); private ClientInterface client; private ObjectMapper mapper = new ObjectMapper(); private class VariableImpl implements Variable, StateChangedListener { String identifier; TypeReference type; T value; long revision = 0; OnChangeListener listener = null; boolean waitingForUpdate; public VariableImpl(String identifier, TypeReference type) { this.identifier = identifier; this.type = type; } @Override public T get() { return value; } @Override public synchronized void set(T value) throws UpdateConflict { try { String serializedValue = mapper.writeValueAsString(value); client.set(identifier, serializedValue, revision); waitingForUpdate = true; } catch (JsonGenerationException e) { logger.warn("Failed to convert to JSON: {}", value); logger.warn("Parse exception.", e); waitingForUpdate = false; throw new RuntimeException(e); } catch (JsonMappingException e) { logger.warn("Failed to convert to JSON: {}", value); logger.warn("Parse exception.", e); waitingForUpdate = false; throw new RuntimeException(e); } catch (IOException e) { logger.warn("Failed to cornvert to JSON: {}", value); logger.warn("Parse exception.", e); waitingForUpdate = false; throw new RuntimeException(e); } } @Override public void update() { value = client.getState().getParsedData(identifier, type); revision = client.getState().getRevision(identifier); } @Override public void setOnChangeListener(OnChangeListener listener) { this.listener = listener; } @Override public synchronized void waitForChange() { while (waitingForUpdate) { try { wait(); } catch (InterruptedException e) { waitingForUpdate = false; return; } } } @Override public synchronized boolean waitingForUpdate() { return waitingForUpdate; } @Override public synchronized void stateChanged(Component component) { if (component.getName().equals(identifier)) { if (listener != null) { listener.valueChanged(this); } waitingForUpdate = false; notifyAll(); } } } public static VariableFactory create(ClientInterface client) { return new VariableFactory(client); } VariableFactory(ClientInterface client) { this.client = client; } public Variable create(String identifier, TypeReference type) { VariableImpl variable = new VariableImpl(identifier, type); variable.update(); client.addStateListener(variable); return variable; } public Variable createString(String identifier) { return create(identifier, new TypeReference() {}); } }