1 package com.atlassian.marketplace.client.model;
2
3 import java.net.URI;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import com.atlassian.fugue.Option;
8 import com.atlassian.marketplace.client.MpacException;
9 import com.atlassian.marketplace.client.api.AddonCategoryId;
10 import com.atlassian.marketplace.client.api.AddonExternalLinkType;
11 import com.atlassian.marketplace.client.api.AddonVersionExternalLinkType;
12 import com.atlassian.marketplace.client.api.ApplicationKey;
13 import com.atlassian.marketplace.client.api.ArtifactId;
14 import com.atlassian.marketplace.client.api.ImageId;
15 import com.atlassian.marketplace.client.api.LicenseTypeId;
16 import com.atlassian.marketplace.client.api.UriTemplate;
17 import com.atlassian.marketplace.client.api.VendorExternalLinkType;
18 import com.atlassian.marketplace.client.api.VendorId;
19 import com.atlassian.marketplace.client.encoding.SchemaViolation;
20 import com.atlassian.marketplace.client.impl.SchemaViolationException;
21 import com.atlassian.marketplace.client.model.Screenshot.ScreenshotEmbedded;
22 import com.atlassian.marketplace.client.model.VersionCompatibility.CompatibilityHosting;
23 import com.atlassian.marketplace.client.model.VersionCompatibility.CompatibilityHostingBounds;
24 import com.atlassian.marketplace.client.util.EntityFunctions;
25
26 import com.google.common.base.Function;
27 import com.google.common.base.Joiner;
28 import com.google.common.collect.ImmutableList;
29 import com.google.common.collect.ImmutableMap;
30 import com.google.common.collect.Iterables;
31
32 import org.joda.time.LocalDate;
33
34 import static com.atlassian.fugue.Option.none;
35 import static com.atlassian.fugue.Option.some;
36 import static com.atlassian.marketplace.client.api.ResourceId.resourceIdToUri;
37 import static com.atlassian.marketplace.client.impl.EntityValidator.validateInstance;
38 import static com.atlassian.marketplace.client.model.TestModelBuilders.DEFAULT_URI;
39 import static com.atlassian.marketplace.client.model.TestModelBuilders.addonDistributionSummary;
40 import static com.atlassian.marketplace.client.model.TestModelBuilders.addonReviewsSummary;
41 import static com.atlassian.marketplace.client.model.TestModelBuilders.imageInfo;
42 import static com.google.common.base.Preconditions.checkNotNull;
43 import static com.google.common.collect.Iterables.transform;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public abstract class ModelBuilders
69 {
70 private ModelBuilders()
71 {
72 }
73
74
75
76
77
78
79
80 @SuppressWarnings("serial")
81 public static class InvalidModelException extends MpacException
82 {
83 private ImmutableList<SchemaViolation> schemaViolations;
84
85 InvalidModelException(Iterable<SchemaViolation> schemaViolations)
86 {
87 this.schemaViolations = ImmutableList.copyOf(schemaViolations);
88 }
89
90 public Iterable<SchemaViolation> getSchemaViolations()
91 {
92 return schemaViolations;
93 }
94
95 @Override
96 public String getMessage()
97 {
98 return Joiner.on(", ").join(schemaViolations);
99 }
100 }
101
102
103
104
105
106
107
108 public static interface SafeBuilder<T>
109 {
110 T build();
111 }
112
113
114
115
116
117
118
119
120 public static interface UnsafeBuilder<T>
121 {
122 T build() throws InvalidModelException;
123 }
124
125 private static InvalidModelException modelException(SchemaViolationException e)
126 {
127 return new InvalidModelException(e.getSchemaViolations());
128 }
129
130
131
132
133 public static AddonBuilder addon()
134 {
135 return new AddonBuilder();
136 }
137
138
139
140
141
142 public static AddonBuilder addon(Addon from)
143 {
144 return new AddonBuilder(from);
145 }
146
147
148
149
150
151 public static AddonVersionBuilder addonVersion()
152 {
153 return new AddonVersionBuilder();
154 }
155
156
157
158
159
160 public static AddonVersionBuilder addonVersion(AddonVersion from)
161 {
162 return new AddonVersionBuilder(from);
163 }
164
165
166
167
168
169 public static AddressBuilder address()
170 {
171 return new AddressBuilder();
172 }
173
174
175
176
177
178 public static ApplicationVersionBuilder applicationVersion()
179 {
180 return new ApplicationVersionBuilder();
181 }
182
183
184
185
186
187 public static ApplicationVersionBuilder applicationVersion(ApplicationVersion from)
188 {
189 return new ApplicationVersionBuilder(from);
190 }
191
192
193
194
195
196 public static HighlightBuilder highlight()
197 {
198 return new HighlightBuilder();
199 }
200
201
202
203
204
205 public static LinksBuilder links()
206 {
207 return new LinksBuilder();
208 }
209
210
211
212
213
214 public static ScreenshotBuilder screenshot()
215 {
216 return new ScreenshotBuilder();
217 }
218
219
220
221
222
223 public static VendorBuilder vendor()
224 {
225 return new VendorBuilder();
226 }
227
228
229
230
231
232 public static VendorBuilder vendor(Vendor from)
233 {
234 return new VendorBuilder(from);
235 }
236
237
238
239
240
241
242 public static VersionCompatibility versionCompatibilityForCloud(ApplicationKey appKey)
243 {
244 return new VersionCompatibility(appKey,
245 new CompatibilityHosting(none(CompatibilityHostingBounds.class), some(true)));
246 }
247
248
249
250
251
252
253
254 public static VersionCompatibility versionCompatibilityForServer(ApplicationKey appKey,
255 int minBuild, int maxBuild)
256 {
257 return new VersionCompatibility(appKey,
258 new CompatibilityHosting(some(makeHostingBounds(minBuild, maxBuild)), some(false)));
259 }
260
261
262
263
264
265
266
267 public static VersionCompatibility versionCompatibilityForServerAndCloud(ApplicationKey appKey,
268 int minBuild, int maxBuild)
269 {
270 return new VersionCompatibility(appKey,
271 new CompatibilityHosting(some(makeHostingBounds(minBuild, maxBuild)), some(true)));
272 }
273
274 private static CompatibilityHostingBounds makeHostingBounds(int min, int max)
275 {
276 return new CompatibilityHostingBounds(
277 new VersionCompatibility.VersionPoint(min, none(String.class)),
278 new VersionCompatibility.VersionPoint(max, none(String.class)));
279 }
280
281 public static abstract class BuilderWithLinks<T extends BuilderWithLinks<T>>
282 {
283 protected LinksBuilder links = new LinksBuilder();
284
285 protected BuilderWithLinks()
286 {
287
288
289
290 links.put("self", TestModelBuilders.DEFAULT_URI);
291 }
292
293 @SuppressWarnings("unchecked")
294 public T links(Links links)
295 {
296 this.links.removeAll();
297 this.links.put(links);
298 return (T) this;
299 }
300
301 @SuppressWarnings("unchecked")
302 public T addLinks(Links links)
303 {
304 this.links.put(links);
305 return (T) this;
306 }
307
308 @SuppressWarnings("unchecked")
309 public T addLink(String rel, URI uri)
310 {
311 this.links.put(rel, uri);
312 return (T) this;
313 }
314
315 @SuppressWarnings("unchecked")
316 public T addLink(String rel, String type, URI uri)
317 {
318 this.links.put(rel, some(type), uri);
319 return (T) this;
320 }
321
322 @SuppressWarnings("unchecked")
323 public T addLinkTemplate(String rel, String template)
324 {
325 this.links.putTemplate(rel, template);
326 return (T) this;
327 }
328 }
329
330 public static abstract class UnsafeBuilderWithLinks<A, T extends UnsafeBuilderWithLinks<A, T>>
331 extends BuilderWithLinks<T> implements UnsafeBuilder<A>
332 {
333 protected abstract A buildUnsafe();
334
335 public A build() throws InvalidModelException
336 {
337 try
338 {
339 return buildUnsafe();
340 }
341 catch (SchemaViolationException e)
342 {
343 throw modelException(e);
344 }
345 }
346 }
347
348 public static class AddonBuilder extends UnsafeBuilderWithLinks<Addon, AddonBuilder>
349 {
350 private String name;
351 private String key;
352 private AddonStatus status;
353 private Option<String> summary = none();
354 private Option<String> tagLine = none();
355 private Option<AddonVersion> version = none();
356 private Option<Boolean> enableAtlassianAnswers = none();
357 private Map<String, URI> externalLinks = new HashMap<String, URI>();
358
359 private AddonBuilder()
360 {
361 links.put("alternate", TestModelBuilders.DEFAULT_URI);
362 }
363
364 private AddonBuilder(Addon from)
365 {
366 links.put(from.getLinks());
367 name = from.getName();
368 key = from.getKey();
369 status = from.getStatus();
370 summary = from.getSummary();
371 tagLine = from.getTagLine();
372 version = from.getVersion();
373 enableAtlassianAnswers = from.isEnableAtlassianAnswers();
374 for (AddonExternalLinkType type: AddonExternalLinkType.values())
375 {
376 for (URI u: from.getExternalLinkUri(type))
377 {
378 externalLinks.put(type.getKey(), u);
379 }
380 }
381 }
382
383 protected Addon buildUnsafe()
384 {
385 Addon addon = new Addon();
386 addon._links = links.build();
387
388 addon._embedded = new Addon.Embedded();
389 addon._embedded.banner = none();
390 addon._embedded.logo = none();
391 addon._embedded.categories = ImmutableList.of();
392 addon._embedded.distribution = addonDistributionSummary().build();
393 addon._embedded.reviews = addonReviewsSummary(0, 0);
394 addon._embedded.vendor = none();
395 addon._embedded.version = version;
396 addon._embedded = validateInstance(addon._embedded);
397
398 addon.name = name;
399 addon.key = key;
400 addon.status = status;
401 addon.summary = summary;
402 addon.tagLine = tagLine;
403 addon.cloudFreeUsers = none();
404 addon.legacy = none();
405 addon.status = status;
406 addon.enableAtlassianAnswers = enableAtlassianAnswers;
407 addon.vendorLinks = ImmutableMap.copyOf(externalLinks);
408
409 return validateInstance(addon);
410 }
411
412
413
414
415 public AddonBuilder name(String name)
416 {
417 this.name = checkNotNull(name);
418 return this;
419 }
420
421
422
423
424 public AddonBuilder key(String key)
425 {
426 this.key = checkNotNull(key);
427 return this;
428 }
429
430
431
432
433 public AddonBuilder status(AddonStatus status)
434 {
435 this.status = status;
436 return this;
437 }
438
439
440
441
442 public AddonBuilder summary(Option<String> summary)
443 {
444 this.summary = checkNotNull(summary);
445 return this;
446 }
447
448
449
450
451 public AddonBuilder tagLine(Option<String> tagLine)
452 {
453 this.tagLine = checkNotNull(tagLine);
454 return this;
455 }
456
457
458
459
460 public AddonBuilder banner(Option<ImageId> image)
461 {
462 links.put("banner", image.map(resourceIdToUri()));
463 return this;
464 }
465
466
467
468
469 public AddonBuilder logo(Option<ImageId> image)
470 {
471 links.put("logo", image.map(resourceIdToUri()));
472 return this;
473 }
474
475
476
477
478 public AddonBuilder categories(Iterable<AddonCategoryId> categories)
479 {
480 links.put("categories", transform(categories, resourceIdToUri()));
481 return this;
482 }
483
484
485
486
487
488 public AddonBuilder vendor(VendorSummary vendor)
489 {
490 return vendor(vendor.getId());
491 }
492
493
494
495
496
497
498 public AddonBuilder vendor(VendorId id)
499 {
500 links.put("vendor", id.getUri());
501 return this;
502 }
503
504
505
506
507 public AddonBuilder enableAtlassianAnswers(boolean enableAtlassianAnswers)
508 {
509 this.enableAtlassianAnswers = some(enableAtlassianAnswers);
510 return this;
511 }
512
513
514
515
516
517
518 public AddonBuilder version(Option<AddonVersion> version)
519 {
520 this.version = checkNotNull(version);
521 return this;
522 }
523
524
525
526
527
528
529
530 public AddonBuilder externalLinkUri(AddonExternalLinkType type, Option<URI> uri)
531 {
532 if (!type.canSetForNewAddons())
533 {
534 throw new IllegalArgumentException("Cannot set " + type + " link for new add-ons");
535 }
536 externalLinks.remove(type.getKey());
537 for (URI u: uri)
538 {
539 externalLinks.put(type.getKey(), u);
540 }
541 return this;
542 }
543 }
544
545 public static class AddonVersionBuilder extends UnsafeBuilderWithLinks<AddonVersion, AddonVersionBuilder>
546 {
547 private Integer buildNumber;
548 private Option<String> name = none();
549 private AddonVersionStatus status;
550 private PaymentModel paymentModel;
551 private Option<ImmutableList<Highlight>> highlights = none();
552 private Option<ImmutableList<Screenshot>> screenshots = none();
553 private Option<String> youtubeId = none();
554 private Option<ImmutableList<VersionCompatibility>> compatibilities = none();
555 private LocalDate releaseDate;
556 private Option<String> releasedBy = none();
557 private boolean beta = false;
558 private boolean staticAddon = false;
559 private boolean supported = false;
560 private boolean deployable = false;
561 private Option<String> releaseSummary = none();
562 private Option<HtmlString> moreDetails = none();
563 private Option<HtmlString> releaseNotes = none();
564 private Map<String, URI> externalLinks = new HashMap<String, URI>();
565
566 private AddonVersionBuilder()
567 {
568 }
569
570 private AddonVersionBuilder(AddonVersion from)
571 {
572 links.put(from.getLinks());
573 buildNumber = from.getBuildNumber();
574 name = from.getName();
575 status = from.getStatus();
576 paymentModel = from.getPaymentModel();
577 releaseDate = from.getReleaseDate();
578 releasedBy = from.getReleasedBy();
579 highlights = copyOptionalList(from.getHighlightsIfSpecified());
580 screenshots = copyOptionalList(from.getScreenshotsIfSpecified());
581 youtubeId = from.getYoutubeId();
582 compatibilities = copyOptionalList(from.getCompatibilitiesIfSpecified());
583 beta = from.isBeta();
584 supported = from.isSupported();
585 staticAddon = from.isStatic();
586 deployable = from.isDeployable();
587 releaseSummary = from.getReleaseSummary();
588 moreDetails = from.getMoreDetails();
589 releaseNotes = from.getReleaseNotes();
590 for (AddonVersionExternalLinkType type: AddonVersionExternalLinkType.values())
591 {
592 for (URI u: from.getExternalLinkUri(type))
593 {
594 externalLinks.put(type.getKey(), u);
595 }
596 }
597 }
598
599 protected AddonVersion buildUnsafe()
600 {
601 AddonVersion ret = new AddonVersion();
602 ret._links = links.build();
603 ret._embedded = new AddonVersion.Embedded();
604 ret._embedded.artifact = none();
605 ret._embedded.highlights = highlights;
606 ret._embedded.screenshots = screenshots;
607 ret.buildNumber = buildNumber;
608 ret.name = name;
609 ret.status = status;
610 ret.paymentModel = paymentModel;
611 ret.youtubeId = youtubeId;
612 ret.compatibilities = compatibilities;
613 ret.staticAddon = staticAddon;
614 ret.deployable = deployable;
615 ret.deployment = new AddonVersion.DeploymentProperties();
616 ret.deployment.autoUpdateAllowed = false;
617 ret.deployment.cloud = false;
618 ret.deployment.connect = false;
619 ret.deployment.dataCenter = false;
620 ret.deployment.permissions = none();
621 ret.deployment.server = false;
622 ret.legacy = none();
623 AddonVersionBase.ReleaseProperties release = new AddonVersionBase.ReleaseProperties();
624 release.beta = beta;
625 release.date = releaseDate;
626 release.releasedBy = releasedBy;
627 release.supported = supported;
628 ret.release = validateInstance(release);
629 ret.text = new AddonVersion.TextProperties();
630 ret.text.releaseSummary = releaseSummary;
631 ret.text.moreDetails = moreDetails;
632 ret.text.releaseNotes = releaseNotes;
633 ret.text = validateInstance(ret.text);
634 ret.vendorLinks = ImmutableMap.copyOf(externalLinks);
635 return validateInstance(ret);
636 }
637
638
639
640
641
642 public AddonVersionBuilder artifact(Option<ArtifactId> artifact)
643 {
644 links.put("artifact", artifact.map(resourceIdToUri()));
645 return this;
646 }
647
648
649
650
651
652
653
654
655
656 public AddonVersionBuilder buildNumber(int buildNumber)
657 {
658 this.buildNumber = buildNumber;
659 return this;
660 }
661
662
663
664
665
666
667
668
669 public AddonVersionBuilder name(String name)
670 {
671 this.name = some(name);
672 return this;
673 }
674
675
676
677
678 public AddonVersionBuilder status(AddonVersionStatus status)
679 {
680 this.status = checkNotNull(status);
681 return this;
682 }
683
684
685
686
687 public AddonVersionBuilder licenseType(Option<LicenseType> licenseType)
688 {
689 links.put("license", licenseType.flatMap(EntityFunctions.selfUri()));
690 return this;
691 }
692
693
694
695
696 public AddonVersionBuilder licenseTypeId(Option<LicenseTypeId> licenseTypeId)
697 {
698 links.put("license", licenseTypeId.map(resourceIdToUri()));
699 return this;
700 }
701
702
703
704
705 public AddonVersionBuilder paymentModel(PaymentModel paymentModel)
706 {
707 this.paymentModel = checkNotNull(paymentModel);
708 return this;
709 }
710
711
712
713
714 public AddonVersionBuilder releaseDate(LocalDate releaseDate)
715 {
716 this.releaseDate = checkNotNull(releaseDate);
717 return this;
718 }
719
720
721
722
723 public AddonVersionBuilder releasedBy(Option<String> releasedBy)
724 {
725 this.releasedBy = checkNotNull(releasedBy);
726 return this;
727 }
728
729
730
731
732 public AddonVersionBuilder highlights(Iterable<Highlight> highlights)
733 {
734 this.highlights = some(ImmutableList.copyOf(highlights));
735 return this;
736 }
737
738
739
740
741 public AddonVersionBuilder screenshots(Iterable<Screenshot> screenshots)
742 {
743 this.screenshots = some(ImmutableList.copyOf(screenshots));
744 return this;
745 }
746
747
748
749
750 public AddonVersionBuilder youtubeId(Option<String> youtubeId)
751 {
752 this.youtubeId = youtubeId;
753 return this;
754 }
755
756
757
758
759 public AddonVersionBuilder compatibilities(Iterable<VersionCompatibility> compatibilities)
760 {
761 this.compatibilities = some(ImmutableList.copyOf(compatibilities));
762 return this;
763 }
764
765
766
767
768 public AddonVersionBuilder beta(boolean beta)
769 {
770 this.beta = beta;
771 return this;
772 }
773
774
775
776
777 public AddonVersionBuilder supported(boolean supported)
778 {
779 this.supported = supported;
780 return this;
781 }
782
783
784
785
786 public AddonVersionBuilder staticAddon(boolean staticAddon)
787 {
788 this.staticAddon = staticAddon;
789 return this;
790 }
791
792
793
794
795 public AddonVersionBuilder deployable(boolean deployable)
796 {
797 this.deployable = deployable;
798 return this;
799 }
800
801
802
803
804 public AddonVersionBuilder releaseSummary(Option<String> releaseSummary)
805 {
806 this.releaseSummary = releaseSummary;
807 return this;
808 }
809
810
811
812
813 public AddonVersionBuilder moreDetails(Option<HtmlString> moreDetails)
814 {
815 this.moreDetails = moreDetails;
816 return this;
817 }
818
819
820
821
822 public AddonVersionBuilder releaseNotes(Option<HtmlString> releaseNotes)
823 {
824 this.releaseNotes = releaseNotes;
825 return this;
826 }
827
828
829
830
831
832
833
834 public AddonVersionBuilder externalLinkUri(AddonVersionExternalLinkType type, Option<URI> uri)
835 {
836 if (!type.canSetForNewAddonVersions())
837 {
838 throw new IllegalArgumentException("Cannot set " + type + " link for new add-ons");
839 }
840 externalLinks.remove(type.getKey());
841 for (URI u: uri)
842 {
843 externalLinks.put(type.getKey(), u);
844 }
845 return this;
846 }
847 }
848
849 public static class AddressBuilder implements UnsafeBuilder<Address>
850 {
851 private String line1;
852 private Option<String> line2 = none();
853 private Option<String> city = none();
854 private Option<String> state = none();
855 private Option<String> postCode = none();
856 private Option<String> country = none();
857
858 public Address build() throws InvalidModelException
859 {
860 try
861 {
862 Address ret = new Address();
863 ret.line1 = line1;
864 ret.line2 = line2;
865 ret.city = city;
866 ret.state = state;
867 ret.postCode = postCode;
868 ret.country = country;
869 return validateInstance(ret);
870 }
871 catch (SchemaViolationException e)
872 {
873 throw modelException(e);
874 }
875 }
876
877
878
879
880 public AddressBuilder line1(String line1)
881 {
882 this.line1 = checkNotNull(line1);
883 return this;
884 }
885
886
887
888
889 public AddressBuilder line2(Option<String> line2)
890 {
891 this.line2 = checkNotNull(line2);
892 return this;
893 }
894
895
896
897
898 public AddressBuilder city(Option<String> city)
899 {
900 this.city = checkNotNull(city);
901 return this;
902 }
903
904
905
906
907 public AddressBuilder state(Option<String> state)
908 {
909 this.state = checkNotNull(state);
910 return this;
911 }
912
913
914
915
916 public AddressBuilder postCode(Option<String> postCode)
917 {
918 this.postCode = checkNotNull(postCode);
919 return this;
920 }
921
922
923
924
925 public AddressBuilder country(Option<String> country)
926 {
927 this.country = checkNotNull(country);
928 return this;
929 }
930 }
931
932 public static class ApplicationVersionBuilder extends UnsafeBuilderWithLinks<ApplicationVersion, ApplicationVersionBuilder>
933 {
934 private Integer buildNumber;
935 private String name;
936 private LocalDate releaseDate;
937 private ApplicationVersionStatus status;
938
939 private ApplicationVersionBuilder()
940 {
941 }
942
943 private ApplicationVersionBuilder(ApplicationVersion from)
944 {
945 links.put(from.getLinks());
946 buildNumber = from.getBuildNumber();
947 name = from.getName();
948 releaseDate = from.getReleaseDate();
949 status = from.getStatus();
950 }
951
952 protected ApplicationVersion buildUnsafe()
953 {
954 ApplicationVersion ret = new ApplicationVersion();
955 ret._links = links.build();
956 ret.buildNumber = buildNumber;
957 ret.version = name;
958 ret.releaseDate = releaseDate;
959 ret.status = status;
960 return validateInstance(ret);
961 }
962
963
964
965
966 public ApplicationVersionBuilder buildNumber(int buildNumber)
967 {
968 this.buildNumber = buildNumber;
969 return this;
970 }
971
972
973
974
975 public ApplicationVersionBuilder name(String name)
976 {
977 this.name = checkNotNull(name);
978 return this;
979 }
980
981
982
983
984 public ApplicationVersionBuilder releaseDate(LocalDate releaseDate)
985 {
986 this.releaseDate = checkNotNull(releaseDate);
987 return this;
988 }
989
990
991
992
993 public ApplicationVersionBuilder status(ApplicationVersionStatus status)
994 {
995 this.status = checkNotNull(status);
996 return this;
997 }
998 }
999
1000 public static class HighlightBuilder extends UnsafeBuilderWithLinks<Highlight, HighlightBuilder>
1001 {
1002 private ImageInfo fullImage;
1003 private ImageInfo thumbnailImage;
1004 private String title;
1005 private HtmlString body;
1006 private Option<String> explanation = none();
1007
1008 protected Highlight buildUnsafe()
1009 {
1010 Highlight ret = new Highlight();
1011 ret._embedded = new Highlight.Embedded();
1012 ret._embedded.screenshot = fullImage;
1013 ret._embedded.thumbnail = thumbnailImage;
1014 ret._embedded = validateInstance(ret._embedded);
1015 ret._links = links.build();
1016 ret.body = body;
1017 ret.title = title;
1018 ret.explanation = explanation;
1019 return validateInstance(ret);
1020 }
1021
1022
1023
1024
1025 public HighlightBuilder fullImage(ImageId fullImage)
1026 {
1027 links.put("screenshot", fullImage.getUri());
1028 this.fullImage = imageInfo().build();
1029 return this;
1030 }
1031
1032
1033
1034
1035 public HighlightBuilder thumbnailImage(ImageId thumbnailImage)
1036 {
1037 links.put("thumbnail", thumbnailImage.getUri());
1038 this.thumbnailImage = imageInfo().build();
1039 return this;
1040 }
1041
1042
1043
1044
1045 public HighlightBuilder title(String title)
1046 {
1047 this.title = checkNotNull(title);
1048 return this;
1049 }
1050
1051
1052
1053
1054 public HighlightBuilder body(HtmlString body)
1055 {
1056 this.body = checkNotNull(body);
1057 return this;
1058 }
1059
1060
1061
1062
1063 public HighlightBuilder explanation(Option<String> explanation)
1064 {
1065 this.explanation = checkNotNull(explanation);
1066 return this;
1067 }
1068 }
1069
1070 public static class LinksBuilder implements SafeBuilder<Links>
1071 {
1072 private Map<String, ImmutableList<Link>> links = new HashMap<String, ImmutableList<Link>>();
1073
1074 public Links build()
1075 {
1076 return new Links(links);
1077 }
1078
1079
1080
1081
1082 public LinksBuilder put(String rel, URI uri)
1083 {
1084 return put(rel, none(String.class), uri);
1085 }
1086
1087
1088
1089
1090
1091 public LinksBuilder put(String rel, Iterable<URI> uris)
1092 {
1093 return put(rel, ImmutableList.copyOf(Iterables.transform(uris, new Function<URI, Link>()
1094 {
1095 public Link apply(URI uri)
1096 {
1097 return Link.fromUri(uri, none(String.class));
1098 }
1099 })));
1100 }
1101
1102
1103
1104
1105 public LinksBuilder put(String rel, Option<String> type, URI uri)
1106 {
1107 return put(rel, ImmutableList.of(Link.fromUri(uri, type)));
1108 }
1109
1110
1111
1112
1113 public LinksBuilder put(String rel, Option<URI> maybeUri)
1114 {
1115 for (URI uri: maybeUri)
1116 {
1117 return put(rel, uri);
1118 }
1119 return this;
1120 }
1121
1122
1123
1124
1125 public LinksBuilder put(String rel, ImmutableList<Link> values)
1126 {
1127 links.put(rel, values);
1128 return this;
1129 }
1130
1131
1132
1133
1134
1135 public LinksBuilder put(Links from)
1136 {
1137 links.putAll(from.getItems());
1138 return this;
1139 }
1140
1141
1142
1143
1144 public LinksBuilder putTemplate(String rel, String template)
1145 {
1146 return put(rel, ImmutableList.of(Link.fromUriTemplate(UriTemplate.create(template), none(String.class))));
1147 }
1148
1149
1150
1151
1152 public LinksBuilder remove(String rel)
1153 {
1154 links.remove(rel);
1155 return this;
1156 }
1157
1158
1159
1160
1161 public LinksBuilder removeAll()
1162 {
1163 links.clear();
1164 return this;
1165 }
1166 }
1167
1168 public static class ScreenshotBuilder extends UnsafeBuilderWithLinks<Screenshot, ScreenshotBuilder>
1169 {
1170 private ImageInfo image;
1171 private Option<String> caption = none();
1172
1173 protected Screenshot buildUnsafe()
1174 {
1175 Screenshot ret = new Screenshot();
1176 ret._links = links.build();
1177 ret._embedded = new ScreenshotEmbedded();
1178 ret._embedded.image = image;
1179 ret._embedded = validateInstance(ret._embedded);
1180 ret.caption = caption;
1181 return validateInstance(ret);
1182 }
1183
1184
1185
1186
1187 public ScreenshotBuilder image(ImageId image)
1188 {
1189 links.put("image", image.getUri());
1190 this.image = imageInfo().build();
1191 return this;
1192 }
1193
1194
1195
1196
1197 public ScreenshotBuilder caption(Option<String> caption)
1198 {
1199 this.caption = checkNotNull(caption);
1200 return this;
1201 }
1202 }
1203
1204 public static class VendorBuilder extends UnsafeBuilderWithLinks<Vendor, VendorBuilder>
1205 {
1206 private String name;
1207 private Option<String> description = none();
1208 private String email;
1209 private Option<Address> address = none();
1210 private Option<String> phone = none();
1211 private Option<String> otherContactDetails = none();
1212 private Map<String, URI> externalLinks = new HashMap<String, URI>();
1213
1214 private VendorBuilder()
1215 {
1216 links.put("alternate", DEFAULT_URI);
1217 }
1218
1219 private VendorBuilder(Vendor from)
1220 {
1221 links.put(from.getLinks());
1222 name = from.getName();
1223 description = from.getDescription();
1224 address = from.getAddress();
1225 email = from.getEmail();
1226 phone = from.getPhone();
1227 otherContactDetails = from.getOtherContactDetails();
1228 for (VendorExternalLinkType type: VendorExternalLinkType.values())
1229 {
1230 for (URI u: from.getExternalLinkUri(type))
1231 {
1232 externalLinks.put(type.getKey(), u);
1233 }
1234 }
1235 }
1236
1237 protected Vendor buildUnsafe()
1238 {
1239 Vendor ret = new Vendor();
1240 ret._links = links.build();
1241 ret._embedded = new Vendor.Embedded();
1242 ret._embedded.logo = none();
1243 ret.address = address;
1244 ret.description = description;
1245 ret.email = email;
1246 ret.name = name;
1247 ret.otherContactDetails = otherContactDetails;
1248 ret.phone = phone;
1249 ret.vendorLinks = ImmutableMap.copyOf(externalLinks);
1250 ret.verifiedStatus = none();
1251 return validateInstance(ret);
1252 }
1253
1254
1255
1256
1257 public VendorBuilder logo(Option<ImageId> logo)
1258 {
1259 links.put("logo", logo.map(resourceIdToUri()));
1260 return this;
1261 }
1262
1263
1264
1265
1266 public VendorBuilder name(String name)
1267 {
1268 this.name = checkNotNull(name);
1269 return this;
1270 }
1271
1272
1273
1274
1275 public VendorBuilder description(Option<String> description)
1276 {
1277 this.description = checkNotNull(description);
1278 return this;
1279 }
1280
1281
1282
1283
1284 public VendorBuilder address(Option<Address> address)
1285 {
1286 this.address = checkNotNull(address);
1287 return this;
1288 }
1289
1290
1291
1292
1293 public VendorBuilder email(String email)
1294 {
1295 this.email = checkNotNull(email);
1296 return this;
1297 }
1298
1299
1300
1301
1302 public VendorBuilder phone(Option<String> phone)
1303 {
1304 this.phone = checkNotNull(phone);
1305 return this;
1306 }
1307
1308
1309
1310
1311 public VendorBuilder otherContactDetails(Option<String> otherContactDetails)
1312 {
1313 this.otherContactDetails = checkNotNull(otherContactDetails);
1314 return this;
1315 }
1316
1317
1318
1319
1320
1321
1322
1323 public VendorBuilder externalLinkUri(VendorExternalLinkType type, Option<URI> uri)
1324 {
1325 externalLinks.remove(type.getKey());
1326 for (URI u: uri)
1327 {
1328 externalLinks.put(type.getKey(), u);
1329 }
1330 return this;
1331 }
1332 }
1333
1334 private static <T> Option<ImmutableList<T>> copyOptionalList(Option<Iterable<T>> list)
1335 {
1336 for (Iterable<T> l: list)
1337 {
1338 return some(ImmutableList.copyOf(l));
1339 }
1340 return none();
1341 }
1342 }