Move test builders to their own top-level classes.
[Sone.git] / src / test / java / net / pterodactylus / sone / core / ConfigurationSoneParserTest.java
1 package net.pterodactylus.sone.core;
2
3 import static com.google.common.base.Optional.of;
4 import static net.pterodactylus.sone.Matchers.isAlbum;
5 import static net.pterodactylus.sone.Matchers.isImage;
6 import static net.pterodactylus.sone.Matchers.isPost;
7 import static net.pterodactylus.sone.Matchers.isPostReply;
8 import static org.hamcrest.MatcherAssert.assertThat;
9 import static org.hamcrest.Matchers.contains;
10 import static org.hamcrest.Matchers.containsInAnyOrder;
11 import static org.hamcrest.Matchers.emptyIterable;
12 import static org.hamcrest.Matchers.hasSize;
13 import static org.hamcrest.Matchers.is;
14 import static org.hamcrest.Matchers.notNullValue;
15 import static org.hamcrest.Matchers.nullValue;
16 import static org.mockito.Matchers.anyString;
17 import static org.mockito.Matchers.eq;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.when;
20
21 import java.util.Collection;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.concurrent.atomic.AtomicReference;
26
27 import net.pterodactylus.sone.TestAlbumBuilder;
28 import net.pterodactylus.sone.TestImageBuilder;
29 import net.pterodactylus.sone.TestPostBuilder;
30 import net.pterodactylus.sone.TestPostReplyBuilder;
31 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidAlbumFound;
32 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidImageFound;
33 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound;
34 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound;
35 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound;
36 import net.pterodactylus.sone.data.Album;
37 import net.pterodactylus.sone.data.Post;
38 import net.pterodactylus.sone.data.PostReply;
39 import net.pterodactylus.sone.data.Profile;
40 import net.pterodactylus.sone.data.Profile.Field;
41 import net.pterodactylus.sone.data.Sone;
42 import net.pterodactylus.sone.database.AlbumBuilder;
43 import net.pterodactylus.sone.database.AlbumBuilderFactory;
44 import net.pterodactylus.sone.database.ImageBuilder;
45 import net.pterodactylus.sone.database.ImageBuilderFactory;
46 import net.pterodactylus.sone.database.PostBuilder;
47 import net.pterodactylus.sone.database.PostBuilderFactory;
48 import net.pterodactylus.sone.database.PostReplyBuilder;
49 import net.pterodactylus.sone.database.PostReplyBuilderFactory;
50 import net.pterodactylus.util.config.Configuration;
51 import net.pterodactylus.util.config.ConfigurationException;
52 import net.pterodactylus.util.config.Value;
53
54 import com.google.common.base.Optional;
55 import org.hamcrest.Matchers;
56 import org.junit.Test;
57 import org.mockito.invocation.InvocationOnMock;
58 import org.mockito.stubbing.Answer;
59
60 /**
61  * Unit test for {@link ConfigurationSoneParser}.
62  *
63  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
64  */
65 public class ConfigurationSoneParserTest {
66
67         private final Configuration configuration = mock(Configuration.class);
68         private final Sone sone = mock(Sone.class);
69         private final ConfigurationSoneParser configurationSoneParser;
70
71         public ConfigurationSoneParserTest() {
72                 when(sone.getId()).thenReturn("1");
73                 configurationSoneParser =
74                                 new ConfigurationSoneParser(configuration, sone);
75         }
76
77         @Test
78         public void emptyProfileIsLoadedCorrectly() {
79                 setupEmptyProfile();
80                 Profile profile = configurationSoneParser.parseProfile();
81                 assertThat(profile, notNullValue());
82                 assertThat(profile.getFirstName(), nullValue());
83                 assertThat(profile.getMiddleName(), nullValue());
84                 assertThat(profile.getLastName(), nullValue());
85                 assertThat(profile.getBirthDay(), nullValue());
86                 assertThat(profile.getBirthMonth(), nullValue());
87                 assertThat(profile.getBirthYear(), nullValue());
88                 assertThat(profile.getFields(), emptyIterable());
89         }
90
91         private void setupEmptyProfile() {
92                 when(configuration.getStringValue(anyString())).thenReturn(
93                                 new TestValue<String>(null));
94                 when(configuration.getIntValue(anyString())).thenReturn(
95                                 new TestValue<Integer>(null));
96         }
97
98         @Test
99         public void filledProfileWithFieldsIsParsedCorrectly() {
100                 setupFilledProfile();
101                 Profile profile = configurationSoneParser.parseProfile();
102                 assertThat(profile, notNullValue());
103                 assertThat(profile.getFirstName(), is("First"));
104                 assertThat(profile.getMiddleName(), is("M."));
105                 assertThat(profile.getLastName(), is("Last"));
106                 assertThat(profile.getBirthDay(), is(18));
107                 assertThat(profile.getBirthMonth(), is(12));
108                 assertThat(profile.getBirthYear(), is(1976));
109                 final List<Field> fields = profile.getFields();
110                 assertThat(fields, hasSize(2));
111                 assertThat(fields.get(0).getName(), is("Field1"));
112                 assertThat(fields.get(0).getValue(), is("Value1"));
113                 assertThat(fields.get(1).getName(), is("Field2"));
114                 assertThat(fields.get(1).getValue(), is("Value2"));
115         }
116
117         private void setupFilledProfile() {
118                 setupString("Sone/1/Profile/FirstName", "First");
119                 setupString("Sone/1/Profile/MiddleName", "M.");
120                 setupString("Sone/1/Profile/LastName", "Last");
121                 setupInteger("Sone/1/Profile/BirthDay", 18);
122                 setupInteger("Sone/1/Profile/BirthMonth", 12);
123                 setupInteger("Sone/1/Profile/BirthYear", 1976);
124                 setupString("Sone/1/Profile/Fields/0/Name", "Field1");
125                 setupString("Sone/1/Profile/Fields/0/Value", "Value1");
126                 setupString("Sone/1/Profile/Fields/1/Name", "Field2");
127                 setupString("Sone/1/Profile/Fields/1/Value", "Value2");
128                 setupString("Sone/1/Profile/Fields/2/Name", null);
129         }
130
131         private void setupString(String nodeName, String value) {
132                 when(configuration.getStringValue(eq(nodeName))).thenReturn(
133                                 new TestValue<String>(value));
134         }
135
136         private void setupInteger(String nodeName, Integer value) {
137                 when(configuration.getIntValue(eq(nodeName))).thenReturn(
138                                 new TestValue<Integer>(value));
139         }
140
141         @Test
142         public void postsAreParsedCorrectly() {
143                 setupCompletePosts();
144                 PostBuilderFactory postBuilderFactory = createPostBuilderFactory();
145                 Collection<Post> posts =
146                                 configurationSoneParser.parsePosts(postBuilderFactory);
147                 assertThat(posts,
148                                 Matchers.<Post>containsInAnyOrder(
149                                                 isPost("P0", 1000L, "T0", Optional.<String>absent()),
150                                                 isPost("P1", 1001L, "T1",
151                                                                 of("1234567890123456789012345678901234567890123"))));
152         }
153
154         private PostBuilderFactory createPostBuilderFactory() {
155                 PostBuilderFactory postBuilderFactory =
156                                 mock(PostBuilderFactory.class);
157                 when(postBuilderFactory.newPostBuilder()).thenAnswer(
158                                 new Answer<PostBuilder>() {
159                                         @Override
160                                         public PostBuilder answer(InvocationOnMock invocation)
161                                         throws Throwable {
162                                                 return new TestPostBuilder();
163                                         }
164                                 });
165                 return postBuilderFactory;
166         }
167
168         private void setupCompletePosts() {
169                 setupPost("0", "P0", 1000L, "T0", null);
170                 setupPost("1", "P1", 1001L, "T1",
171                                 "1234567890123456789012345678901234567890123");
172                 setupPost("2", null, 0L, null, null);
173         }
174
175         private void setupPost(String postNumber, String postId, long time,
176                         String text, String recipientId) {
177                 setupString("Sone/1/Posts/" + postNumber + "/ID", postId);
178                 setupLong("Sone/1/Posts/" + postNumber + "/Time", time);
179                 setupString("Sone/1/Posts/" + postNumber + "/Text", text);
180                 setupString("Sone/1/Posts/" + postNumber + "/Recipient", recipientId);
181         }
182
183         private void setupLong(String nodeName, Long value) {
184                 when(configuration.getLongValue(eq(nodeName))).thenReturn(
185                                 new TestValue<Long>(value));
186         }
187
188         @Test(expected = InvalidPostFound.class)
189         public void postWithoutTimeIsRecognized() {
190                 setupPostWithoutTime();
191                 configurationSoneParser.parsePosts(createPostBuilderFactory());
192         }
193
194         private void setupPostWithoutTime() {
195                 setupPost("0", "P0", 0L, "T0", null);
196         }
197
198         @Test(expected = InvalidPostFound.class)
199         public void postWithoutTextIsRecognized() {
200                 setupPostWithoutText();
201                 configurationSoneParser.parsePosts(createPostBuilderFactory());
202         }
203
204         private void setupPostWithoutText() {
205                 setupPost("0", "P0", 1000L, null, null);
206         }
207
208         @Test
209         public void postWithInvalidRecipientIdIsRecognized() {
210                 setupPostWithInvalidRecipientId();
211                 Collection<Post> posts = configurationSoneParser.parsePosts(
212                                 createPostBuilderFactory());
213                 assertThat(posts, contains(
214                                 isPost("P0", 1000L, "T0", Optional.<String>absent())));
215         }
216
217         private void setupPostWithInvalidRecipientId() {
218                 setupPost("0", "P0", 1000L, "T0", "123");
219                 setupPost("1", null, 0L, null, null);
220         }
221
222         @Test
223         public void postRepliesAreParsedCorrectly() {
224                 setupPostReplies();
225                 PostReplyBuilderFactory postReplyBuilderFactory =
226                                 new PostReplyBuilderFactory() {
227                                         @Override
228                                         public PostReplyBuilder newPostReplyBuilder() {
229                                                 return new TestPostReplyBuilder();
230                                         }
231                                 };
232                 Collection<PostReply> postReplies =
233                                 configurationSoneParser.parsePostReplies(
234                                                 postReplyBuilderFactory);
235                 assertThat(postReplies, hasSize(2));
236                 assertThat(postReplies,
237                                 containsInAnyOrder(isPostReply("R0", "P0", 1000L, "T0"),
238                                                 isPostReply("R1", "P1", 1001L, "T1")));
239         }
240
241         private void setupPostReplies() {
242                 setupPostReply("0", "R0", "P0", 1000L, "T0");
243                 setupPostReply("1", "R1", "P1", 1001L, "T1");
244                 setupPostReply("2", null, null, 0L, null);
245         }
246
247         private void setupPostReply(String postReplyNumber, String postReplyId,
248                         String postId, long time, String text) {
249                 setupString("Sone/1/Replies/" + postReplyNumber + "/ID", postReplyId);
250                 setupString("Sone/1/Replies/" + postReplyNumber + "/Post/ID", postId);
251                 setupLong("Sone/1/Replies/" + postReplyNumber + "/Time", time);
252                 setupString("Sone/1/Replies/" + postReplyNumber + "/Text", text);
253         }
254
255         @Test(expected = InvalidPostReplyFound.class)
256         public void missingPostIdIsRecognized() {
257                 setupPostReplyWithMissingPostId();
258                 configurationSoneParser.parsePostReplies(null);
259         }
260
261         private void setupPostReplyWithMissingPostId() {
262                 setupPostReply("0", "R0", null, 1000L, "T0");
263         }
264
265         @Test(expected = InvalidPostReplyFound.class)
266         public void missingPostReplyTimeIsRecognized() {
267                 setupPostReplyWithMissingPostReplyTime();
268                 configurationSoneParser.parsePostReplies(null);
269         }
270
271         private void setupPostReplyWithMissingPostReplyTime() {
272                 setupPostReply("0", "R0", "P0", 0L, "T0");
273         }
274
275         @Test(expected = InvalidPostReplyFound.class)
276         public void missingPostReplyTextIsRecognized() {
277                 setupPostReplyWithMissingPostReplyText();
278                 configurationSoneParser.parsePostReplies(null);
279         }
280
281         private void setupPostReplyWithMissingPostReplyText() {
282                 setupPostReply("0", "R0", "P0", 1000L, null);
283         }
284
285         @Test
286         public void likedPostIdsParsedCorrectly() {
287                 setupLikedPostIds();
288                 Set<String> likedPostIds =
289                                 configurationSoneParser.parseLikedPostIds();
290                 assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3"));
291         }
292
293         private void setupLikedPostIds() {
294                 setupString("Sone/1/Likes/Post/0/ID", "P1");
295                 setupString("Sone/1/Likes/Post/1/ID", "P2");
296                 setupString("Sone/1/Likes/Post/2/ID", "P3");
297                 setupString("Sone/1/Likes/Post/3/ID", null);
298         }
299
300         @Test
301         public void likedPostReplyIdsAreParsedCorrectly() {
302                 setupLikedPostReplyIds();
303                 Set<String> likedPostReplyIds =
304                                 configurationSoneParser.parseLikedPostReplyIds();
305                 assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3"));
306         }
307
308         private void setupLikedPostReplyIds() {
309                 setupString("Sone/1/Likes/Reply/0/ID", "R1");
310                 setupString("Sone/1/Likes/Reply/1/ID", "R2");
311                 setupString("Sone/1/Likes/Reply/2/ID", "R3");
312                 setupString("Sone/1/Likes/Reply/3/ID", null);
313         }
314
315         @Test
316         public void friendsAreParsedCorrectly() {
317                 setupFriends();
318                 Set<String> friends = configurationSoneParser.parseFriends();
319                 assertThat(friends, containsInAnyOrder("F1", "F2", "F3"));
320         }
321
322         private void setupFriends() {
323                 setupString("Sone/1/Friends/0/ID", "F1");
324                 setupString("Sone/1/Friends/1/ID", "F2");
325                 setupString("Sone/1/Friends/2/ID", "F3");
326                 setupString("Sone/1/Friends/3/ID", null);
327         }
328
329         @Test
330         public void topLevelAlbumsAreParsedCorrectly() {
331                 setupTopLevelAlbums();
332                 AlbumBuilderFactory albumBuilderFactory = createAlbumBuilderFactory();
333                 List<Album> topLevelAlbums =
334                                 configurationSoneParser.parseTopLevelAlbums(
335                                                 albumBuilderFactory);
336                 assertThat(topLevelAlbums, hasSize(2));
337                 Album firstAlbum = topLevelAlbums.get(0);
338                 assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1", "I1"));
339                 assertThat(firstAlbum.getAlbums(), emptyIterable());
340                 assertThat(firstAlbum.getImages(), emptyIterable());
341                 Album secondAlbum = topLevelAlbums.get(1);
342                 assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2", null));
343                 assertThat(secondAlbum.getAlbums(), hasSize(1));
344                 assertThat(secondAlbum.getImages(), emptyIterable());
345                 Album thirdAlbum = secondAlbum.getAlbums().get(0);
346                 assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3", "I3"));
347                 assertThat(thirdAlbum.getAlbums(), emptyIterable());
348                 assertThat(thirdAlbum.getImages(), emptyIterable());
349         }
350
351         private void setupTopLevelAlbums() {
352                 setupAlbum(0, "A1", null, "T1", "D1", "I1");
353                 setupAlbum(1, "A2", null, "T2", "D2", null);
354                 setupAlbum(2, "A3", "A2", "T3", "D3", "I3");
355                 setupAlbum(3, null, null, null, null, null);
356         }
357
358         private void setupAlbum(int albumNumber, String albumId,
359                         String parentAlbumId,
360                         String title, String description, String imageId) {
361                 final String albumPrefix = "Sone/1/Albums/" + albumNumber;
362                 setupString(albumPrefix + "/ID", albumId);
363                 setupString(albumPrefix + "/Title", title);
364                 setupString(albumPrefix + "/Description", description);
365                 setupString(albumPrefix + "/Parent", parentAlbumId);
366                 setupString(albumPrefix + "/AlbumImage", imageId);
367         }
368
369         private AlbumBuilderFactory createAlbumBuilderFactory() {
370                 AlbumBuilderFactory albumBuilderFactory =
371                                 mock(AlbumBuilderFactory.class);
372                 when(albumBuilderFactory.newAlbumBuilder()).thenAnswer(
373                                 new Answer<AlbumBuilder>() {
374                                         @Override
375                                         public AlbumBuilder answer(InvocationOnMock invocation) {
376                                                 return new TestAlbumBuilder();
377                                         }
378                                 });
379                 return albumBuilderFactory;
380         }
381
382         @Test(expected = InvalidAlbumFound.class)
383         public void albumWithInvalidTitleIsRecognized() {
384                 setupAlbum(0, "A1", null, null, "D1", "I1");
385                 configurationSoneParser.parseTopLevelAlbums(
386                                 createAlbumBuilderFactory());
387         }
388
389         @Test(expected = InvalidAlbumFound.class)
390         public void albumWithInvalidDescriptionIsRecognized() {
391                 setupAlbum(0, "A1", null, "T1", null, "I1");
392                 configurationSoneParser.parseTopLevelAlbums(
393                                 createAlbumBuilderFactory());
394         }
395
396         @Test(expected = InvalidParentAlbumFound.class)
397         public void albumWithInvalidParentIsRecognized() {
398                 setupAlbum(0, "A1", "A0", "T1", "D1", "I1");
399                 configurationSoneParser.parseTopLevelAlbums(
400                                 createAlbumBuilderFactory());
401         }
402
403         @Test
404         public void imagesAreParsedCorrectly() {
405                 setupTopLevelAlbums();
406                 configurationSoneParser.parseTopLevelAlbums(
407                                 createAlbumBuilderFactory());
408                 setupImages();
409                 configurationSoneParser.parseImages(createImageBuilderFactory());
410                 Map<String, Album> albums = configurationSoneParser.getAlbums();
411                 assertThat(albums.get("A1").getImages(),
412                                 contains(isImage("I1", 1000L, "K1", "T1", "D1", 16, 9)));
413                 assertThat(albums.get("A2").getImages(), contains(
414                                 isImage("I2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2)));
415                 assertThat(albums.get("A3").getImages(), contains(
416                                 isImage("I3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3)));
417         }
418
419         private void setupImages() {
420                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, 9);
421                 setupImage(1, "I2", "A2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2);
422                 setupImage(2, "I3", "A3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3);
423                 setupImage(3, null, null, 0L, null, null, null, 0, 0);
424         }
425
426         private void setupImage(int imageNumber, String id,
427                         String parentAlbumId, Long creationTime, String key, String title,
428                         String description, Integer width, Integer height) {
429                 final String imagePrefix = "Sone/1/Images/" + imageNumber;
430                 setupString(imagePrefix + "/ID", id);
431                 setupString(imagePrefix + "/Album", parentAlbumId);
432                 setupLong(imagePrefix + "/CreationTime", creationTime);
433                 setupString(imagePrefix + "/Key", key);
434                 setupString(imagePrefix + "/Title", title);
435                 setupString(imagePrefix + "/Description", description);
436                 setupInteger(imagePrefix + "/Width", width);
437                 setupInteger(imagePrefix + "/Height", height);
438         }
439
440         private ImageBuilderFactory createImageBuilderFactory() {
441                 ImageBuilderFactory imageBuilderFactory =
442                                 mock(ImageBuilderFactory.class);
443                 when(imageBuilderFactory.newImageBuilder()).thenAnswer(
444                                 new Answer<ImageBuilder>() {
445                                         @Override
446                                         public ImageBuilder answer(InvocationOnMock invocation)
447                                         throws Throwable {
448                                                 return new TestImageBuilder();
449                                         }
450                                 });
451                 return imageBuilderFactory;
452         }
453
454         @Test(expected = InvalidImageFound.class)
455         public void missingAlbumIdIsRecognized() {
456                 setupTopLevelAlbums();
457                 configurationSoneParser.parseTopLevelAlbums(
458                                 createAlbumBuilderFactory());
459                 setupImage(0, "I1", null, 1000L, "K1", "T1", "D1", 16, 9);
460                 configurationSoneParser.parseImages(createImageBuilderFactory());
461         }
462
463         @Test(expected = InvalidParentAlbumFound.class)
464         public void invalidAlbumIdIsRecognized() {
465                 setupTopLevelAlbums();
466                 configurationSoneParser.parseTopLevelAlbums(
467                                 createAlbumBuilderFactory());
468                 setupImage(0, "I1", "A4", 1000L, "K1", "T1", "D1", 16, 9);
469                 configurationSoneParser.parseImages(createImageBuilderFactory());
470         }
471
472         @Test(expected = InvalidImageFound.class)
473         public void missingCreationTimeIsRecognized() {
474                 setupTopLevelAlbums();
475                 configurationSoneParser.parseTopLevelAlbums(
476                                 createAlbumBuilderFactory());
477                 setupImage(0, "I1", "A1", null, "K1", "T1", "D1", 16, 9);
478                 configurationSoneParser.parseImages(createImageBuilderFactory());
479         }
480
481         @Test(expected = InvalidImageFound.class)
482         public void missingKeyIsRecognized() {
483                 setupTopLevelAlbums();
484                 configurationSoneParser.parseTopLevelAlbums(
485                                 createAlbumBuilderFactory());
486                 setupImage(0, "I1", "A1", 1000L, null, "T1", "D1", 16, 9);
487                 configurationSoneParser.parseImages(createImageBuilderFactory());
488         }
489
490         @Test(expected = InvalidImageFound.class)
491         public void missingTitleIsRecognized() {
492                 setupTopLevelAlbums();
493                 configurationSoneParser.parseTopLevelAlbums(
494                                 createAlbumBuilderFactory());
495                 setupImage(0, "I1", "A1", 1000L, "K1", null, "D1", 16, 9);
496                 configurationSoneParser.parseImages(createImageBuilderFactory());
497         }
498
499         @Test(expected = InvalidImageFound.class)
500         public void missingDescriptionIsRecognized() {
501                 setupTopLevelAlbums();
502                 configurationSoneParser.parseTopLevelAlbums(
503                                 createAlbumBuilderFactory());
504                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", null, 16, 9);
505                 configurationSoneParser.parseImages(createImageBuilderFactory());
506         }
507
508         @Test(expected = InvalidImageFound.class)
509         public void missingWidthIsRecognized() {
510                 setupTopLevelAlbums();
511                 configurationSoneParser.parseTopLevelAlbums(
512                                 createAlbumBuilderFactory());
513                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", null, 9);
514                 configurationSoneParser.parseImages(createImageBuilderFactory());
515         }
516
517         @Test(expected = InvalidImageFound.class)
518         public void missingHeightIsRecognized() {
519                 setupTopLevelAlbums();
520                 configurationSoneParser.parseTopLevelAlbums(
521                                 createAlbumBuilderFactory());
522                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, null);
523                 configurationSoneParser.parseImages(createImageBuilderFactory());
524         }
525
526         private static class TestValue<T> implements Value<T> {
527
528                 private final AtomicReference<T> value = new AtomicReference<T>();
529
530                 public TestValue(T originalValue) {
531                         value.set(originalValue);
532                 }
533
534                 @Override
535                 public T getValue() throws ConfigurationException {
536                         return value.get();
537                 }
538
539                 @Override
540                 public T getValue(T defaultValue) {
541                         final T realValue = value.get();
542                         return (realValue != null) ? realValue : defaultValue;
543                 }
544
545                 @Override
546                 public void setValue(T newValue) throws ConfigurationException {
547                         value.set(newValue);
548                 }
549
550         }
551
552 }