com.almende.eve.state.couchdb.CouchDBState Maven / Gradle / Ivy
/*
* Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
* License: The Apache Software License, Version 2.0
*/
package com.almende.eve.state.couchdb;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ektorp.CouchDbConnector;
import org.ektorp.UpdateConflictException;
import com.almende.eve.rpc.jsonrpc.jackson.JOM;
import com.almende.eve.state.AbstractState;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion;
import com.fasterxml.jackson.databind.node.NullNode;
/**
* The Class CouchDBState.
*/
public class CouchDBState extends AbstractState {
private static final Logger LOG = Logger.getLogger("CouchDBState");
private String revision = null;
private Map properties = Collections
.synchronizedMap(new HashMap());
private CouchDbConnector db = null;
private String id = null;
/**
* Instantiates a new couch db state.
*/
public CouchDBState() {
}
/**
* Instantiates a new couch db state.
*
* @param agentId the agent id
* @param db the db
*/
public CouchDBState(final String agentId, final CouchDbConnector db) {
super(agentId);
id = couchify(agentId);
this.db = db;
}
/**
* Read.
*/
private void read() {
final CouchDBState state = db.get(CouchDBState.class, id);
revision = state.revision;
properties = state.properties;
}
/**
* Update.
*/
private synchronized void update() {
db.update(this);
}
/* (non-Javadoc)
* @see com.almende.eve.state.AbstractState#locPut(java.lang.String, com.fasterxml.jackson.databind.JsonNode)
*/
@Override
public synchronized JsonNode locPut(final String key, final JsonNode value) {
final String ckey = couchify(key);
JsonNode result = null;
try {
result = properties.put(ckey, value);
update();
} catch (final UpdateConflictException uce) {
read();
locPut(ckey, value);
} catch (final Exception e) {
LOG.log(Level.WARNING, "Failed to store property", e);
}
return result;
}
/* (non-Javadoc)
* @see com.almende.eve.state.AbstractState#locPutIfUnchanged(java.lang.String, com.fasterxml.jackson.databind.JsonNode, com.fasterxml.jackson.databind.JsonNode)
*/
@Override
public synchronized boolean locPutIfUnchanged(final String key,
final JsonNode newVal, JsonNode oldVal) {
final String ckey = couchify(key);
boolean result = false;
try {
JsonNode cur = NullNode.getInstance();
if (properties.containsKey(ckey)) {
cur = properties.get(ckey);
}
if (oldVal == null) {
oldVal = NullNode.getInstance();
}
// Poor mans equality as some Numbers are compared incorrectly: e.g.
// IntNode versus LongNode
if (oldVal.equals(cur) || oldVal.toString().equals(cur.toString())) {
properties.put(ckey, newVal);
update();
result = true;
}
} catch (final UpdateConflictException uce) {
read();
locPutIfUnchanged(ckey, newVal, oldVal);
} catch (final Exception e) {
LOG.log(Level.WARNING, "", e);
}
return result;
}
/**
* Check the key if it starts with a _
* Add a prefix if this is the case, because _ properties are reserved.
*
* @param key the key
* @return prefixed key (if necessary)
*/
private String couchify(final String key) {
if (key.startsWith("_")) {
return "cdb" + key;
}
return key;
}
/**
* Check the key if it starts with a _
* Add a prefix if this is the case, because _ properties are reserved.
*
* @param key the key
* @return prefixed key (if necessary)
*/
private String decouchify(final String key) {
if (key.startsWith("cdb_")) {
return key.replaceFirst("cdb_", "_");
}
return key;
}
/* (non-Javadoc)
* @see com.almende.eve.state.State#init()
*/
@Override
public void init() {
}
/* (non-Javadoc)
* @see com.almende.eve.state.State#destroy()
*/
@Override
public void destroy() {
}
/* (non-Javadoc)
* @see com.almende.eve.state.State#remove(java.lang.String)
*/
@Override
public synchronized Object remove(final String key) {
Object result = null;
try {
result = properties.remove(key);
update();
} catch (final Exception e) {
LOG.log(Level.WARNING, "", e);
}
return result;
}
/* (non-Javadoc)
* @see com.almende.eve.state.State#containsKey(java.lang.String)
*/
@Override
public boolean containsKey(final String key) {
final String ckey = couchify(key);
boolean result = false;
try {
result = properties.containsKey(ckey);
} catch (final Exception e) {
LOG.log(Level.WARNING, "", e);
}
return result;
}
/* (non-Javadoc)
* @see com.almende.eve.state.State#keySet()
*/
@Override
public Set keySet() {
final Set result = new HashSet();
Set keys = null;
try {
keys = new HashSet(properties.keySet());
for (final String key : keys) {
result.add(decouchify(key));
}
} catch (final Exception e) {
LOG.log(Level.WARNING, "", e);
}
return result;
}
/* (non-Javadoc)
* @see com.almende.eve.state.State#clear()
*/
@Override
public synchronized void clear() {
try {
final String agentType = properties
.get(couchify(KEY_AGENT_TYPE)).textValue();
properties.clear();
properties.put(couchify(KEY_AGENT_TYPE), JOM.getInstance()
.valueToTree(agentType));
update();
} catch (final Exception e) {
LOG.log(Level.WARNING, "Failed clearing state", e);
}
}
/* (non-Javadoc)
* @see com.almende.eve.state.State#size()
*/
@Override
public int size() {
int result = -1;
try {
result = properties.size();
} catch (final Exception e) {
LOG.log(Level.WARNING, "", e);
}
return result;
}
/* (non-Javadoc)
* @see com.almende.eve.state.AbstractState#get(java.lang.String)
*/
@Override
public JsonNode get(String key) {
key = couchify(key);
JsonNode result = null;
try {
result = properties.get(key);
} catch (final Exception e) {
LOG.log(Level.WARNING, "", e);
}
return result;
}
/**
* Gets the id.
*
* @return the id
*/
@JsonProperty("_id")
public String getId() {
return id;
};
/**
* Sets the id.
*
* @param id the new id
*/
@JsonProperty("_id")
public void setId(final String id) {
this.id = id;
}
/**
* Gets the revision.
*
* @return the revision
*/
@JsonProperty("_rev")
@JsonSerialize(include = Inclusion.NON_NULL)
public String getRevision() {
return revision;
}
/**
* Sets the revision.
*
* @param revision the new revision
*/
@JsonProperty("_rev")
public void setRevision(final String revision) {
this.revision = revision;
}
/* (non-Javadoc)
* @see com.almende.eve.state.AbstractState#getAgentType()
*/
@Override
@JsonIgnore
public synchronized Class> getAgentType() throws ClassNotFoundException {
return super.getAgentType();
}
/* (non-Javadoc)
* @see com.almende.eve.state.AbstractState#setAgentType(java.lang.Class)
*/
@Override
@JsonIgnore
public synchronized void setAgentType(final Class> agentType) {
super.setAgentType(agentType);
}
/**
* Gets the properties.
*
* @return the properties
*/
public Map getProperties() {
return properties;
}
/**
* Sets the properties.
*
* @param properties the properties
*/
public void setProperties(final Map properties) {
this.properties = properties;
}
/**
* Sets the db.
*
* @param db the new db
*/
public void setDb(final CouchDbConnector db) {
this.db = db;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy