2 * Copyright (C) 2001-2006 The Mir-coders group
4 * This file is part of Mir.
6 * Mir is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Mir is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Mir; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * In addition, as a special exception, The Mir-coders gives permission to link
21 * the code of this program with any library licensed under the Apache Software License,
22 * and distribute linked combinations including the two. You must obey the
23 * GNU General Public License in all respects for all of the code used other than
24 * the above mentioned libraries. If you modify this file, you may extend this
25 * exception to your version of the file, but you are not obligated to do so.
26 * If you do not wish to do so, delete this exception statement from your version.
29 package mir.changetracker;
31 import java.util.ArrayList;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.Date;
38 import java.util.Calendar;
41 * Change tracker, tracks changes to a path based repository.
42 * All methods are thread-safe
45 public class ChangeTracker {
46 private final List changes = new ArrayList();
47 private Calendar calendar = Calendar.getInstance();
49 // to prevent memory issues with the number of recorded changes,
50 // we'll adhere to this maximum
51 private static final int MAX_CHANGES = 10000;
54 * Add a single change. A change is represented by the full path
55 * of the file involved.
57 public void addChange(String aPath, ChangeType aChangeType) {
58 synchronized (changes) {
59 changes.add(new Change(aPath, aChangeType, calendar.getTime()));
64 * Add an array of changes. Each change is represented by the full path
65 * of the file involved.
67 public void addChanges(String[] aPaths, ChangeType aChangeType) {
68 addChanges(Arrays.asList(aPaths), aChangeType);
72 * Adds a <code>Collection</code> of changes. Each change is represented by the
73 * full path of the file involved.
75 public void addChanges(Collection aChanges, ChangeType aChangeType) {
76 synchronized (changes) {
77 Iterator i = aChanges.iterator();
79 addChange((String) i.next(), aChangeType);
85 private ChangeType type;
89 Change(String anAbsolutePath, ChangeType aType, Date aDate) {
91 path = anAbsolutePath;
95 public String getPath() {
99 public ChangeType getType() {
103 public Date getDate() {
110 * Returns a <code>Collection</code> of {@link Change}s within a base
111 * path, and removes them from the tracker.
113 public Collection flushChanges(String aBasePath) {
114 return flushChanges(aBasePath, Collections.EMPTY_LIST);
118 * Returns a <code>Collection</code> of {@link Change}s within a base
119 * path, exluding a list of excluded paths, and removes them from
122 public Collection flushChanges(String aBasePath, Collection anExcludedPaths) {
123 synchronized (changes) {
124 Collection result = getChanges(aBasePath, anExcludedPaths);
126 removeChanges(result);
133 * Remove specific changes from the change tracker.
135 * @param someChanges a <code>Collection</code> of changes represented by
136 * their full path in the form of a <code>String</code>
138 void removeChanges(Collection someChanges) {
139 synchronized (changes) {
140 changes.removeAll(someChanges);
145 * Returns all changes within a base path
147 List getChanges(String aBasePath) {
148 synchronized (changes) {
149 List result = new ArrayList();
151 Iterator i = changes.iterator();
152 while (i.hasNext()) {
153 Change change = (Change) i.next();
154 if (change.getPath().startsWith(aBasePath)) {
164 * Gets all changes within a base path, but excluding some other paths
167 * @param anExcludedPaths a collection of paths to exclude. may be <code>null</code>
168 * to not exclude anything
170 Collection getChanges(String aBasePath, Collection anExcludedPaths) {
171 synchronized (changes) {
172 List result = getChanges(aBasePath);
174 if (anExcludedPaths != null) {
175 Iterator i = anExcludedPaths.iterator();
176 while (i.hasNext()) {
177 String excludedPath = (String) i.next();
178 List remove = new ArrayList();
179 Iterator j = result.iterator();
180 while (j.hasNext()) {
181 Change change = (Change) j.next();
182 if (change.getPath().startsWith(excludedPath)) {
186 result.removeAll(remove);
190 if (changes.size()>MAX_CHANGES) {