001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.schematic.internal.document;
017
018import java.util.Map;
019import org.modeshape.schematic.document.Document;
020import org.modeshape.schematic.document.EditableArray;
021import org.modeshape.schematic.document.EditableDocument;
022import org.modeshape.schematic.document.Path;
023import org.modeshape.schematic.internal.delta.DocumentObserver;
024import org.modeshape.schematic.internal.delta.PutIfAbsentOperation;
025import org.modeshape.schematic.internal.delta.PutOperation;
026import org.modeshape.schematic.internal.delta.RemoveOperation;
027
028public class ObservableDocumentEditor extends DocumentEditor {
029
030    private static final long serialVersionUID = 1L;
031
032    private transient final Path path;
033    private transient final DocumentObserver observer;
034
035    public ObservableDocumentEditor( MutableDocument document,
036                                     Path path,
037                                     DocumentObserver observer,
038                                     DocumentValueFactory factory ) {
039        super(document, factory);
040        this.path = path;
041        this.observer = observer;
042    }
043
044    @Override
045    protected Object doSetValue( String name,
046                                 Object newValue ) {
047        Object oldValue = super.doSetValue(name, newValue);
048        observer.addOperation(new PutOperation(path, name, copy(oldValue), copy(newValue)));
049        return oldValue;
050    }
051
052    @Override
053    protected Object doSetValueIfAbsent( String name,
054                                         Object value ) {
055        Object oldValue = super.doSetValue(name, value);
056        observer.addOperation(new PutIfAbsentOperation(path, name, copy(value)));
057        return oldValue;
058    }
059
060    @Override
061    protected void doSetAllValues( Document values ) {
062        if (values != null && !values.isEmpty()) {
063            for (Field field : values.fields()) {
064                doSetValue(field.getName(), field.getValue());
065            }
066        }
067    }
068
069    @Override
070    protected void doSetAllValues( Map<? extends String, ?> values ) {
071        if (values != null && !values.isEmpty()) {
072            for (Map.Entry<? extends String, ?> entry : values.entrySet()) {
073                doSetValue(entry.getKey(), entry.getValue());
074            }
075        }
076    }
077
078    @Override
079    public Object remove( String name ) {
080        Object oldValue = super.remove(name);
081        observer.addOperation(new RemoveOperation(path, name, copy(oldValue)));
082        return oldValue;
083    }
084
085    protected Object copy( Object value ) {
086        if (value instanceof MutableArray) return ((MutableArray)value).clone();
087        if (value instanceof MutableDocument) return ((MutableDocument)value).clone();
088        return value;
089    }
090
091    @Override
092    public void removeAll() {
093        super.removeAll();
094        observer.addOperation(new PutOperation(path.parent(), path.getLast(), copy(unwrap()), new BasicDocument()));
095    }
096
097    @Override
098    protected EditableDocument createEditableDocument( MutableDocument document,
099                                                       String fieldName,
100                                                       DocumentValueFactory factory ) {
101        return new ObservableDocumentEditor(document, path.with(fieldName), observer, factory);
102    }
103
104    @Override
105    protected EditableArray createEditableArray( MutableArray array,
106                                                 String fieldName,
107                                                 DocumentValueFactory factory ) {
108        return new ObservableArrayEditor(array, path.with(fieldName), observer, factory);
109    }
110
111}