1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 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 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package issuetrackinglite.model; 33 34 import issuetrackinglite.model.Issue.IssueStatus; 35 36 import java.util.Arrays; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.TreeMap; 40 import java.util.concurrent.atomic.AtomicInteger; 41 42 import javafx.beans.property.SimpleObjectProperty; 43 import javafx.beans.property.SimpleStringProperty; 44 import javafx.beans.value.ObservableValue; 45 import javafx.collections.FXCollections; 46 import javafx.collections.MapChangeListener; 47 import javafx.collections.ObservableList; 48 import javafx.collections.ObservableMap; 49 50 public class TrackingServiceStub implements TrackingService { 51 52 // You add a project by adding an entry with an empty observable array list 53 // of issue IDs in the projects Map. 54 final ObservableMap<String, ObservableList<String>> projectsMap; 55 { 56 final Map<String, ObservableList<String>> map = new TreeMap<>(); 57 projectsMap = FXCollections.observableMap(map); 58 for (String s : newList("Project1", "Project2", "Project3", "Project4")) { 59 projectsMap.put(s, FXCollections.<String>observableArrayList()); 60 } 61 } 62 63 // The projectNames list is kept in sync with the project's map by observing 64 // the projectsMap and modifying the projectNames list in consequence. 65 final ObservableList<String> projectNames = FXCollections.<String>observableArrayList(); 66 final MapChangeListener<String, ObservableList<String>> projectsMapChangeListener = change -> { 67 if (change.wasAdded()) projectNames.add(change.getKey()); 68 if (change.wasRemoved()) projectNames.remove(change.getKey()); 69 }; 70 71 { 72 projectNames.addAll(projectsMap.keySet()); 73 projectsMap.addListener(projectsMapChangeListener); 74 } 75 76 // A Issue stub. 77 public final class IssueStub implements ObservableIssue { 78 private final SimpleStringProperty id; 79 private final SimpleStringProperty projectName; 80 private final SimpleStringProperty title; 81 private final SimpleStringProperty description; 82 private final SimpleObjectProperty<IssueStatus> status = 83 new SimpleObjectProperty<>(IssueStatus.NEW); 84 85 IssueStub(String projectName, String id) { 86 this(projectName, id, null); 87 } 88 IssueStub(String projectName, String id, String title) { 89 assert projectNames.contains(projectName); 90 assert ! projectsMap.get(projectName).contains(id); 91 assert ! issuesMap.containsKey(id); 92 this.projectName = new SimpleStringProperty(projectName); 93 this.id = new SimpleStringProperty(id); 94 this.title = new SimpleStringProperty(title); 95 this.description = new SimpleStringProperty(""); 96 } 97 98 @Override 99 public IssueStatus getStatus() { 100 return status.get(); 101 } 102 103 @Override 104 public String getId() { 105 return id.get(); 106 } 107 108 @Override 109 public String getProjectName() { 110 return projectName.get(); 111 } 112 113 @Override 114 public String getSynopsis() { 115 return title.get(); 116 } 117 118 private void setSynopsis(String title) { 119 this.title.set(title); 120 } 121 122 @Override 123 public String getDescription() { 124 return description.get(); 125 } 126 127 private void setDescription(String description) { 128 this.description.set(description); 129 } 130 131 private void setStatus(IssueStatus issueStatus) { 132 this.status.set(issueStatus); 133 } 134 135 @Override 136 public ObservableValue<String> idProperty() { 137 return id; 138 } 139 140 @Override 141 public ObservableValue<String> projectNameProperty() { 142 return projectName; 143 } 144 145 @Override 146 public ObservableValue<IssueStatus> statusProperty() { 147 return status; 148 } 149 150 @Override 151 public ObservableValue<String> synopsisProperty() { 152 return title; 153 } 154 155 @Override 156 public ObservableValue<String> descriptionProperty() { 157 return description; 158 } 159 } 160 161 // You create new issue by adding a IssueStub instance to the issuesMap. 162 // the new id will be automatically added to the corresponding list in 163 // the projectsMap. 164 // 165 final MapChangeListener<String, IssueStub> issuesMapChangeListener = change -> { 166 if (change.wasAdded()) { 167 final IssueStub val1 = change.getValueAdded(); 168 projectsMap.get(val1.getProjectName()).add(val1.getId()); 169 } 170 if (change.wasRemoved()) { 171 final IssueStub val2 = change.getValueRemoved(); 172 projectsMap.get(val2.getProjectName()).remove(val2.getId()); 173 } 174 }; 175 176 final AtomicInteger issueCounter = new AtomicInteger(0); 177 final ObservableMap<String, IssueStub> issuesMap; 178 { 179 final Map<String, IssueStub> map = new TreeMap<>(); 180 issuesMap = FXCollections.observableMap(map); 181 issuesMap.addListener(issuesMapChangeListener); 182 IssueStub ts; 183 ts = createIssueFor("Project1"); 184 ts.setSynopsis("We rode in sorrow, with strong hounds three"); 185 ts.setDescription("From \"The Wanderings Of Oisin\".\nW. B. Yeats."); 186 ts = createIssueFor("Project1"); 187 ts.setSynopsis("Bran, Sgeolan, and Lomair"); 188 ts.setDescription("From \"The Wanderings Of Oisin\".\nW. B. Yeats."); 189 ts = createIssueFor("Project2"); 190 ts.setSynopsis("On a morning misty and mild and fair"); 191 ts.setDescription("From \"The Wanderings Of Oisin\".\nW. B. Yeats."); 192 ts = createIssueFor("Project4"); 193 ts.setSynopsis("The mist-drops hung on the fragrant trees"); 194 ts.setDescription("From \"The Wanderings Of Oisin\".\nW. B. Yeats."); 195 ts = createIssueFor("Project3"); 196 ts.setSynopsis("And in the blossoms hung the bees"); 197 ts.setDescription("From \"The Wanderings Of Oisin\".\nW. B. Yeats."); 198 ts = createIssueFor("Project2"); 199 ts.setSynopsis("We rode in sadness above Lough Lean"); 200 ts.setDescription("From \"The Wanderings Of Oisin\".\nW. B. Yeats."); 201 ts = createIssueFor("Project1"); 202 ts.setSynopsis("For our best were dead on Gavra's green"); 203 ts.setDescription("From \"The Wanderings Of Oisin\".\nW. B. Yeats."); 204 ts = createIssueFor("Project4"); 205 ts.setSynopsis("The Wanderings of Oisin"); 206 ts.setDescription("William Butler Yeats."); 207 } 208 209 @SafeVarargs 210 private static <T> List<T> newList(T... items) { 211 return Arrays.asList(items); 212 } 213 214 215 @Override 216 public IssueStub createIssueFor(String projectName) { 217 assert projectNames.contains(projectName); 218 final IssueStub issue = new IssueStub(projectName, "TT-"+issueCounter.incrementAndGet()); 219 assert issuesMap.containsKey(issue.getId()) == false; 220 assert projectsMap.get(projectName).contains(issue.getId()) == false; 221 issuesMap.put(issue.getId(), issue); 222 return issue; 223 } 224 225 @Override 226 public void deleteIssue(String issueId) { 227 assert issuesMap.containsKey(issueId); 228 issuesMap.remove(issueId); 229 } 230 231 @Override 232 public ObservableList<String> getProjectNames() { 233 return projectNames; 234 } 235 236 @Override 237 public ObservableList<String> getIssueIds(String projectName) { 238 return projectsMap.get(projectName); 239 } 240 241 @Override 242 public IssueStub getIssue(String issueId) { 243 return issuesMap.get(issueId); 244 } 245 246 @Override 247 public void saveIssue(String issueId, IssueStatus status, 248 String synopsis, String description) { 249 IssueStub issue = getIssue(issueId); 250 issue.setDescription(description); 251 issue.setSynopsis(synopsis); 252 issue.setStatus(status); 253 } 254 255 }