View Javadoc

1   package com.atlassian.marketplace.client.model;
2   
3   import java.net.URI;
4   import java.util.Date;
5   import java.util.HashMap;
6   import java.util.Map;
7   
8   import com.atlassian.fugue.Option;
9   import com.atlassian.fugue.Pair;
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.VendorExternalLinkType;
14  import com.atlassian.marketplace.client.api.VendorId;
15  import com.atlassian.marketplace.client.model.AddonPricing.RoleInfo;
16  import com.atlassian.marketplace.client.model.AddonVersionBase.DeploymentProperties;
17  import com.atlassian.marketplace.client.model.ModelBuilders.BuilderWithLinks;
18  import com.atlassian.marketplace.client.model.ModelBuilders.LinksBuilder;
19  import com.atlassian.marketplace.client.model.ModelBuilders.SafeBuilder;
20  import com.atlassian.marketplace.client.util.EntityFunctions;
21  
22  import com.google.common.collect.ImmutableList;
23  import com.google.common.collect.ImmutableMap;
24  
25  import org.joda.time.DateTime;
26  import org.joda.time.LocalDate;
27  
28  import static com.atlassian.fugue.Option.none;
29  import static com.atlassian.fugue.Option.some;
30  import static com.atlassian.fugue.Options.flatten;
31  import static com.atlassian.marketplace.client.impl.EntityValidator.validateInstance;
32  import static com.atlassian.marketplace.client.model.Links.WEB_TYPE;
33  import static com.atlassian.marketplace.client.model.ModelBuilders.links;
34  import static com.google.common.base.Preconditions.checkNotNull;
35  import static com.google.common.collect.Iterables.transform;
36  
37  /**
38   * Classes for constructing model objects for the 2.0 API that normally are only ever returned
39   * by the server, so that the only reason for constructing them yourself is to provide fake data
40   * for testing your own code.  Therefore, these builders behave differently than the ones in
41   * {@link ModelBuilders}:  any required property that you do not set a value for will be given
42   * a default value, so that the object returned by {@code build()} always has a valid schema,
43   * and {@code build()} will never throw an exception.
44   * 
45   * @since 2.0.0
46   */
47  public abstract class TestModelBuilders
48  {
49      // Some comments on implementation:
50      //
51      // 1. As the above javadoc comment says, TestModelBuilders by design is never supposed to throw
52      // an InvalidModelException.  However, we still want to call validateInstance(), because that
53      // method doesn't only throw errors for bad things: it also provides good things, like ensuring
54      // that unset Options default to none(), and that calculated fields like selfUri are properly
55      // initialized.  It could theoretically still throw an unchecked exception, but that would
56      // indicate a library bug (and there are unit tests for TestModelBuilders to verify that that
57      // doesn't happen in reality).
58      //
59      // 2. For objects like Addon that also have a corresponding builder in ModelBuilders, the builder
60      // here is a wrapper around a ModelBuilders instance, with additional property initialization
61      // and in some cases additional setters (for properties that ModelBuilders doesn't handle,
62      // because they are normally read-only/generated by the server).
63          
64      public static URI DEFAULT_URI = URI.create("http://default/uri");
65      static String DEFAULT_STRING = "DefaultValue";
66      static Date DEFAULT_DATE = new Date(0L);
67      static int DEFAULT_INT = Integer.MAX_VALUE;
68      static LocalDate DEFAULT_LOCAL_DATE = new LocalDate(2000, 01, 01);
69      static long DEFAULT_LONG = Long.MAX_VALUE;
70      static URI DEFAULT_ABSOLUTE_URI = URI.create("http://default/uri");
71      static float DEFAULT_PRICE = 100.00f;
72      static int DEFAULT_STARS = 3;
73      
74      private TestModelBuilders()
75      {
76      }
77      
78      /**
79       * Creates a new {@link AddonBuilder}.  Use this only to create test data imitating a
80       * server response; if you are constructing an object to create or update on the server, use
81       * {@link ModelBuilders#addon()}.
82       */
83      public static AddonBuilder addon()
84      {
85          return new AddonBuilder();
86      }
87      
88      /**
89       * Creates a new {@link AddonBuilder}.  Use this only to create test data imitating a
90       * server response; if you are constructing an object to create or update on the server, use
91       * {@link ModelBuilders#addon()}.
92       */
93      public static AddonBuilder addon(Addon from)
94      {
95          return new AddonBuilder(from);
96      }
97      
98      /**
99       * Creates a new {@link AddonCategorySummaryBuilder}.
100      */
101     public static AddonCategorySummaryBuilder addonCategorySummary()
102     {
103         return new AddonCategorySummaryBuilder();
104     }
105     
106     /**
107      * Creates a new {@link AddonDistributionSummaryBuilder}.
108      */
109     public static AddonDistributionSummaryBuilder addonDistributionSummary()
110     {
111         return new AddonDistributionSummaryBuilder();
112     }
113 
114     /**
115      * Creates a new {@link AddonPricingBuilder}.
116      */
117     public static AddonPricingBuilder addonPricing()
118     {
119         return new AddonPricingBuilder();
120     }
121     
122     /**
123      * Creates a new {@link AddonPricingItemBuilder}.
124      */
125     public static AddonPricingItemBuilder addonPricingItem()
126     {
127         return new AddonPricingItemBuilder();
128     }
129     
130     /**
131      * Creates a new {@link AddonReferenceBuilder}.
132      */
133     public static AddonReferenceBuilder addonReference()
134     {
135         return new AddonReferenceBuilder();
136     }
137 
138     /**
139      * Creates a new {@link AddonReviewsSummary}.
140      */
141     public static AddonReviewsSummary addonReviewsSummary(float averageStars, int count)
142     {
143         AddonReviewsSummary ret = new AddonReviewsSummary();
144         ret.averageStars = averageStars;
145         ret.count = count;
146         return ret;
147     }
148 
149     /**
150      * Creates a new {@link AddonSummaryBuilder}.
151      */
152     public static AddonSummaryBuilder addonSummary()
153     {
154         return new AddonSummaryBuilder();
155     }
156 
157     /**
158      * Creates a new {@link AddonVersionBuilder}.  Use this only to create test data imitating a
159      * server response; if you are constructing an object to create or update on the server, use
160      * {@link ModelBuilders#addonVersion()}.
161      */
162     public static AddonVersionBuilder addonVersion()
163     {
164         return new AddonVersionBuilder();
165     }
166 
167     /**
168      * Creates a new {@link AddonVersionBuilder}.  Use this only to create test data imitating a
169      * server response; if you are constructing an object to create or update on the server, use
170      * {@link ModelBuilders#addonVersion(AddonVersion)}.
171      */
172     public static AddonVersionBuilder addonVersion(AddonVersion from)
173     {
174         return new AddonVersionBuilder(from);
175     }
176 
177     /**
178      * Creates a new {@link AddonVersionSummaryBuilder}.
179      */
180     public static AddonVersionSummaryBuilder addonVersionSummary()
181     {
182         return new AddonVersionSummaryBuilder();
183     }
184     
185     /**
186      * Creates a new {@link ApplicationBuilder}.
187      */
188     public static ApplicationBuilder application()
189     {
190         return new ApplicationBuilder();
191     }
192 
193     /**
194      * Creates a new {@link ApplicationBuilder}.
195      */
196     public static ApplicationBuilder application(Application from)
197     {
198         return new ApplicationBuilder(from);
199     }
200     
201     /**
202      * Creates a new {@link ApplicationVersionBuilder}.  Use this only to create test data imitating a
203      * server response; if you are constructing an object to create or update on the server, use
204      * {@link ModelBuilders#applicationVersion()}.
205      */
206     public static ApplicationVersionBuilder applicationVersion()
207     {
208         return new ApplicationVersionBuilder();
209     }
210 
211     /**
212      * Creates a new {@link ApplicationVersionBuilder}.  Use this only to create test data imitating a
213      * server response; if you are constructing an object to create or update on the server, use
214      * {@link ModelBuilders#applicationVersion(ApplicationVersion)}.
215      */
216     public static ApplicationVersionBuilder applicationVersion(ApplicationVersion from)
217     {
218         return new ApplicationVersionBuilder(from);
219     }
220     
221     /**
222      * Creates a new {@link ArtifactInfo}.
223      */
224     public static ArtifactInfo artifactInfo(URI binaryUri, boolean remote)
225     {
226         ArtifactInfo ai = new ArtifactInfo();
227         LinksBuilder links = links();
228         links.put("self", DEFAULT_URI);
229         links.put("binary", binaryUri);
230         if (remote)
231         {
232             links.put("remote", binaryUri);
233         }
234         ai._links = links.build();
235         return validateInstance(ai);
236     }
237     
238     /**
239      * Creates a new {@link ConnectScope}.
240      */
241     public static ConnectScope connectScope(String key, String name, String description)
242     {
243         ConnectScope ret = new ConnectScope();
244         ret._links = links().put("alternate", DEFAULT_ABSOLUTE_URI).build();
245         ret.key = checkNotNull(key);
246         ret.name = checkNotNull(name);
247         ret.description = checkNotNull(description);
248         return ret;
249     }
250 
251     /**
252      * Creates a new {@link ErrorDetail}.
253      */
254     public static ErrorDetail errorDetail(String message)
255     {
256         return errorDetail(message, none(String.class), none(String.class));
257     }
258 
259     /**
260      * Creates a new {@link ErrorDetail}.
261      */
262     public static ErrorDetail errorDetail(String message, Option<String> path, Option<String> code)
263     {
264         ErrorDetail ret = new ErrorDetail();
265         ret.message = checkNotNull(message);
266         ret.path = checkNotNull(path);
267         ret.code = checkNotNull(code);
268         return ret;
269     }
270 
271     /**
272      * Creates a new {@link ImageInfoBuilder}.
273      */
274     public static ImageInfoBuilder imageInfo()
275     {
276         return new ImageInfoBuilder();
277     }
278     
279     /**
280      * Creates a new {@link ProductBuilder}.
281      */
282     public static ProductBuilder product()
283     {
284         return new ProductBuilder();
285     }
286     
287     /**
288      * Creates a new {@link ProductVersionBuilder}.
289      */
290     public static ProductVersionBuilder productVersion()
291     {
292         return new ProductVersionBuilder();
293     }
294 
295     /**
296      * Creates a new {@link VendorBuilder}.  Use this only to create test data imitating a
297      * server response; if you are constructing a vendor to create or update on the server, use
298      * {@link ModelBuilders#vendor()}.
299      */
300     public static VendorBuilder vendor()
301     {
302         return new VendorBuilder();
303     }
304 
305     /**
306      * Creates a new {@link VendorBuilder}.  Use this only to create test data imitating a
307      * server response; if you are constructing a vendor to create or update on the server, use
308      * {@link ModelBuilders#vendor(Vendor)}.
309      */
310     public static VendorBuilder vendor(Vendor from)
311     {
312         return new VendorBuilder(from);
313     }
314     
315     /**
316      * Creates a new {@link VendorSummaryBuilder}.
317      */
318     public static VendorSummaryBuilder vendorSummary()
319     {
320         return new VendorSummaryBuilder();
321     }
322     
323     public static class AddonBuilder extends BuilderWithLinks<AddonBuilder> implements SafeBuilder<Addon>
324     {
325         private ModelBuilders.AddonBuilder builder;
326         private Option<ImageInfo> banner = none();
327         private ImmutableList<AddonCategorySummary> categories = ImmutableList.of();
328         private AddonDistributionSummary distribution = addonDistributionSummary().build();
329         private Option<ImageInfo> logo = none();
330         private AddonReviewsSummary reviews = addonReviewsSummary(DEFAULT_STARS, DEFAULT_INT);
331         private VendorSummary vendor = vendorSummary().build();
332         private Option<Integer> cloudFreeUsers = none();
333         private Map<String, URI> legacyLinks = new HashMap<String, URI>();
334         private Option<HtmlString> legacyDescription = none();
335         
336         private AddonBuilder()
337         {
338             builder = ModelBuilders.addon();
339             builder.name(DEFAULT_STRING);
340             builder.key(DEFAULT_STRING);
341             builder.status(AddonStatus.PUBLIC);
342             builder.vendor(VendorId.fromUri(DEFAULT_URI));
343         }
344 
345         private AddonBuilder(Addon a)
346         {
347             builder = ModelBuilders.addon(a);
348             banner = a.getBanner();
349             categories = ImmutableList.copyOf(a.getCategories());
350             distribution = a.getDistribution();
351             logo = a.getLogo();
352             reviews = a.getReviews();
353             vendor = a.getVendor().getOrElse(vendor);
354             cloudFreeUsers = a.getCloudFreeUsers();
355             legacyDescription = a.getDescription();
356         }
357         
358         public Addon build()
359         {
360             builder.addLinks(this.links.build());
361             Addon a = safeBuild(builder);
362             a._embedded.banner = banner;
363             a._embedded.logo = logo;
364             a._embedded.categories = categories;
365             a._embedded.distribution = distribution;
366             a._embedded.reviews = reviews;
367             a._embedded.vendor = some(vendor);
368             a.cloudFreeUsers = cloudFreeUsers;
369             if (!legacyLinks.isEmpty() || !legacyDescription.isEmpty())
370             {
371                 Addon.LegacyProperties legacy = new Addon.LegacyProperties();
372                 legacy.description = legacyDescription;
373                 legacy.vendorLinks = ImmutableMap.copyOf(legacyLinks);
374             }
375             return a;
376         }
377         
378         public AddonBuilder name(String name)
379         {
380             builder.name(name);
381             return this;
382         }
383         
384         public AddonBuilder key(String key)
385         {
386             builder.key(key);
387             return this;
388         }
389 
390         public AddonBuilder status(AddonStatus status)
391         {
392             builder.status(status);
393             return this;
394         }
395         
396         public AddonBuilder summary(Option<String> summary)
397         {
398             builder.summary(summary);
399             return this;
400         }
401 
402         public AddonBuilder tagLine(Option<String> tagLine)
403         {
404             builder.tagLine(tagLine);
405             return this;
406         }
407 
408         public AddonBuilder cloudFreeUsers(Option<Integer> cloudFreeUsers)
409         {
410             this.cloudFreeUsers = checkNotNull(cloudFreeUsers);
411             return this;
412         }
413 
414         public AddonBuilder banner(Option<ImageInfo> banner)
415         {
416             this.banner = checkNotNull(banner);
417             links.put("banner", banner.flatMap(EntityFunctions.selfUri()));
418             return this;
419         }
420         
421         public AddonBuilder logo(Option<ImageInfo> logo)
422         {
423             this.logo = checkNotNull(logo);
424             links.put("logo", logo.flatMap(EntityFunctions.selfUri()));
425             return this;
426         }
427         
428         public AddonBuilder categories(Iterable<AddonCategorySummary> categories)
429         {
430             this.categories = ImmutableList.copyOf(checkNotNull(categories));
431             builder.links.put("categories", flatten(transform(categories, EntityFunctions.<AddonCategorySummary>selfUri())));
432             return this;
433         }
434 
435         public AddonBuilder distribution(AddonDistributionSummary distribution)
436         {
437             this.distribution = distribution;
438             return this;
439         }
440 
441         public AddonBuilder reviews(AddonReviewsSummary reviews)
442         {
443             this.reviews = reviews;
444             return this;
445         }
446 
447         /**
448          * Specifies the add-on's vendor using a {@link VendorSummary} instance.
449          * @see #vendor(URI)
450          */
451         public AddonBuilder vendor(VendorSummary vendor)
452         {
453             this.vendor = checkNotNull(vendor);
454             builder.vendor(vendor);
455             return this;
456         }
457         
458         /**
459          * Attaches an {@link AddonVersion} to the {@link Addon}.  You must do this if you are
460          * creating a new add-on, since an add-on cannot be created with no versions.
461          */
462         public AddonBuilder version(Option<AddonVersion> version)
463         {
464             builder.version(version);
465             return this;
466         }
467         
468         public AddonBuilder externalLinkUri(AddonExternalLinkType type, Option<URI> issueTrackerUri)
469         {
470             if (type.canSetForNewAddons())
471             {
472                 builder.externalLinkUri(type, issueTrackerUri);
473             }
474             else
475             {
476                 legacyLinks.remove(type.getKey());
477                 for (URI u: issueTrackerUri)
478                 {
479                     legacyLinks.put(type.getKey(), u);
480                 }
481             }
482             return this;
483         }
484     }
485     
486     public static class AddonCategorySummaryBuilder extends BuilderWithLinks<AddonCategorySummaryBuilder>
487         implements SafeBuilder<AddonCategorySummary>
488     {
489         private String name = DEFAULT_STRING;
490         
491         public AddonCategorySummary build()
492         {
493             AddonCategorySummary ret = new AddonCategorySummary();
494             ret._links = links.build();
495             ret.name = name;
496             return ret;
497         }
498         
499         public AddonCategorySummaryBuilder name(String name)
500         {
501             this.name = checkNotNull(name);
502             return this;
503         }
504     }
505     
506     public static class AddonDistributionSummaryBuilder implements SafeBuilder<AddonDistributionSummary>
507     {
508         private boolean bundled;
509         private int downloads = 1;
510         private Option<Integer> totalInstalls = none();
511         private Option<Integer> totalUsers = none();
512         
513         public AddonDistributionSummary build()
514         {
515             AddonDistributionSummary ret = new AddonDistributionSummary();
516             ret.bundled = bundled;
517             ret.downloads = downloads;
518             ret.totalInstalls = totalInstalls;
519             ret.totalUsers = totalUsers;
520             return ret;
521         }
522         
523         public AddonDistributionSummaryBuilder bundled(boolean bundled)
524         {
525             this.bundled = bundled;
526             return this;
527         }
528         
529         public AddonDistributionSummaryBuilder downloads(int downloads)
530         {
531             this.downloads = downloads;
532             return this;
533         }
534         
535         public AddonDistributionSummaryBuilder totalInstalls(Option<Integer> totalInstalls)
536         {
537             this.totalInstalls = totalInstalls;
538             return this;
539         }
540         
541         public AddonDistributionSummaryBuilder totalUsers(Option<Integer> totalUsers)
542         {
543             this.totalUsers = totalUsers;
544             return this;
545         }
546     }
547 
548     public static class AddonPricingBuilder extends BuilderWithLinks<AddonPricingBuilder>
549         implements SafeBuilder<AddonPricing>
550     {
551         private LinksBuilder links = ModelBuilders.links().put("self", DEFAULT_URI);
552         private ImmutableList<AddonPricingItem> items = ImmutableList.of();
553         private boolean expertDiscountOptOut;
554         private boolean contactSalesForAdditionalPricing;
555         private Option<String> parent = none();
556         private Option<DateTime> lastModified = none();
557         private Option<RoleInfo> role = none();
558 
559         public AddonPricing build()
560         {
561             AddonPricing ret = new AddonPricing();
562             ret._links = links.build();
563             ret.items = items;
564             ret.expertDiscountOptOut = expertDiscountOptOut;
565             ret.contactSalesForAdditionalPricing = contactSalesForAdditionalPricing;
566             ret.parent = parent;
567             ret.lastModified = lastModified;
568             ret.role = role;
569             return ret;
570         }
571         
572         public AddonPricingBuilder items(Iterable<AddonPricingItem> items)
573         {
574             this.items = ImmutableList.copyOf(items);
575             return this;
576         }
577         
578         public AddonPricingBuilder expertDiscountOptOut(boolean expertDiscountOptOut)
579         {
580             this.expertDiscountOptOut = expertDiscountOptOut;
581             return this;
582         }
583         
584         public AddonPricingBuilder contactSalesForAdditionalPricing(boolean contactSalesForAdditionalPricing)
585         {
586             this.contactSalesForAdditionalPricing = contactSalesForAdditionalPricing;
587             return this;
588         }
589         
590         public AddonPricingBuilder parent(Option<String> parent)
591         {
592             this.parent = checkNotNull(parent);
593             return this;
594         }
595         
596         public AddonPricingBuilder lastModified(Option<DateTime> lastModified)
597         {
598             this.lastModified = checkNotNull(lastModified);
599             return this;
600         }
601         
602         public AddonPricingBuilder role(Option<Pair<String, String>> singularAndPluralRoleName)
603         {
604             for (Pair<String, String> p: singularAndPluralRoleName)
605             {
606                 RoleInfo r = new RoleInfo();
607                 r.singularName = p.left();
608                 r.pluralName = p.right();
609                 this.role = some(r);
610                 return this;
611             }
612             this.role = none();
613             return this;
614         }
615     }
616     
617     public static class AddonPricingItemBuilder implements SafeBuilder<AddonPricingItem>
618     {
619         private String description = DEFAULT_STRING;
620         private String editionId = DEFAULT_STRING;
621         private String editionDescription = DEFAULT_STRING;
622         private LicenseEditionType editionType = LicenseEditionType.USER_TIER;
623         private String licenseType = DEFAULT_STRING;
624         private float amount;
625         private Option<Float> renewalAmount = none();
626         private int unitCount = 1;
627         private int monthsValid = 1;
628         
629         public AddonPricingItem build()
630         {
631             AddonPricingItem ret = new AddonPricingItem();
632             ret.description = description;
633             ret.editionId = editionId;
634             ret.editionDescription = editionDescription;
635             ret.editionType = editionType;
636             ret.licenseType = licenseType;
637             ret.amount = amount;
638             ret.renewalAmount = renewalAmount;
639             ret.unitCount = unitCount;
640             ret.monthsValid = monthsValid;
641             return ret;
642         }
643         
644         public AddonPricingItemBuilder description(String description)
645         {
646             this.description = checkNotNull(description);
647             return this;
648         }
649         
650         public AddonPricingItemBuilder editionId(String editionId)
651         {
652             this.editionId = checkNotNull(editionId);
653             return this;
654         }
655         
656         public AddonPricingItemBuilder editionDescription(String editionDescription)
657         {
658             this.editionDescription = checkNotNull(editionDescription);
659             return this;
660         }
661         
662         public AddonPricingItemBuilder editionType(LicenseEditionType editionType)
663         {
664             this.editionType = checkNotNull(editionType);
665             return this;
666         }
667         
668         public AddonPricingItemBuilder licenseType(String licenseType)
669         {
670             this.licenseType = checkNotNull(licenseType);
671             return this;
672         }
673         
674         public AddonPricingItemBuilder amount(float amount)
675         {
676             this.amount = amount;
677             return this;
678         }
679         
680         public AddonPricingItemBuilder renewalAmount(Option<Float> renewalAmount)
681         {
682             this.renewalAmount = checkNotNull(renewalAmount);
683             return this;
684         }
685         
686         public AddonPricingItemBuilder unitCount(int unitCount)
687         {
688             this.unitCount = unitCount;
689             return this;
690         }
691         
692         public AddonPricingItemBuilder monthsValid(int monthsValid)
693         {
694             this.monthsValid = monthsValid;
695             return this;
696         }
697     }
698     
699     public static class AddonReferenceBuilder extends BuilderWithLinks<AddonReferenceBuilder>
700         implements SafeBuilder<AddonReference>
701     {
702         private String key = DEFAULT_STRING;
703         private String name = DEFAULT_STRING;
704         private Option<ImageInfo> image = none();
705         private Option<AddonReviewsSummary> reviews = none();
706         
707         private AddonReferenceBuilder()
708         {
709             links.put("self", DEFAULT_URI);
710             links.put("alternate", some(WEB_TYPE), DEFAULT_URI);
711             links.put("vendor", DEFAULT_URI);
712         }
713         
714         public AddonReference build()
715         {
716             AddonReference ret = new AddonReference();
717             ret._links = links.build();
718             ret._embedded = new AddonReference.Embedded();
719             ret._embedded.image = image;
720             ret._embedded.reviews = reviews;
721             ret.name = name;
722             ret.key = key;
723             return ret;
724         }
725 
726         public AddonReferenceBuilder key(String key)
727         {
728             this.key = key;
729             return this;
730         }
731 
732         public AddonReferenceBuilder name(String name)
733         {
734             this.name = name;
735             return this;
736         }
737 
738         public AddonReferenceBuilder image(Option<ImageInfo> image)
739         {
740             this.image = image;
741             links.put("image", image.flatMap(EntityFunctions.<ImageInfo>selfUri()));
742             return this;
743         }
744         
745         public AddonReferenceBuilder reviews(Option<AddonReviewsSummary> reviews)
746         {
747             this.reviews = reviews;
748             return this;
749         }
750     }
751 
752     public static class AddonSummaryBuilder extends BuilderWithLinks<AddonSummaryBuilder>
753         implements SafeBuilder<AddonSummary>
754     {
755         private String key = DEFAULT_STRING;
756         private String name = DEFAULT_STRING;
757         private AddonStatus status = AddonStatus.PUBLIC;
758         private Option<String> summary = none();
759         private Option<Integer> cloudFreeUsers = none();
760         private ImmutableList<AddonCategorySummary> categories = ImmutableList.of();
761         private AddonDistributionSummary distribution = addonDistributionSummary().build();
762         private Option<ImageInfo> logo = none();
763         private AddonReviewsSummary reviews = addonReviewsSummary(DEFAULT_STARS, DEFAULT_INT);
764         private Option<VendorSummary> vendor = none();
765         private Option<AddonVersionSummary> version = none();
766 
767         private AddonSummaryBuilder()
768         {
769             links.put("alternate", some(WEB_TYPE), DEFAULT_URI);
770             links.put("vendor", DEFAULT_URI);
771         }
772         
773         public AddonSummary build()
774         {
775             AddonSummary ret = new AddonSummary();
776             ret._links = links.build();
777             ret._embedded = new AddonSummary.Embedded();
778             ret._embedded.categories = categories;
779             ret._embedded.distribution = distribution;
780             ret._embedded.logo = logo;
781             ret._embedded.reviews = reviews;
782             ret._embedded.vendor = vendor;
783             ret._embedded.version = version;
784             ret.cloudFreeUsers = cloudFreeUsers;
785             ret.key = key;
786             ret.name = name;
787             ret.status = status;
788             ret.summary = summary;
789             return validateInstance(ret);
790         }
791 
792         public AddonSummaryBuilder key(String key)
793         {
794             this.key = key;
795             return this;
796         }
797 
798         public AddonSummaryBuilder name(String name)
799         {
800             this.name = name;
801             return this;
802         }
803 
804         public AddonSummaryBuilder status(AddonStatus status)
805         {
806             this.status = status;
807             return this;
808         }
809         
810         public AddonSummaryBuilder summary(Option<String> summary)
811         {
812             this.summary = checkNotNull(summary);
813             return this;
814         }
815 
816         public AddonSummaryBuilder cloudFreeUsers(Option<Integer> cloudFreeUsers)
817         {
818             this.cloudFreeUsers = checkNotNull(cloudFreeUsers);
819             return this;
820         }
821 
822         public AddonSummaryBuilder categories(Iterable<AddonCategorySummary> categories)
823         {
824             this.categories = ImmutableList.copyOf(categories);
825             links.put("categories", flatten(transform(categories, EntityFunctions.<AddonCategorySummary>selfUri())));
826             return this;
827         }
828 
829         public AddonSummaryBuilder distribution(AddonDistributionSummary distribution)
830         {
831             this.distribution = distribution;
832             return this;
833         }
834 
835         public AddonSummaryBuilder logo(Option<ImageInfo> logo)
836         {
837             this.logo = logo;
838             links.put("logo", logo.flatMap(EntityFunctions.<ImageInfo>selfUri()));
839             return this;
840         }
841 
842         public AddonSummaryBuilder reviews(AddonReviewsSummary reviews)
843         {
844             this.reviews = reviews;
845             return this;
846         }
847 
848         public AddonSummaryBuilder vendor(Option<VendorSummary> vendor)
849         {
850             this.vendor = vendor;
851             links.put("vendor", vendor.flatMap(EntityFunctions.<VendorSummary>selfUri()));
852             return this;
853         }
854 
855         public AddonSummaryBuilder version(Option<AddonVersionSummary> version)
856         {
857             this.version = version;
858             return this;
859         }
860     }
861     
862     public static class AddonVersionBuilder extends BuilderWithLinks<AddonVersionBuilder>
863         implements SafeBuilder<AddonVersion>
864     {
865         private ModelBuilders.AddonVersionBuilder builder;
866         private Option<ArtifactInfo> artifactInfo = none();
867         private ImmutableList<AddonCategorySummary> functionalCategories = ImmutableList.of();
868         private boolean autoUpdateAllowed = false;
869         private boolean cloud = false;
870         private boolean dataCenter = false;
871         private boolean connect = false;
872         private Map<String, URI> legacyLinks = new HashMap<String, URI>();
873         private boolean server = true;
874         private Option<ImmutableList<ConnectScope>> scopes = none();
875         
876         private AddonVersionBuilder()
877         {
878             builder = ModelBuilders.addonVersion();
879             builder.name(DEFAULT_STRING);
880             builder.buildNumber(DEFAULT_INT);
881             builder.paymentModel(PaymentModel.FREE);
882             builder.releaseDate(DEFAULT_LOCAL_DATE);
883             builder.status(AddonVersionStatus.PUBLIC);
884         }
885         
886         private AddonVersionBuilder(AddonVersion v)
887         {
888             builder = ModelBuilders.addonVersion(v);
889             artifactInfo = v.getArtifactInfo();
890             autoUpdateAllowed = v.isAutoUpdateAllowed();
891             cloud = v.isCloud();
892             connect = v.isConnect();
893             dataCenter = v.isDataCenterCompatible();
894             server = v.isServer();
895             scopes = v.isConnect() ? some(ImmutableList.copyOf(v.getConnectScopes())) :
896                 Option.<ImmutableList<ConnectScope>>none();
897         }
898         
899         public AddonVersion build()
900         {
901             builder.addLinks(this.links.build());
902 
903             Links ls = builder.links.build();
904             Option<ArtifactInfo> a = artifactInfo;
905             if (!a.isDefined())
906             {
907                 for (URI artifactUri: ls.getUri("artifact"))
908                 {
909                     a = some(artifactInfo(artifactUri, this.connect));
910                 }
911             }
912 
913             AddonVersion v = safeBuild(builder);
914             v._embedded.artifact = a;
915             v._embedded.functionalCategories = functionalCategories;
916             v.deployment.autoUpdateAllowed = autoUpdateAllowed;
917             v.deployment.cloud = cloud;
918             v.deployment.connect = connect;
919             v.deployment.dataCenter = dataCenter;
920             v.deployment.server = server;
921             v.deployment.permissions = scopes;
922             if (!legacyLinks.isEmpty())
923             {
924                 AddonVersion.LegacyProperties legacy = new AddonVersion.LegacyProperties();
925                 legacy.vendorLinks = ImmutableMap.copyOf(legacyLinks);
926                 v.legacy = some(legacy);
927             }
928             return v;
929         }
930         
931         public AddonVersionBuilder artifact(Option<ArtifactInfo> artifact)
932         {
933             this.artifactInfo = checkNotNull(artifact);
934             links.put("artifact", artifact.flatMap(EntityFunctions.<ArtifactInfo>selfUri()));
935             return this;
936         }
937         
938         public AddonVersionBuilder artifactUri(Option<URI> artifactUri)
939         {
940             links.put("artifact", artifactUri);
941             this.artifactInfo = none();
942             return this;
943         }
944         
945         public AddonVersionBuilder autoUpdateAllowed(boolean flag)
946         {
947             this.autoUpdateAllowed = flag;
948             return this;
949         }
950         
951         public AddonVersionBuilder buildNumber(int buildNumber)
952         {
953             builder.buildNumber(buildNumber);
954             return this;
955         }
956 
957         public AddonVersionBuilder cloud(boolean flag)
958         {
959             this.cloud = flag;
960             return this;
961         }
962         
963         public AddonVersionBuilder connect(boolean flag)
964         {
965             this.connect = flag;
966             return this;
967         }
968         
969         public AddonVersionBuilder dataCenter(boolean dataCenter)
970         {
971             this.dataCenter = dataCenter;
972             return this;
973         }
974 
975         public AddonVersionBuilder functionalCategories(Iterable<AddonCategorySummary> categories)
976         {
977             this.functionalCategories = ImmutableList.copyOf(categories);
978             builder.links.put("categories", flatten(transform(categories, EntityFunctions.<AddonCategorySummary>selfUri())));
979             return this;
980         }
981 
982         public AddonVersionBuilder name(String name)
983         {
984             builder.name(name);
985             return this;
986         }
987         
988         public AddonVersionBuilder status(AddonVersionStatus status)
989         {
990             builder.status(status);
991             return this;
992         }
993         
994         public AddonVersionBuilder paymentModel(PaymentModel paymentModel)
995         {
996             builder.paymentModel(paymentModel);
997             return this;
998         }
999         
1000         public AddonVersionBuilder releaseDate(LocalDate releaseDate)
1001         {
1002             builder.releaseDate(releaseDate);
1003             return this;
1004         }
1005         
1006         public AddonVersionBuilder releasedBy(Option<String> releasedBy)
1007         {
1008             builder.releasedBy(releasedBy);
1009             return this;
1010         }
1011         
1012         public AddonVersionBuilder beta(boolean flag)
1013         {
1014             builder.beta(flag);
1015             return this;
1016         }
1017 
1018         public AddonVersionBuilder supported(boolean flag)
1019         {
1020             builder.supported(flag);
1021             return this;
1022         }
1023         
1024         public AddonVersionBuilder server(boolean flag)
1025         {
1026             this.server = flag;
1027             return this;
1028         }
1029         
1030         public AddonVersionBuilder highlights(Iterable<Highlight> highlights)
1031         {
1032             builder.highlights(highlights);
1033             return this;
1034         }
1035         
1036         public AddonVersionBuilder screenshots(Iterable<Screenshot> screenshots)
1037         {
1038             builder.screenshots(screenshots);
1039             return this;
1040         }
1041         
1042         public AddonVersionBuilder youtubeId(Option<String> youtubeId)
1043         {
1044             builder.youtubeId(youtubeId);
1045             return this;
1046         }
1047         
1048         public AddonVersionBuilder compatibilities(Iterable<VersionCompatibility> compatibilities)
1049         {
1050             builder.compatibilities(compatibilities);
1051             return this;
1052         }
1053 
1054         public AddonVersionBuilder staticAddon(boolean staticAddon)
1055         {
1056             builder.staticAddon(staticAddon);
1057             return this;
1058         }
1059 
1060         public AddonVersionBuilder deployable(boolean deployable)
1061         {
1062             builder.deployable(deployable);
1063             return this;
1064         }
1065 
1066         public AddonVersionBuilder releaseSummary(Option<String> releaseSummary)
1067         {
1068             builder.releaseSummary(releaseSummary);
1069             return this;
1070         }
1071         
1072         public AddonVersionBuilder moreDetails(Option<HtmlString> moreDetails)
1073         {
1074             builder.moreDetails(moreDetails);
1075             return this;
1076         }
1077         
1078         public AddonVersionBuilder releaseNotes(Option<HtmlString> releaseNotes)
1079         {
1080             builder.releaseNotes(releaseNotes);
1081             return this;
1082         }
1083 
1084         public AddonVersionBuilder scopes(Iterable<ConnectScope> scopes)
1085         {
1086             this.scopes = some(ImmutableList.copyOf(scopes));
1087             return this;
1088         }
1089         
1090         public AddonVersionBuilder externalLinkUri(AddonVersionExternalLinkType type, Option<URI> uri)
1091         {
1092             if (type.canSetForNewAddonVersions())
1093             {
1094                 builder.externalLinkUri(type, uri);
1095             }
1096             else
1097             {
1098                 legacyLinks.remove(type.getKey());
1099                 for (URI u: uri)
1100                 {
1101                     legacyLinks.put(type.getKey(), u);
1102                 }
1103             }
1104             return this;
1105         }
1106     }
1107     
1108     public static class AddonVersionSummaryBuilder extends BuilderWithLinks<AddonVersionSummaryBuilder>
1109         implements SafeBuilder<AddonVersionSummary>
1110     {
1111         private Option<URI> artifactUri = none();
1112         private ImmutableList<AddonCategorySummary> functionalCategories = ImmutableList.of();
1113         private String name = DEFAULT_STRING;
1114         private AddonVersionStatus status = AddonVersionStatus.PUBLIC;
1115         private PaymentModel paymentModel = PaymentModel.FREE;
1116         private LocalDate releaseDate = DEFAULT_LOCAL_DATE;
1117         private Option<String> releasedBy = none();
1118         private boolean beta = false;
1119         private boolean supported = false;
1120         private boolean staticAddon = false;
1121         private boolean deployable = false;
1122         private boolean autoUpdateAllowed = false;
1123         private boolean cloud = false;
1124         private boolean connect = false;
1125         private boolean dataCenter = false;
1126         private boolean server = false;
1127         private Option<ImmutableList<ConnectScope>> scopes = none();
1128         
1129         public AddonVersionSummary build()
1130         {
1131             AddonVersionSummary ret = new AddonVersionSummary();
1132             ret._links = links.build();
1133             ret._embedded = new AddonVersionSummary.Embedded();
1134             ret._embedded.artifact = none();
1135             ret._embedded.functionalCategories = functionalCategories;
1136             for (URI u: artifactUri)
1137             {
1138                 ret._embedded.artifact = some(artifactInfo(u, this.connect));
1139             }
1140             ret.deployable = deployable;
1141             ret.deployment = new DeploymentProperties();
1142             ret.deployment.autoUpdateAllowed = autoUpdateAllowed;
1143             ret.deployment.cloud = cloud;
1144             ret.deployment.connect = connect;
1145             ret.deployment.dataCenter = dataCenter;
1146             ret.deployment.permissions = scopes; 
1147             ret.deployment.server = server;
1148             ret.name = some(name);
1149             ret.paymentModel = paymentModel;
1150             ret.release = new AddonVersionBase.ReleaseProperties();
1151             ret.release.beta = beta;
1152             ret.release.date = releaseDate;
1153             ret.release.releasedBy = releasedBy;
1154             ret.release.supported = supported;
1155             ret.staticAddon = staticAddon;
1156             ret.status = status;
1157             return validateInstance(ret);
1158         }
1159         
1160         public AddonVersionSummaryBuilder artifactUri(Option<URI> artifactUri)
1161         {
1162             this.artifactUri = artifactUri;
1163             return this;
1164         }
1165 
1166         public AddonVersionSummaryBuilder functionalCategories(Iterable<AddonCategorySummary> categories)
1167         {
1168             this.functionalCategories = ImmutableList.copyOf(categories);
1169             links.put("categories", flatten(transform(categories, EntityFunctions.<AddonCategorySummary>selfUri())));
1170             return this;
1171         }
1172 
1173         public AddonVersionSummaryBuilder name(String name)
1174         {
1175             this.name = name;
1176             return this;
1177         }
1178         
1179         public AddonVersionSummaryBuilder status(AddonVersionStatus status)
1180         {
1181             this.status = status;
1182             return this;
1183         }
1184         
1185         public AddonVersionSummaryBuilder paymentModel(PaymentModel paymentModel)
1186         {
1187             this.paymentModel = paymentModel;
1188             return this;
1189         }
1190         
1191         public AddonVersionSummaryBuilder releaseDate(LocalDate releaseDate)
1192         {
1193             this.releaseDate = checkNotNull(releaseDate);
1194             return this;
1195         }
1196 
1197         public AddonVersionSummaryBuilder releasedBy(Option<String> releasedBy)
1198         {
1199             this.releasedBy = checkNotNull(releasedBy);
1200             return this;
1201         }
1202 
1203         public AddonVersionSummaryBuilder beta(boolean beta)
1204         {
1205             this.beta = beta;
1206             return this;
1207         }
1208         
1209         public AddonVersionSummaryBuilder supported(boolean supported)
1210         {
1211             this.supported = supported;
1212             return this;
1213         }
1214         
1215         public AddonVersionSummaryBuilder staticAddon(boolean staticAddon)
1216         {
1217             this.staticAddon = staticAddon;
1218             return this;
1219         }
1220 
1221         public AddonVersionSummaryBuilder autoUpdateAllowed(boolean autoUpdateAllowed)
1222         {
1223             this.autoUpdateAllowed = autoUpdateAllowed;
1224             return this;
1225         }
1226 
1227         public AddonVersionSummaryBuilder deployable(boolean deployable)
1228         {
1229             this.deployable = deployable;
1230             return this;
1231         }
1232 
1233         public AddonVersionSummaryBuilder cloud(boolean cloud)
1234         {
1235             this.cloud = cloud;
1236             return this;
1237         }
1238 
1239         public AddonVersionSummaryBuilder connect(boolean connect)
1240         {
1241             this.connect = connect;
1242             return this;
1243         }
1244 
1245         public AddonVersionSummaryBuilder dataCenter(boolean dataCenter)
1246         {
1247             this.dataCenter = dataCenter;
1248             return this;
1249         }
1250 
1251         public AddonVersionSummaryBuilder server(boolean server)
1252         {
1253             this.server = server;
1254             return this;
1255         }
1256         
1257         public AddonVersionSummaryBuilder scopes(Iterable<ConnectScope> scopes)
1258         {
1259             this.scopes = some(ImmutableList.copyOf(scopes));
1260             return this;
1261         }
1262     }
1263     
1264     public static class ApplicationBuilder extends BuilderWithLinks<ApplicationBuilder>
1265         implements SafeBuilder<Application>
1266     {
1267         private ApplicationKey key = ApplicationKey.valueOf(DEFAULT_STRING);
1268         private String name = DEFAULT_STRING;
1269         private ApplicationStatus status = ApplicationStatus.PUBLISHED;
1270         private String introduction = DEFAULT_STRING;
1271         private Option<Integer> cloudFreeUsers = none();
1272         private Application.CompatibilityUpdateMode compatibilityMode = Application.CompatibilityUpdateMode.MINOR_VERSIONS;
1273         private String description = DEFAULT_STRING;
1274         private Option<URI> downloadPage = none();
1275         private URI learnMore = DEFAULT_ABSOLUTE_URI;
1276         
1277         private ApplicationBuilder()
1278         {
1279         }
1280         
1281         private ApplicationBuilder(Application from)
1282         {
1283             links.put(from.getLinks());
1284             key = from.getKey();
1285             name = from.getName();
1286             status = from.getStatus();
1287             introduction = from.getIntroduction();
1288             cloudFreeUsers = from.getCloudFreeUsers();
1289             compatibilityMode = from.getCompatibilityUpdateMode();
1290             description = from.getDescription();
1291             downloadPage = from.getDownloadPageUri();
1292             learnMore = from.getLearnMoreUri();
1293         }
1294         
1295         public Application build()
1296         {
1297             Application a = new Application();
1298             a._links = links.build();
1299             a.key = key;
1300             a.name = name;
1301             a.status = status;
1302             a.introduction = introduction;
1303             a.cloudFreeUsers = cloudFreeUsers;
1304             
1305             a.atlassianConnectSupport = new Application.ConnectSupport();
1306             a.atlassianConnectSupport.cloud = false;
1307             a.atlassianConnectSupport.server = false;
1308             a.compatibilityMode = compatibilityMode;
1309             a.details = new Application.Details();
1310             a.details.description = description;
1311             a.details.downloadPage = downloadPage;
1312             a.details.learnMore = learnMore;
1313             a.hostingSupport = new Application.HostingSupport();
1314             a.hostingSupport.cloud = new Application.HostingModelSupport();
1315             a.hostingSupport.cloud.enabled = true;
1316             a.hostingSupport.server = new Application.HostingModelSupport();
1317             a.hostingSupport.server.enabled = true;
1318             
1319             return validateInstance(a);
1320         }
1321 
1322         public ApplicationBuilder key(ApplicationKey key)
1323         {
1324             this.key = checkNotNull(key);
1325             return this;
1326         }
1327 
1328         public ApplicationBuilder name(String name)
1329         {
1330             this.name = checkNotNull(name);
1331             return this;
1332         }
1333         
1334         public ApplicationBuilder introduction(String introduction)
1335         {
1336             this.introduction = checkNotNull(introduction);
1337             return this;
1338         }
1339 
1340         public ApplicationBuilder cloudFreeUsers(Option<Integer> cloudFreeUsers)
1341         {
1342             this.cloudFreeUsers = checkNotNull(cloudFreeUsers);
1343             return this;
1344         }
1345 
1346         public ApplicationBuilder status(ApplicationStatus status)
1347         {
1348             this.status = checkNotNull(status);
1349             return this;
1350         }
1351     }
1352 
1353     public static class ApplicationVersionBuilder extends BuilderWithLinks<ApplicationVersionBuilder>
1354         implements SafeBuilder<ApplicationVersion>
1355     {
1356         private ModelBuilders.ApplicationVersionBuilder builder;
1357         
1358         private ApplicationVersionBuilder()
1359         {
1360             builder = ModelBuilders.applicationVersion();
1361             builder.name(DEFAULT_STRING);
1362             builder.buildNumber(DEFAULT_INT);
1363             builder.releaseDate(DEFAULT_LOCAL_DATE);
1364             builder.status(ApplicationVersionStatus.PUBLISHED);
1365         }
1366 
1367         private ApplicationVersionBuilder(ApplicationVersion v)
1368         {
1369             builder = ModelBuilders.applicationVersion(v);
1370         }
1371         
1372         public ApplicationVersion build()
1373         {
1374             builder.addLinks(links.build());
1375             return safeBuild(builder);
1376         }
1377         
1378         public ApplicationVersionBuilder buildNumber(int buildNumber)
1379         {
1380             builder.buildNumber(buildNumber);
1381             return this;
1382         }
1383         
1384         public ApplicationVersionBuilder name(String name)
1385         {
1386             builder.name(name);
1387             return this;
1388         }
1389         
1390         public ApplicationVersionBuilder releaseDate(LocalDate releaseDate)
1391         {
1392             builder.releaseDate(releaseDate);
1393             return this;
1394         }
1395         
1396         public ApplicationVersionBuilder status(ApplicationVersionStatus status)
1397         {
1398             builder.status(status);
1399             return this;
1400         }
1401     }
1402     
1403     public static class ImageInfoBuilder implements SafeBuilder<ImageInfo>
1404     {
1405         private LinksBuilder links = links();
1406 
1407         private ImageInfoBuilder()
1408         {
1409             links.put("image", DEFAULT_URI);
1410             links.put("self", DEFAULT_URI);
1411         }
1412         
1413         public ImageInfo build()
1414         {
1415             ImageInfo i = new ImageInfo();
1416             i._links = links.build();
1417             return validateInstance(i);
1418         }
1419         
1420         public ImageInfoBuilder setImageUri(URI uri)
1421         {
1422             links.put("image", uri);
1423             return this;
1424         }
1425         
1426         public ImageInfoBuilder setResourceUri(URI uri)
1427         {
1428             links.put("self", uri);
1429             return this;
1430         }
1431         
1432         public ImageInfoBuilder setImageUri(ImageInfo.Size size, ImageInfo.Resolution resolution, URI uri)
1433         {
1434             links.put(ImageInfo.getImageLinkRel(size, resolution), uri);
1435             return this;
1436         }
1437     }
1438 
1439     public static class ProductBuilder extends BuilderWithLinks<ProductBuilder>
1440     {
1441         private Option<ImageInfo> logo = none();
1442         private Option<ImageInfo> titleLogo = none();
1443         private Option<ProductVersion> version = none();
1444         private String key = DEFAULT_STRING;
1445         private String name = DEFAULT_STRING;
1446         private String summary = DEFAULT_STRING;
1447         
1448         public Product build()
1449         {
1450             Product ret = new Product();
1451             ret._links = links.build();
1452             ret._embedded = new Product.Embedded();
1453             ret._embedded.logo = logo;
1454             ret._embedded.titleLogo = titleLogo;
1455             ret._embedded.version = version;
1456             ret.key = key;
1457             ret.name = name;
1458             ret.summary = summary;
1459             return validateInstance(ret);
1460         }
1461         
1462         public ProductBuilder downloadsPageUri(Option<URI> uri)
1463         {
1464             links.put("downloads", uri);
1465             return this;
1466         }
1467         
1468         public ProductBuilder key(String key)
1469         {
1470             this.key = key;
1471             return this;
1472         }
1473         
1474         public ProductBuilder logo(Option<ImageInfo> logo)
1475         {
1476             this.logo = logo;
1477             return this;
1478         }
1479         
1480         public ProductBuilder name(String name)
1481         {
1482             this.name = name;
1483             return this;
1484         }
1485         
1486         public ProductBuilder summary(String summary)
1487         {
1488             this.summary = summary;
1489             return this;
1490         }
1491         
1492         public ProductBuilder titleLogo(Option<ImageInfo> titleLogo)
1493         {
1494             this.titleLogo = titleLogo;
1495             return this;
1496         }
1497         
1498         public ProductBuilder version(Option<ProductVersion> version)
1499         {
1500             this.version = version;
1501             return this;
1502         }
1503     }
1504     
1505     public static class ProductVersionBuilder extends BuilderWithLinks<ProductVersionBuilder>
1506     {
1507         private String name = DEFAULT_STRING;
1508         private int buildNumber = DEFAULT_INT;
1509         private Option<URI> artifactUri = none();
1510         private PaymentModel paymentModel = PaymentModel.FREE;
1511         private LocalDate releaseDate = DEFAULT_LOCAL_DATE;
1512         private ImmutableList<VersionCompatibility> compatibilities = ImmutableList.of();
1513         
1514         public ProductVersion build()
1515         {
1516             ProductVersion ret = new ProductVersion();
1517             ret._links = links.build();
1518             ret._embedded = new ProductVersion.Embedded();
1519             ret._embedded.artifact = none();
1520             ret.buildNumber = buildNumber;
1521             ret.name = name;
1522             ret.paymentModel = paymentModel;
1523             ret.releaseDate = releaseDate;
1524             ret.compatibilities = compatibilities;
1525             for (URI u: artifactUri)
1526             {
1527                 ret._embedded.artifact = some(artifactInfo(u, false));
1528             }
1529             return validateInstance(ret);
1530         }
1531         
1532         public ProductVersionBuilder name(String name)
1533         {
1534             this.name = name;
1535             return this;
1536         }
1537         
1538         public ProductVersionBuilder buildNumber(int buildNumber)
1539         {
1540             this.buildNumber = buildNumber;
1541             return this;
1542         }
1543         
1544         public ProductVersionBuilder artifactUri(Option<URI> artifactUri)
1545         {
1546             this.artifactUri = artifactUri;
1547             return this;
1548         }
1549         
1550         public ProductVersionBuilder learnMoreUri(Option<URI> learnMoreUri)
1551         {
1552             for (URI u: learnMoreUri)
1553             {
1554                 this.links.put("view", u);
1555             }
1556             if (!learnMoreUri.isDefined())
1557             {
1558                 this.links.remove("view");
1559             }
1560             return this;
1561         }
1562         
1563         public ProductVersionBuilder paymentModel(PaymentModel paymentModel)
1564         {
1565             this.paymentModel = checkNotNull(paymentModel);
1566             return this;
1567         }
1568         
1569         public ProductVersionBuilder releaseDate(LocalDate releaseDate)
1570         {
1571             this.releaseDate = checkNotNull(releaseDate);
1572             return this;
1573         }
1574         
1575         public ProductVersionBuilder compatibilities(Iterable<VersionCompatibility> compatibilities)
1576         {
1577             this.compatibilities = ImmutableList.copyOf(compatibilities);
1578             return this;
1579         }
1580     }
1581 
1582     public static class VendorBuilder extends BuilderWithLinks<VendorBuilder> implements SafeBuilder<Vendor>
1583     {
1584         private ModelBuilders.VendorBuilder builder;
1585         private Option<ImageInfo> logo = none();
1586         private Option<String> verifiedStatus = none();
1587         
1588         private VendorBuilder()
1589         {
1590             builder = ModelBuilders.vendor();
1591             builder.name(DEFAULT_STRING);
1592             builder.email(DEFAULT_STRING);
1593         }
1594         
1595         private VendorBuilder(Vendor from)
1596         {
1597             builder = ModelBuilders.vendor(from);
1598             logo = from.getLogo();
1599         }
1600 
1601         public Vendor build()
1602         {
1603             builder.addLinks(links.build());
1604             Vendor v = safeBuild(builder);
1605             v._embedded.logo = logo;
1606             v.verifiedStatus = verifiedStatus;
1607             return v;
1608         }
1609         
1610         public VendorBuilder logo(Option<ImageInfo> logo)
1611         {
1612             links.put("logo", logo.flatMap(EntityFunctions.selfUri()));
1613             this.logo = logo;
1614             return this;
1615         }
1616 
1617         public VendorBuilder name(String name)
1618         {
1619             builder.name(name);
1620             return this;
1621         }
1622 
1623         public VendorBuilder description(Option<String> description)
1624         {
1625             builder.description(description);
1626             return this;
1627         }
1628 
1629         public VendorBuilder address(Option<Address> address)
1630         {
1631             builder.address(address);
1632             return this;
1633         }
1634         
1635         public VendorBuilder email(String email)
1636         {
1637             builder.email(email);
1638             return this;
1639         }
1640         
1641         public VendorBuilder phone(Option<String> phone)
1642         {
1643             builder.phone(phone);
1644             return this;
1645         }
1646 
1647         public VendorBuilder otherContactDetails(Option<String> otherContactDetails)
1648         {
1649             builder.otherContactDetails(otherContactDetails);
1650             return this;
1651         }
1652 
1653         public VendorBuilder externalLinkUri(VendorExternalLinkType type, Option<URI> uri)
1654         {
1655             builder.externalLinkUri(type, uri);
1656             return this;
1657         }
1658         
1659         public VendorBuilder verifiedStatus(Option<String> verifiedStatus)
1660         {
1661             this.verifiedStatus = checkNotNull(verifiedStatus);
1662             return this;
1663         }
1664     }
1665     
1666     public static class VendorSummaryBuilder extends BuilderWithLinks<VendorSummaryBuilder>
1667     {
1668         private Option<ImageInfo> logo = none();
1669         private String name = DEFAULT_STRING;
1670         private Option<String> verifiedStatus = none();
1671 
1672         private VendorSummaryBuilder()
1673         {
1674             links.put("alternate", some(WEB_TYPE), DEFAULT_URI);
1675         }
1676 
1677         public VendorSummary build()
1678         {
1679             VendorSummary ret = new VendorSummary();
1680             ret._links = links.build();
1681             ret._embedded = new VendorSummary.Embedded();
1682             ret._embedded.logo = logo;
1683             ret.name = name;
1684             ret.verifiedStatus = verifiedStatus;
1685             return validateInstance(ret);
1686         }
1687         
1688         public VendorSummaryBuilder logo(Option<ImageInfo> logo)
1689         {
1690             this.logo = checkNotNull(logo);
1691             return this;
1692         }
1693 
1694         public VendorSummaryBuilder name(String name)
1695         {
1696             this.name = checkNotNull(name);
1697             return this;
1698         }
1699 
1700         public VendorSummaryBuilder verifiedStatus(Option<String> verifiedStatus)
1701         {
1702             this.verifiedStatus = checkNotNull(verifiedStatus);
1703             return this;
1704         }
1705     }
1706 
1707     public static <T> T safeBuild(ModelBuilders.UnsafeBuilder<T> builder)
1708     {
1709         try
1710         {
1711             return builder.build();
1712         }
1713         catch (ModelBuilders.InvalidModelException e)
1714         {
1715             throw new RuntimeException(e);
1716         }
1717     }
1718 }