001: package fitnesse.components;
002:
003: import java.util.Collection;
004: import java.util.Collections;
005: import java.util.HashMap;
006: import java.util.HashSet;
007: import java.util.Iterator;
008: import java.util.Map;
009: import java.util.Set;
010:
011: import fitnesse.wiki.PageCrawler;
012: import fitnesse.wiki.WikiPage;
013: import fitnesse.wikitext.widgets.TagSuiteWidget;
014: import fitnesse.wikitext.widgets.TagWidget;
015: import fitnesse.wikitext.widgets.WidgetRoot;
016:
017: public class CachingTagManager implements TagManager {
018:
019: private Map tagCache = null;
020:
021: public Set pagesForTags(WikiPage root, String[] tags,
022: boolean anyTags, boolean noTags) throws Exception {
023: if (tagCache == null) {
024: buildTagCache(root);
025: }
026: Set possiblyMatchingPages = findPagesWithMatchingTags(tags,
027: anyTags, noTags);
028: Set matchingPages = removeNonChildren(root,
029: possiblyMatchingPages);
030: return matchingPages;
031: }
032:
033: private Set findPagesWithMatchingTags(String[] tags,
034: boolean anyTags, boolean noTags) throws Exception {
035: if (anyTags && noTags) {
036: return findAllPages();
037: } else if (anyTags) {
038: return findPagesWithAnyTags();
039: } else if (noTags) {
040: return findPagesWIthNoTags();
041: } else {
042: return findPagesWithAllTags(tags);
043: }
044: }
045:
046: private Set findAllPages() {
047: Set possiblyMatchingPages = new HashSet();
048: Collection collection = tagCache.keySet();
049: for (Iterator i = collection.iterator(); i.hasNext();) {
050: String key = (String) i.next();
051: possiblyMatchingPages
052: .addAll((Collection) tagCache.get(key));
053: }
054: return possiblyMatchingPages;
055: }
056:
057: private Set findPagesWIthNoTags() {
058: Set possiblyMatchingPages = new HashSet();
059: possiblyMatchingPages.addAll(((Collection) tagCache
060: .get(TagSuiteWidget.NO_TAGS)));
061: return possiblyMatchingPages;
062: }
063:
064: private Set findPagesWithAnyTags() {
065: Set possiblyMatchingPages = findAllPages();
066: possiblyMatchingPages.removeAll((Collection) tagCache
067: .get(TagSuiteWidget.NO_TAGS));
068: return possiblyMatchingPages;
069: }
070:
071: private Set findPagesWithAllTags(String[] tags) throws Exception {
072: Set possiblyMatchingPages = new HashSet();
073: Collection collection = (Collection) tagCache.get(tags[0]);
074: if (collection == null) {
075: return Collections.emptySet();
076: }
077: possiblyMatchingPages.addAll(collection);
078: for (int tagIndex = 1; tagIndex < tags.length; tagIndex++) {
079: String tag = tags[tagIndex];
080: Set secondTagMatches = (Set) tagCache.get(tag);
081: possiblyMatchingPages.retainAll(secondTagMatches);
082: }
083: return possiblyMatchingPages;
084: }
085:
086: private Set removeNonChildren(WikiPage root,
087: Set possiblyMatchingPages) throws Exception {
088: Set matchingPages = new HashSet();
089: for (Iterator i = possiblyMatchingPages.iterator(); i.hasNext();) {
090: WikiPage page = (WikiPage) i.next();
091: if (pageIsOrContains(root, page)) {
092: matchingPages.add(page);
093: }
094: }
095: return matchingPages;
096: }
097:
098: private boolean pageIsOrContains(WikiPage root, WikiPage child)
099: throws Exception {
100: if (child == root) {
101: return true;
102: }
103: while (child.getParent() != root && child.getParent() != child) {
104: child = child.getParent();
105: }
106: if (child.getParent() == root) {
107: return true;
108: }
109: return false;
110: }
111:
112: private synchronized void buildTagCache(WikiPage root)
113: throws Exception {
114: tagCache = new HashMap();
115: tagCache.put(TagSuiteWidget.NO_TAGS, new HashSet());
116: WikiPage trueRoot = findTrueRoot(root);
117: PageCrawler crawler = root.getPageCrawler();
118: TagCachingListener tagCachingListener = new TagCachingListener();
119: crawler.traverse(trueRoot, tagCachingListener);
120: }
121:
122: private WikiPage findTrueRoot(WikiPage root) throws Exception {
123: WikiPage trueRoot = root;
124: while (trueRoot.getParent() != trueRoot) {
125: trueRoot = trueRoot.getParent();
126: }
127: return trueRoot;
128: }
129:
130: public void recordTagsForPage(WikiPage wikiPage) throws Exception {
131: if (tagCache != null) {
132: removeExistingTagsForPage(wikiPage);
133: if (wikiPage.isSTIQTest()) {
134: String[] tags = findTags(wikiPage);
135: if (tags != null && tags.length > 0) {
136: for (int tagIndex = 0; tagIndex < tags.length; tagIndex++) {
137: String tag = tags[tagIndex];
138: addPageToTag(wikiPage, tag);
139: }
140: } else {
141: addPageToTag(wikiPage, TagSuiteWidget.NO_TAGS);
142: }
143: }
144: }
145: }
146:
147: public void removeExistingTagsForPage(WikiPage wikiPage) {
148: if (tagCache == null) {
149: return;
150: }
151: for (Iterator i = tagCache.values().iterator(); i.hasNext();) {
152: HashSet set = (HashSet) i.next();
153: set.remove(wikiPage);
154: }
155: }
156:
157: private String[] findTags(WikiPage wikiPage) throws Exception {
158: String[] contentLines = wikiPage.getData().getContent().split(
159: "\n");
160: String contentLine = "";
161: for (int i = 0; i < contentLines.length; i++) {
162: contentLine = contentLines[i];
163: if (contentLine.startsWith("!tag")) {
164: TagWidget tagWidget = new TagWidget(new WidgetRoot(
165: wikiPage), contentLine);
166: return tagWidget.getTags();
167: }
168: }
169: return null;
170: }
171:
172: private void addPageToTag(WikiPage wikiPage, String tag) {
173: if (!tagCache.containsKey(tag)) {
174: tagCache.put(tag, new HashSet());
175: }
176: ((Collection) tagCache.get(tag)).add(wikiPage);
177: }
178:
179: class TagCachingListener implements FitNesseTraversalListener {
180:
181: public String getSearchPattern() throws Exception {
182: return null;
183: }
184:
185: public void processPage(WikiPage page) throws Exception {
186: recordTagsForPage(page);
187:
188: }
189:
190: }
191:
192: public void clearIndex() {
193: tagCache = null;
194: }
195: }
|