source: src/main/java/geniusweb/profilesserver/DefaultProfilesFactory.java@ 7

Last change on this file since 7 was 7, checked in by bart, 5 years ago

Release 1.1.0

File size: 6.4 KB
Line 
1package geniusweb.profilesserver;
2
3import java.util.Collections;
4import java.util.LinkedList;
5import java.util.List;
6import java.util.Map;
7import java.util.Optional;
8import java.util.concurrent.ConcurrentHashMap;
9import java.util.stream.Collectors;
10
11import geniusweb.issuevalue.Domain;
12import geniusweb.profile.Profile;
13import geniusweb.profilesserver.events.ChangeEvent;
14import geniusweb.profilesserver.events.DomainChangeEvent;
15import geniusweb.profilesserver.events.ProfileChangeEvent;
16import tudelft.utilities.listener.DefaultListenable;
17
18/**
19 * Listeners will get a notification call with a {@link ChangeEvent} when a
20 * {@link Domain} or {@link Profile} is changed/removed.
21 * <p>
22 * Warning: If possible create only 1 instance of this to avoid expensive
23 * duplicate bookkeeping. This class could , but is not made a singleton to
24 * facilitate testing.
25 * <p>
26 * This object is mutable: the {@link #available} map is updated with the
27 * current state of available domains and profiles.
28 */
29public class DefaultProfilesFactory extends DefaultListenable<ChangeEvent>
30 implements ProfilesFactory {
31 /**
32 * all currently available profiles and domains. Invariant for this class:
33 * All {@link Domain}s in this map have a unique name that matches the
34 * directory name and file name on the file system below {@link #dir}. All
35 * profile values in the map their {@link Profile#getDomain()} match with
36 * the domain key in the map.
37 */
38 protected final Map<Domain, List<Profile>> available = new ConcurrentHashMap<>();
39
40 @Override
41 public synchronized Domain getDomain(String name) {
42 if (name == null) {
43 throw new IllegalArgumentException("domain = null");
44 }
45 Optional<Domain> optional = available.keySet().stream()
46 .filter(domain -> name.equals(domain.getName())).findFirst();
47 return optional.isPresent() ? optional.get() : null;
48 }
49
50 @Override
51 public synchronized Profile getProfile(String domainprofilename) {
52 if (domainprofilename == null) {
53 throw new IllegalArgumentException("profilename=null");
54 }
55 String[] values = domainprofilename.split("/", 2);
56 if (values.length != 2) {
57 throw new IllegalArgumentException(
58 "profile name must be <domainname>/<profilename> but got "
59 + domainprofilename);
60 }
61 // check if domain exists.
62 Domain domain = getDomain(values[0]);
63 if (domain == null) {
64 return null;
65 }
66 String profilename = values[1];
67 Optional<Profile> profile = available.get(domain).stream()
68 .filter(prof -> profilename.equals(prof.getName())).findFirst();
69 return profile.isPresent() ? profile.get() : null;
70 }
71
72 @Override
73 public synchronized List<Profile> getProfiles(String domainname) {
74 Domain domain = getDomain(domainname);
75 return domain == null ? Collections.EMPTY_LIST
76 : Collections.unmodifiableList(available.get(domain));
77
78 }
79
80 @Override
81 public synchronized List<String> getDomains() {
82 return available.keySet().stream().map(domain -> domain.getName())
83 .collect(Collectors.toList());
84 }
85
86 /**************** support for updating ***************/
87 /**
88 * Add or replace domain. For internal use so little checking of arguments.
89 * If the domain already exists and is the same, we exit immediately. If
90 * such a domain does not yet exist, or a domain with the same name already
91 * exists but that domain is different, the old domain is removed (and all
92 * associated profiles). The new domain is inserted without any known
93 * profiles.
94 *
95 * @param domain the new domain.
96 */
97 protected void add(Domain domain) {
98 synchronized (this) {
99 if (domain == null) {
100 throw new IllegalArgumentException("domain=null");
101 }
102 if (available.containsKey(domain))
103 return;
104 Optional<Domain> existingdom = available.keySet().stream()
105 .filter(dom -> dom.getName().equals(domain.getName()))
106 .findFirst();
107 if (existingdom.isPresent()) {
108 remove(existingdom.get());
109 }
110 available.put(domain, new LinkedList<>());
111 }
112 notifyListeners(new DomainChangeEvent(null, domain));
113 }
114
115 /**
116 * Removes domain from the known domains list, plus all profiles associated
117 * with the domain. For internal use so little checking of arguments.
118 *
119 * @param domain the domain to remove. If null, nothing happens.
120 */
121 protected void remove(Domain domain) {
122 if (domain == null)
123 return;
124
125 List<Profile> removedprofiles;
126 synchronized (this) {
127 removedprofiles = available.get(domain);
128 available.remove(domain);
129 }
130
131 for (Profile prof : removedprofiles) {
132 notifyListeners(new ProfileChangeEvent(prof, null));
133 }
134 notifyListeners(new DomainChangeEvent(domain, null));
135 }
136
137 /**
138 * Adds profile. Internal use only. Domain must exist already. If a profile
139 * with same name already exists, that one is replaced with the given
140 * profile.
141 *
142 * @param profile the profile to add. Ignored if profile=null or if profile
143 * already known. Profile MUST contain a registered domain.
144 */
145 protected void add(Profile profile) {
146 Profile oldprofile = null;
147 synchronized (this) {
148 if (profile == null)
149 return;
150 List<Profile> profiles = available.get(profile.getDomain());
151 if (profiles == null) {
152 throw new IllegalArgumentException("Profile "
153 + profile.getName() + " uses unknown domain "
154 + profile.getDomain());
155 }
156 Optional<Profile> knownprofile = profiles.stream()
157 .filter(prof -> profile.getName().equals(prof.getName()))
158 .findFirst();
159 if (knownprofile.isPresent()) {
160 oldprofile = knownprofile.get();
161 if (profile.equals(oldprofile))
162 return;
163
164 profiles.remove(oldprofile);
165 }
166 profiles.add(profile);
167 }
168 notifyListeners(new ProfileChangeEvent(oldprofile, profile));
169
170 }
171
172 /**
173 * Removes profile. Internal use only.
174 *
175 * @param profile to be removed {@link Profile}
176 */
177 protected void remove(Profile profile) {
178 synchronized (this) {
179 if (profile == null) {
180 throw new IllegalArgumentException("profile=null");
181 }
182 List<Profile> profilelist = available.get(profile.getDomain());
183 if (profilelist == null) {
184 throw new IllegalArgumentException("Profile "
185 + profile.getName() + " uses unknown domain "
186 + profile.getDomain());
187 }
188 profilelist.remove(profile);
189 }
190 notifyListeners(new ProfileChangeEvent(profile, null));
191
192 }
193
194 /**
195 *
196 * @param name the name to check
197 * @return true iff name is simple name. False if not (also if name=null)
198 */
199 protected boolean isSimpleName(String name) {
200 if (name == null)
201 return false;
202 return name.matches("[a-zA-Z0-9]+");
203 }
204
205}
Note: See TracBrowser for help on using the repository browser.