1 /* ====================================================================
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 2000 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
53 *
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
57 */
58 package com.bonevich.eclipse.cvsgrapher.model;
59
60 import org.apache.commons.logging.Log;
61 import org.apache.commons.logging.LogFactory;
62 import org.eclipse.core.runtime.IAdaptable;
63 import org.eclipse.team.internal.ccvs.core.CVSTag;
64 import org.eclipse.team.internal.ccvs.core.ILogEntry;
65 import org.eclipse.team.internal.ccvs.ui.VersionCollator;
66
67 import com.bonevich.eclipse.cvsgrapher.CvsGraphPlugin;
68
69 import java.util.*;
70 import java.util.regex.Matcher;
71 import java.util.regex.Pattern;
72
73 /***
74 * The CVS Graph root, representing the reosurce being displayed.
75 *
76 * @author jbonevic
77 */
78 public final class CvsGraphModel
79 {
80 private static final Log _logger = LogFactory.getLog(CvsGraphModel.class);
81
82 private static final String MAIN_BRANCH = "MAIN";
83
84 private final List _entries; //elements: ILogEntry
85
86 private CvsGraphBranchModel _rootBranch;
87 private List _nodes = new ArrayList(); //elements: ICvsGraphEntryModel
88 private Map _sourceTagMap = new HashMap(); //elements: tag => CvsGraphNodeModel
89 private Map _mergeTagMap = new HashMap(); //elements: tag => CvsGraphNodeModel
90
91 public CvsGraphModel(ILogEntry[] entries)
92 {
93 _entries = Arrays.asList(entries);
94 Collections.sort(_entries, new LogEntrySorter());
95 init();
96 }
97
98 private void init()
99 {
100 ListIterator entries = _entries.listIterator();
101 _rootBranch = createBranch("1", MAIN_BRANCH);
102 addEntry(_rootBranch, _rootBranch, entries);
103
104 createMergeConnections();
105 }
106
107 private void createMergeConnections()
108 {
109 Iterator sourceTags = _sourceTagMap.keySet().iterator();
110 while (sourceTags.hasNext())
111 {
112 String sourceTag = (String) sourceTags.next();
113 CvsGraphVersionModel sourceNode = (CvsGraphVersionModel) _sourceTagMap.get(sourceTag);
114 CvsGraphVersionModel mergeNode = (CvsGraphVersionModel) _mergeTagMap.get(sourceTag);
115 if (sourceNode != null && mergeNode != null && sourceNode != mergeNode)
116 {
117 createConnection(sourceNode, mergeNode, true);
118 }
119 }
120 }
121
122 private void addEntry(ICvsGraphNodeModel previous, CvsGraphBranchModel currentBranch, ListIterator entries)
123 {
124 if (_logger.isDebugEnabled())
125 {
126 _logger.debug("adding entry = " + previous.getVersion());
127 }
128
129 if (!entries.hasNext())
130 {
131 return;
132 }
133 ILogEntry entry = (ILogEntry) entries.next();
134 if (isBranchTerminus(currentBranch, entry))
135 {
136 entries.previous();
137 return;
138 }
139 previous = createVersion(previous, entry);
140 List branchTags = processTags(entry, previous);
141 if (branchTags != null)
142 {
143 int versionSuffix = 0;
144 Iterator tags = branchTags.iterator();
145 while (tags.hasNext())
146 {
147 versionSuffix += 2;
148 String version = previous.getVersion() + "." + versionSuffix;
149 addBranch(previous, entries, (String) tags.next(), version);
150 }
151 }
152 addEntry(previous, currentBranch, entries);
153 }
154
155 private void addBranch(ICvsGraphNodeModel previous, ListIterator entries, String tag, String version)
156 {
157 CvsGraphBranchModel branch = createBranch(version, tag);
158 previous.addChildNode(branch);
159 branch.setParent(previous);
160
161 if (_logger.isDebugEnabled())
162 {
163 _logger.debug("adding branch = " + branch.getVersion());
164 }
165
166 createConnection(previous, branch);
167 addEntry(branch, branch, entries);
168 }
169
170 private CvsGraphBranchModel createBranch(String version, String tag)
171 {
172 CvsGraphBranchModel branch = new CvsGraphBranchModel(version, tag);
173 _nodes.add(branch);
174 return branch;
175 }
176
177 private List processTags(ILogEntry entry, ICvsGraphNodeModel node)
178 {
179 List branchTags = null;
180 CVSTag[] tags = entry.getTags();
181 if (tags.length > 0)
182 {
183 branchTags = new ArrayList(tags.length);
184 for (int j = 0; j < tags.length; j++)
185 {
186 String tag = tags[j].getName();
187 if (tags[j].getType() == CVSTag.BRANCH)
188 {
189 // add in reverse order - earliest to most recent tag
190 branchTags.add(0, tag);
191 }
192 else
193 {
194 extractMergeTag(tag, node);
195 }
196 }
197 }
198 return branchTags;
199 }
200
201 private void extractMergeTag(String tag, ICvsGraphNodeModel node)
202 {
203 Pattern source = CvsGraphPlugin.getPlugin().getMergeTagSourcePreference();
204 if (! extractMergeTag(tag, node, source, _sourceTagMap))
205 {
206 Pattern dest = CvsGraphPlugin.getPlugin().getMergeTagDestPreference();
207 extractMergeTag(tag, node, dest, _mergeTagMap);
208 }
209 }
210
211 private boolean extractMergeTag(String tag, ICvsGraphNodeModel node, Pattern pattern, Map tagMap)
212 {
213 Matcher matcher = pattern.matcher(tag);
214 if (matcher.find())
215 {
216 tagMap.put(tag.substring(matcher.start(1), matcher.end(1)), node);
217 return true;
218 }
219 return false;
220 }
221
222 private CvsGraphVersionModel createVersion(ICvsGraphNodeModel previous, ILogEntry entry)
223 {
224 CvsGraphVersionModel node = new CvsGraphVersionModel(entry);
225 _nodes.add(node);
226 previous.addChildNode(node);
227 node.setParent(previous);
228
229 if (_logger.isDebugEnabled())
230 {
231 _logger.debug("new node = " + node.getVersion());
232 }
233 createConnection(previous, node);
234
235 if (_logger.isDebugEnabled())
236 {
237 _logger.debug("connected to previous = " + previous.getVersion());
238 }
239 return node;
240 }
241
242 private void createConnection(ICvsGraphNodeModel previous, ICvsGraphNodeModel node)
243 {
244 createConnection(previous, node, false);
245 }
246
247 private void createConnection(ICvsGraphNodeModel src, ICvsGraphNodeModel dest, boolean isMerge)
248 {
249 // if (isMerge) create different connection model
250 CvsGraphConnectionModel connection = new CvsGraphConnectionModel(isMerge);
251
252 connection.setSource(src);
253 connection.setTarget(dest);
254
255 src.addSourceConnection(connection);
256 dest.addTargetConnection(connection);
257 }
258
259 private boolean isBranchTerminus(CvsGraphBranchModel currentBranch, ILogEntry next)
260 {
261 String branchVersionPrefix = currentBranch.getVersion() + ".";
262 String nextVersion = next.getRevision();
263 return (! nextVersion.startsWith(branchVersionPrefix));
264 }
265
266 public List getNodes()
267 {
268 return _nodes;
269 }
270
271 public CvsGraphBranchModel getRootBranch()
272 {
273 return _rootBranch;
274 }
275
276 protected ILogEntry adaptToLogEntry(Object element)
277 {
278 // Get the log entry for the provided object
279 ILogEntry entry = null;
280 if (element instanceof ILogEntry)
281 {
282 entry = (ILogEntry) element;
283 }
284 else if (element instanceof IAdaptable)
285 {
286 entry = (ILogEntry) ((IAdaptable) element).getAdapter(ILogEntry.class);
287 }
288 return entry;
289 }
290
291 final class LogEntrySorter implements Comparator
292 {
293 private VersionCollator versionCollator = new VersionCollator();
294
295 /***
296 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
297 */
298 public int compare(Object arg0, Object arg1)
299 {
300 ILogEntry e1 = adaptToLogEntry(arg0);
301 ILogEntry e2 = adaptToLogEntry(arg1);
302
303 return versionCollator.compare(e1.getRevision(), e2.getRevision());
304 }
305 }
306
307 }
This page was automatically generated by Maven