/*
* (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Florent Guillaume
*/
package org.nuxeo.ecm.core.storage.dbs;
import static org.nuxeo.ecm.core.storage.dbs.DBSDocument.INITIAL_CHANGE_TOKEN;
import static org.nuxeo.ecm.core.storage.dbs.DBSDocument.KEY_CHANGE_TOKEN;
import static org.nuxeo.ecm.core.storage.dbs.DBSDocument.KEY_ID;
import static org.nuxeo.ecm.core.storage.dbs.DBSDocument.KEY_NAME;
import static org.nuxeo.ecm.core.storage.dbs.DBSDocument.KEY_PARENT_ID;
import static org.nuxeo.ecm.core.storage.dbs.DBSDocument.KEY_PRIMARY_TYPE;
import static org.nuxeo.ecm.core.storage.dbs.DBSDocument.KEY_VERSION_SERIES_ID;
import java.io.Serializable;
import org.nuxeo.ecm.core.model.Document;
import org.nuxeo.ecm.core.storage.State.StateDiff;
import org.nuxeo.ecm.core.storage.StateHelper;
import org.nuxeo.ecm.core.storage.State;
/**
* Implementation of a {@link Document} state for Document-Based Storage.
* <p>
* It wraps a {@link State}, together with a dirty flag.
*
* @since 5.9.4
*/
public class DBSDocumentState {
private static final String UNDEFINED_PARENT_ID = "_undefined_";
/**
* The current state.
*/
protected State state;
/**
* When non-null, the original state (otherwise the state hasn't been modified).
*/
protected State originalState;
private String id;
private String parentId = UNDEFINED_PARENT_ID;
/**
* Constructs an empty state.
*/
public DBSDocumentState() {
state = new State();
originalState = null;
}
/**
* Constructs a document state from the copy of an existing base state.
*/
public DBSDocumentState(State base) {
state = StateHelper.deepCopy(base);
originalState = null;
}
/**
* This must be called if we're about to directly change the internal state.
*/
public void markDirty() {
if (originalState == null) {
originalState = StateHelper.deepCopy(state);
}
}
/**
* Checks if the document state has been changed since its construction or the last call to {@link #setNotDirty}.
*/
public boolean isDirty() {
return originalState != null;
}
public void setNotDirty() {
originalState = null;
StateHelper.resetDeltas(state);
}
/**
* Gets the state. If the caller changes the state, it must also call {@link #dirty} to inform this object that the
* state is dirtied.
*/
public State getState() {
return state;
}
/**
* Gets a diff of what changed since this document state was read from database or saved.
*
* @return {@code null} if there was no change, or a {@link StateDiff}
*/
public StateDiff getStateChange() {
if (originalState == null) {
return null;
}
StateDiff diff = StateHelper.diff(originalState, state);
if (diff.isEmpty()) {
return null;
}
return diff;
}
/**
* Gets the original state for this, needed when creating an undo log.
*
* @return a state that must not be modified
* @since 7.4
*/
public State getOriginalState() {
return originalState == null ? state : originalState;
}
public Serializable get(String key) {
if (KEY_ID.equals(key)) {
return getId();
} else if (KEY_PARENT_ID.equals(key)) {
return getParentId();
}
return state.get(key);
}
public void put(String key, Serializable value) {
markDirty();
if (KEY_ID.equals(key)) {
id = (String) value;
} else if (KEY_PARENT_ID.equals(key)) {
parentId = (String) value;
}
state.put(key, value);
}
public boolean containsKey(String key) {
return state.get(key) != null;
}
public String getId() {
if (id == null) {
id = (String) state.get(KEY_ID);
}
return id;
}
public String getParentId() {
// use a marker because parentId can be null
if (parentId == UNDEFINED_PARENT_ID) {
parentId = (String) state.get(KEY_PARENT_ID);
}
return parentId;
}
public String getName() {
return (String) get(KEY_NAME);
}
public String getPrimaryType() {
return (String) get(KEY_PRIMARY_TYPE);
}
public String getVersionSeriesId() {
return (String) get(KEY_VERSION_SERIES_ID);
}
@Override
public String toString() {
return getClass().getSimpleName() + '(' + (isDirty() ? "dirty," : "") + state.toString() + ')';
}
}