| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| package org.apache.openjpa.util; |
| |
| import java.util.Map; |
| |
| /** |
| * Default {@link MapChangeTracker}. |
| * |
| * @author Abe White |
| */ |
| public class MapChangeTrackerImpl |
| extends AbstractChangeTracker |
| implements MapChangeTracker { |
| |
| private final Map _map; |
| private boolean _keys = true; |
| |
| /** |
| * Constructor; supply delegate map. |
| */ |
| public MapChangeTrackerImpl(Map map, boolean autoOff) { |
| _map = map; |
| this.setAutoOff(autoOff); |
| } |
| |
| @Override |
| public boolean getTrackKeys() { |
| return _keys; |
| } |
| |
| @Override |
| public void setTrackKeys(boolean keys) { |
| _keys = keys; |
| } |
| |
| @Override |
| public void added(Object key, Object val) { |
| if (_keys) |
| super.added(key); |
| else |
| super.added(val); |
| } |
| |
| @Override |
| public void removed(Object key, Object val) { |
| if (_keys) |
| super.removed(key); |
| else |
| super.removed(val); |
| } |
| |
| @Override |
| public void changed(Object key, Object oldVal, Object newVal) { |
| if (_keys) |
| super.changed(key); |
| else { |
| super.removed(oldVal); |
| super.added(newVal); |
| } |
| } |
| |
| @Override |
| protected void add(Object obj) { |
| // if the key was previously removed and now added back, mark |
| // it as a change; otherwise it's a new addition |
| if (rem != null && rem.remove(obj)) { |
| if (change == null) |
| change = newSet(); |
| change.add(obj); |
| } else { |
| // after a point it becomes inefficient to track changes |
| if (getAutoOff() && getAdded().size() + getChanged().size() |
| + getRemoved().size() >= _map.size()) |
| stopTracking(); |
| else { |
| if (add == null) |
| add = newSet(); |
| add.add(obj); |
| } |
| } |
| } |
| |
| @Override |
| protected void remove(Object obj) { |
| // no longer a change, if it was before |
| if (change != null) |
| change.remove(obj); |
| |
| // if it was a new addition, just forget it; otherwise remember |
| // that it was removed |
| if (add == null || !add.remove(obj)) { |
| // after a point it becomes inefficient to track changes |
| if (getAutoOff() && getAdded().size() + getChanged().size() |
| + getRemoved().size() >= _map.size()) |
| stopTracking(); |
| else { |
| if (rem == null) |
| rem = newSet(); |
| rem.add(obj); |
| } |
| } |
| } |
| |
| @Override |
| protected void change(Object key) { |
| // if the key is already changed or the key is newly added, nothing |
| // to do |
| if ((change != null && change.contains(key)) |
| || (add != null && add.contains(key))) |
| return; |
| |
| // after a point it becomes inefficient to track changes |
| if (getAutoOff() && getAdded().size() + getChanged().size() |
| + getRemoved().size() >= _map.size()) |
| stopTracking(); |
| else { |
| // record the change |
| if (change == null) |
| change = newSet(); |
| change.add(key); |
| } |
| } |
| } |