001: /*
002: * $Id: UndoPageVersionManager.java 461190 2006-06-28 06:35:51Z ehillenius $
003: * $Revision: 461190 $ $Date: 2006-06-28 08:35:51 +0200 (Wed, 28 Jun 2006) $
004: *
005: * ==============================================================================
006: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
007: * use this file except in compliance with the License. You may obtain a copy of
008: * the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015: * License for the specific language governing permissions and limitations under
016: * the License.
017: */
018: package wicket.version.undo;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022:
023: import wicket.Component;
024: import wicket.Page;
025: import wicket.util.collections.ArrayListStack;
026: import wicket.version.IPageVersionManager;
027:
028: /**
029: * A version manager implemented by recording component changes as undo records
030: * which can later be reversed to get back to a given version of the page being
031: * managed.
032: *
033: * @author Jonathan Locke
034: */
035: public class UndoPageVersionManager implements IPageVersionManager {
036: /** log. */
037: private static final Log log = LogFactory
038: .getLog(UndoPageVersionManager.class);
039:
040: private static final long serialVersionUID = 1L;
041:
042: /** The current list of changes */
043: private ChangeList changeList;
044:
045: /** Stack of change lists for undoing */
046: private final ArrayListStack changeListStack = new ArrayListStack();
047:
048: /** The current version number */
049: private int currentVersionNumber = 0;
050:
051: /** Maximum number of most-recent versions to keep */
052: private final int maxVersions;
053:
054: /** The page being managed */
055: private final Page page;
056:
057: /**
058: * Constructor
059: *
060: * @param page
061: * The page that we're tracking changes to
062: * @param maxVersions
063: * The maximum number of versions to maintain before expiring the
064: * old versions
065: */
066: public UndoPageVersionManager(final Page page, final int maxVersions) {
067: this .page = page;
068: this .maxVersions = maxVersions;
069: }
070:
071: /**
072: * @see wicket.version.IPageVersionManager#beginVersion()
073: */
074: public void beginVersion() {
075: // Create new change list
076: changeList = new ChangeList();
077:
078: // We are working on the next version now
079: currentVersionNumber++;
080: }
081:
082: /**
083: * @see wicket.version.IPageVersionManager#componentAdded(wicket.Component)
084: */
085: public void componentAdded(Component component) {
086: changeList.componentAdded(component);
087: }
088:
089: /**
090: * @see wicket.version.IPageVersionManager#componentModelChanging(wicket.Component)
091: */
092: public void componentModelChanging(Component component) {
093: changeList.componentModelChanging(component);
094: }
095:
096: /**
097: * @see wicket.version.IPageVersionManager#componentRemoved(wicket.Component)
098: */
099: public void componentRemoved(Component component) {
100: changeList.componentRemoved(component);
101: }
102:
103: /**
104: * @see wicket.version.IPageVersionManager#componentStateChanging(wicket.version.undo.Change)
105: */
106: public void componentStateChanging(Change change) {
107: changeList.componentStateChanging(change);
108: }
109:
110: /**
111: * @see wicket.version.IPageVersionManager#endVersion()
112: */
113: public void endVersion() {
114: // Push change list onto stack
115: changeListStack.push(changeList);
116:
117: // If stack is overfull, remove oldest entry
118: if (getVersions() > maxVersions) {
119: expireOldestVersion();
120: }
121:
122: // Make memory efficient for replication
123: changeListStack.trimToSize();
124:
125: if (log.isDebugEnabled()) {
126: log.debug("Version " + currentVersionNumber + " for page "
127: + page + " stored");
128: }
129: }
130:
131: /**
132: * Expires an old version
133: */
134: public void expireOldestVersion() {
135: changeListStack.remove(0);
136: }
137:
138: /**
139: * @see wicket.version.IPageVersionManager#getCurrentVersionNumber()
140: */
141: public int getCurrentVersionNumber() {
142: return currentVersionNumber;
143: }
144:
145: /**
146: * @see wicket.version.IPageVersionManager#getVersion(int)
147: */
148: public Page getVersion(final int versionNumber) {
149: // If the requested version is at or before the current version
150: if (versionNumber <= getCurrentVersionNumber()) {
151: // Loop until we reach the right version
152: while (getCurrentVersionNumber() > versionNumber) {
153: // Go back one version
154: if (!undo()) {
155: return null;
156: }
157: }
158:
159: // Return modified page
160: return page;
161: } else {
162: // The version is not available
163: return null;
164: }
165: }
166:
167: /**
168: * @see wicket.version.IPageVersionManager#getVersions()
169: */
170: public int getVersions() {
171: return changeListStack.size();
172: }
173:
174: /**
175: * Goes back a version from the current version
176: *
177: * @return True if the page was successfully reverted to its previous
178: * version
179: */
180: private boolean undo() {
181: if (log.isDebugEnabled()) {
182: log.debug("UNDO: rollback " + page + " to version "
183: + currentVersionNumber);
184: }
185:
186: if (changeListStack.isEmpty()) {
187: return false;
188: }
189:
190: // Pop off top change list
191: final ChangeList changeList = (ChangeList) changeListStack
192: .pop();
193: if (changeList == null) {
194: return false;
195: }
196:
197: // Undo changes made to previous version to get to this version
198: changeList.undo();
199:
200: // One less version around
201: currentVersionNumber--;
202: return true;
203: }
204: }
|