@Override public Object[] getArray(String name) { Serializable object = get(name); if (object == null) { return null; } else if (object instanceof Object[]) { return (Object[]) object; } else { // data migration not done in database, return an array anyway return new Object[] { object }; } }
protected static boolean hasAncestor(State state, String id) { Object[] array = (Object[]) state.get(KEY_ANCESTOR_IDS); return array == null ? false : Arrays.asList(array).contains(id); }
@Override public State readChildState(String parentId, String name, Set<String> ignored) { // TODO optimize by maintaining a parent/child index for (State state : states.values()) { if (ignored.contains(state.get(KEY_ID))) { continue; } if (!parentId.equals(state.get(KEY_PARENT_ID))) { continue; } if (!name.equals(state.get(KEY_NAME))) { continue; } return state; } return null; }
@Override public Object getSingle(String name) { Serializable object = get(name); if (object instanceof Object[]) { Object[] array = (Object[]) object; if (array.length == 0) { return null; } else if (array.length == 1) { // data migration not done in database, return a simple value anyway return array[0]; } else { log.warn("Property " + name + ": expected a simple value but read an array: " + Arrays.toString(array)); return array[0]; } } else { return object; } }
@Override public List<State> queryKeyValue(String key1, Object value1, String key2, Object value2, Set<String> ignored) { if (log.isTraceEnabled()) { log.trace("Mem: QUERY " + key1 + " = " + value1 + " AND " + key2 + " = " + value2); } List<State> list = new ArrayList<>(); for (State state : states.values()) { String id = (String) state.get(KEY_ID); if (ignored.contains(id)) { continue; } if (!(value1.equals(state.get(key1)) && value2.equals(state.get(key2)))) { continue; } list.add(state); } if (log.isTraceEnabled() && !list.isEmpty()) { log.trace("Mem: -> " + list.size()); } return list; }
@Override public synchronized Lock getLock(String id) { State state = states.get(id); if (state == null) { // document not found throw new DocumentNotFoundException(id); } String owner = (String) state.get(KEY_LOCK_OWNER); if (owner == null) { return null; } Calendar created = (Calendar) state.get(KEY_LOCK_CREATED); return new Lock(owner, created); }
@Override public boolean queryKeyValuePresence(String key, String value, Set<String> ignored) { if (log.isTraceEnabled()) { log.trace("Mem: QUERY " + key + " = " + value); } for (State state : states.values()) { String id = (String) state.get(KEY_ID); if (ignored.contains(id)) { continue; } if (value.equals(state.get(key))) { if (log.isTraceEnabled()) { log.trace("Mem: -> present"); } return true; } } if (log.isTraceEnabled()) { log.trace("Mem: -> absent"); } return false; }
@Override public List<State> queryKeyValue(String key, Object value, Set<String> ignored) { if (log.isTraceEnabled()) { log.trace("Mem: QUERY " + key + " = " + value); } List<State> list = new ArrayList<>(); for (State state : states.values()) { String id = (String) state.get(KEY_ID); if (ignored.contains(id)) { continue; } if (!value.equals(state.get(key))) { continue; } list.add(state); } if (log.isTraceEnabled() && !list.isEmpty()) { log.trace("Mem: -> " + list.size()); } return list; }
@Override public void createState(State state) { String id = (String) state.get(KEY_ID); if (log.isTraceEnabled()) { log.trace("Mem: CREATE " + id + ": " + state); } if (states.containsKey(id)) { throw new NuxeoException("Already exists: " + id); } state = StateHelper.deepCopy(state, true); // thread-safe StateHelper.resetDeltas(state); states.put(id, state); }
@Override public State readPartialState(String id, Collection<String> keys) { if (id == null) { return null; } State state = states.get(id); if (state != null) { if (keys != null && !keys.isEmpty()) { State partialState = new State(); for (String key : keys) { Serializable value = state.get(key); if (value != null) { partialState.put(key, value); } } state = partialState; } if (log.isTraceEnabled()) { log.trace("Mem: READ " + id + ": " + state); } } return state; }
protected String getIdFromState(State state) { String idFieldName = getPrefixedIdField(); if (!state.containsKey(idFieldName)) { idFieldName = getIdField(); } return String.valueOf(state.get(idFieldName)); }
protected void markReferencedBinaries(State state, List<String> path, int start, DocumentBlobManager blobManager) { for (int i = start; i < path.size(); i++) { String name = path.get(i); Serializable value = state.get(name); if (value instanceof State) { state = (State) value; } else { if (value instanceof List) { @SuppressWarnings("unchecked") List<Object> list = (List<Object>) value; for (Object v : list) { if (v instanceof State) { markReferencedBinaries((State) v, path, i + 1, blobManager); } else { markReferencedBinary(v, blobManager); } } } state = null; break; } } if (state != null) { Serializable data = state.get(KEY_BLOB_DATA); markReferencedBinary(data, blobManager); } }
@Override public void updateState(String id, StateDiff diff, ChangeTokenUpdater changeTokenUpdater) { if (log.isTraceEnabled()) { log.trace("Mem: UPDATE " + id + ": " + diff); } State state = states.get(id); if (state == null) { throw new ConcurrentUpdateException("Missing: " + id); } synchronized (state) { // synchronization needed for atomic change token if (changeTokenUpdater != null) { for (Entry<String, Serializable> en : changeTokenUpdater.getConditions().entrySet()) { if (!Objects.equals(state.get(en.getKey()), en.getValue())) { throw new ConcurrentUpdateException((String) state.get(KEY_ID)); } } for (Entry<String, Serializable> en : changeTokenUpdater.getUpdates().entrySet()) { applyDiff(state, en.getKey(), en.getValue()); } } applyDiff(state, diff); } }
@Override public synchronized Lock setLock(String id, Lock lock) { State state = states.get(id); if (state == null) { // document not found throw new DocumentNotFoundException(id); } String owner = (String) state.get(KEY_LOCK_OWNER); if (owner != null) { // return old lock Calendar created = (Calendar) state.get(KEY_LOCK_CREATED); return new Lock(owner, created); } state.put(KEY_LOCK_OWNER, lock.getOwner()); state.put(KEY_LOCK_CREATED, lock.getCreated()); return null; }
@Override public synchronized Lock removeLock(String id, String owner) { State state = states.get(id); if (state == null) { // document not found throw new DocumentNotFoundException(id); } String oldOwner = (String) state.get(KEY_LOCK_OWNER); if (oldOwner == null) { // no previous lock return null; } Calendar oldCreated = (Calendar) state.get(KEY_LOCK_CREATED); if (!LockManager.canLockBeRemoved(oldOwner, owner)) { // existing mismatched lock, flag failure return new Lock(oldOwner, oldCreated, true); } // remove lock state.put(KEY_LOCK_OWNER, null); state.put(KEY_LOCK_CREATED, null); // return old lock return new Lock(oldOwner, oldCreated); }
/** * Compares two {@link State}s. */ public static boolean equalsStrict(State a, State b) { if (a == b) { return true; } if (a == null || b == null) { return false; } if (a.size() != b.size()) { return false; } if (!a.keySet().equals(b.keySet())) { return false; } for (Entry<String, Serializable> en : a.entrySet()) { String key = en.getKey(); Serializable va = en.getValue(); Serializable vb = b.get(key); if (!equalsStrict(va, vb)) { return false; } } return true; }
Serializable old = state.get(key); if (old == null) { old = new State(true); // thread-safe state.put(key, applyDiff(state.get(key), (ListDiff) value)); } else if (value instanceof Delta) { Delta delta = (Delta) value; Number oldValue = (Number) state.get(key); Number newValue; if (oldValue == null) {