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 }