View Javadoc

1   package com.atlassian.marketplace.client.api;
2   
3   import com.atlassian.fugue.Option;
4   
5   import com.google.common.collect.ImmutableList;
6   
7   import static com.atlassian.fugue.Option.none;
8   import static com.atlassian.marketplace.client.api.QueryProperties.describeOptBoolean;
9   import static com.atlassian.marketplace.client.api.QueryProperties.describeOptEnum;
10  import static com.atlassian.marketplace.client.api.QueryProperties.describeParams;
11  import static com.atlassian.marketplace.client.api.QueryProperties.describeValues;
12  import static com.google.common.base.Preconditions.checkNotNull;
13  
14  /**
15   * Encapsulates search parameters that can be passed to {@link Addons} to determine what
16   * subset of add-on listings you are interested in and/or what information should be included
17   * in the results.
18   * @since 2.0.0
19   */
20  public final class AddonQuery implements QueryProperties.AccessToken,
21          QueryProperties.ApplicationCriteria,
22          QueryProperties.Bounds,
23          QueryProperties.Cost,
24          QueryProperties.Hosting,
25          QueryProperties.WithVersion
26  {
27      private static final AddonQuery DEFAULT_QUERY = builder().build();
28      
29      private final Option<String> accessToken;
30      private final QueryBuilderProperties.ApplicationCriteriaHelper app;
31      private final QueryBounds bounds;
32      private final Iterable<String> categoryNames;
33      private final Option<Cost> cost;
34      private final boolean forThisUserOnly;
35      private final Option<HostingType> hosting;
36      private final Option<IncludeHiddenType> includeHidden;
37      private final boolean includePrivate;
38      private final Option<String> label;
39      private final Option<TreatPartlyFreeAs> treatPartlyFreeAs;
40      private final Option<String> searchText;
41      private final Option<View> view;
42      private final boolean withVersion;
43      
44      /**
45       * Returns a new {@link Builder} for constructing an AddonQuery.
46       */
47      public static Builder builder()
48      {
49          return new Builder();
50      }
51  
52      /**
53       * Returns an {@link AddonQuery} with no criteria, which will match any available add-on.
54       */
55      public static AddonQuery any()
56      {
57          return DEFAULT_QUERY;
58      }
59      
60      /**
61       * Returns a new {@link Builder} for constructing an {@link AddonQuery} based on an existing {@link AddonQuery}.
62       */
63      public static Builder builder(AddonQuery query)
64      {
65          Builder builder = builder()
66              .application(query.getApplication())
67              .appBuildNumber(query.getAppBuildNumber())
68              .categoryNames(query.getCategoryNames())
69              .cost(query.getCost())
70              .forThisUserOnly(query.isForThisUserOnly())
71              .hosting(query.getHosting())
72              .includeHidden(query.getIncludeHidden())
73              .includePrivate(query.isIncludePrivate())
74              .label(query.getLabel())
75              .treatPartlyFreeAs(query.getTreatPartlyFreeAs())
76              .view(query.getView())
77              .withVersion(query.isWithVersion())
78              .bounds(query.getBounds())
79              .searchText(query.getSearchText());
80  
81          return builder;
82      }
83  
84      private AddonQuery(Builder builder)
85      {
86          accessToken = builder.accessToken;
87          app = builder.app;
88          bounds = builder.bounds;
89          categoryNames = builder.categoryNames;
90          cost = builder.cost;
91          forThisUserOnly = builder.forThisUserOnly;
92          hosting = builder.hosting;
93          includeHidden = builder.includeHidden;
94          includePrivate = builder.includePrivate;
95          label = builder.label;
96          searchText = builder.searchText;
97          treatPartlyFreeAs = builder.treatPartlyFreeAs;
98          view = builder.view;
99          withVersion = builder.withVersion;
100     }
101     
102     @Override
103     public Option<String> getAccessToken()
104     {
105         return accessToken;
106     }
107     
108     @Override
109     public Option<ApplicationKey> getApplication()
110     {
111         return app.application;
112     }
113     
114     @Override
115     public Option<Integer> getAppBuildNumber()
116     {
117         return app.appBuildNumber;
118     }
119     
120     /**
121      * The list of add-on category names, if any, that the client has specified to restrict
122      * the query results.
123      * @see Builder#categoryNames(Iterable)
124      */
125     public Iterable<String> getCategoryNames()
126     {
127         return categoryNames;
128     }
129     
130     @Override
131     public Option<Cost> getCost()
132     {
133         return cost;
134     }
135 
136     /**
137      * True if the client is querying only add-ons that are associated with the current
138      * authenticated user's vendor(s).
139      * @see Builder#forThisUserOnly(boolean)
140      */
141     public boolean isForThisUserOnly()
142     {
143         return forThisUserOnly;
144     }
145 
146     /**
147      * The subset of normally hidden add-ons, if any, that the client has specified to include
148      * in the query results.
149      * @see Builder#includeHidden(Option)
150      */
151     public Option<IncludeHiddenType> getIncludeHidden()
152     {
153         return includeHidden;
154     }
155     
156     /**
157      * True if the client is querying private add-ons as well as public add-ons.
158      * @see Builder#includePrivate(boolean)
159      */
160     public boolean isIncludePrivate()
161     {
162         return includePrivate;
163     }
164     
165     @Override
166     public Option<HostingType> getHosting()
167     {
168         return hosting;
169     }
170     
171     /**
172      * The marketing label string, if any, that the client has specified to restrict the query results.
173      * @see Builder#label(Option)
174      */
175     public Option<String> getLabel()
176     {
177         return label;
178     }
179     
180     /**
181      * The {@link TreatPartlyFreeAs} value, if any, that the client has specified to determine how
182      * free-tier listings will be treated in the query.
183      * @see Builder#treatPartlyFreeAs(Option)
184      */
185     public Option<TreatPartlyFreeAs> getTreatPartlyFreeAs()
186     {
187         return treatPartlyFreeAs;
188     }
189 
190     /**
191      * The search text, if any, that the client has specified for the query.
192      * @see Builder#searchText(Option)
193      */
194     public Option<String> getSearchText()
195     {
196         return searchText;
197     }
198     
199     /**
200      * The {@link View} value, if any, that the client has specified as a filter and/or sort order
201      * for the query.
202      * @see Builder#view(Option)
203      */
204     public Option<View> getView()
205     {
206         return view;
207     }
208     
209     @Override
210     public boolean isWithVersion()
211     {
212         return withVersion;
213     }
214     
215     @Override
216     public QueryBounds getBounds()
217     {
218         return bounds;
219     }
220 
221     @SuppressWarnings("unchecked")
222     @Override
223     public String toString()
224     {
225         return describeParams("AddonQuery", 
226             describeValues("accessToken", accessToken),
227             app.describe(),
228             describeValues("categoryNames", categoryNames),
229             describeOptEnum("cost", cost),
230             describeOptBoolean("forThisUserOnly", forThisUserOnly),
231             describeOptEnum("hosting", hosting),
232             describeOptEnum("includeHidden", includeHidden),
233             describeOptBoolean("includePrivate", includePrivate),
234             describeValues("label", label),
235             describeValues("searchText", searchText),
236             describeOptEnum("treatPartlyFreeAs", treatPartlyFreeAs),
237             describeOptEnum("view", view),
238             describeOptBoolean("withVersion", withVersion),
239             bounds.describe()
240         );
241     }
242     
243     @Override
244     public boolean equals(Object other)
245     {
246         return (other instanceof AddonQuery) ? toString().equals(other.toString()) : false;
247     }
248 
249     @Override
250     public int hashCode()
251     {
252         return toString().hashCode();
253     }
254 
255     /**
256      * Builder class for {@link AddonQuery}.  Use {@link AddonQuery#builder()} to create an instance. 
257      */
258     public static class Builder implements QueryBuilderProperties.AccessToken<Builder>,
259         QueryBuilderProperties.ApplicationCriteria<Builder>,
260         QueryBuilderProperties.Bounds<Builder>,
261         QueryBuilderProperties.Cost<Builder>,
262         QueryBuilderProperties.Hosting<Builder>,
263         QueryBuilderProperties.WithVersion<Builder>
264     {
265         private Option<String> accessToken = none();
266         private QueryBuilderProperties.ApplicationCriteriaHelper app = new QueryBuilderProperties.ApplicationCriteriaHelper();
267         private QueryBounds bounds = QueryBounds.defaultBounds();
268         private Iterable<String> categoryNames = ImmutableList.of();
269         private Option<Cost> cost = none();
270         private boolean forThisUserOnly = false;
271         private Option<HostingType> hosting = none();
272         private Option<IncludeHiddenType> includeHidden = none();
273         private boolean includePrivate = false;
274         private Option<String> label = none();
275         private Option<TreatPartlyFreeAs> treatPartlyFreeAs = none();
276         private Option<String> searchText = none();
277         private Option<View> view = none();
278         private boolean withVersion = false;
279         
280         /**
281          * Returns an immutable {@link AddonQuery} based on the current builder properties.
282          */
283         public AddonQuery build()
284         {
285             return new AddonQuery(this);
286         }
287         
288         @Override
289         public Builder accessToken(Option<String> accessToken)
290         {
291             this.accessToken = checkNotNull(accessToken);
292             return this;
293         }
294         
295         @Override
296         public Builder application(Option<ApplicationKey> application)
297         {
298             app = app.application(application);
299             return this;
300         }
301         
302         @Override
303         public Builder appBuildNumber(Option<Integer> appBuildNumber)
304         {
305             app = app.appBuildNumber(appBuildNumber);
306             return this;
307         }
308         
309         /**
310          * Restricts the query to add-ons that belong to one of the specified categories.  An empty list
311          * means there is no such restriction.  To obtain a list of allowable category names, use
312          * {@link AddonCategories}.
313          * @param categoryNames  category names to search for, or an empty {@code Iterable} if you do
314          *   not want to filter by add-on category
315          * @return  the same query builder
316          * @see AddonQuery#getCategoryNames()
317          */
318         public Builder categoryNames(Iterable<String> categoryNames)
319         {
320             this.categoryNames = ImmutableList.copyOf(categoryNames);
321             return this;
322         }
323 
324         @Override
325         public Builder cost(Option<Cost> cost)
326         {
327             this.cost = checkNotNull(cost);
328             return this;
329         }
330         
331         /**
332          * Specifies whether to query only the addons associated with the current authenticated user's vendor(s).
333          * @param forThisUserOnly  true to query only addons associated with the current
334          *   authenticated user; false (the default) to query add-ons from any vendor.
335          * @return  the same query builder
336          * @see AddonQuery#isForThisUserOnly()
337          */
338         public Builder forThisUserOnly(boolean forThisUserOnly)
339         {
340             this.forThisUserOnly = forThisUserOnly;
341             return this;
342         }
343         
344         @Override
345         public Builder hosting(Option<HostingType> hosting)
346         {
347             this.hosting = checkNotNull(hosting);
348             return this;
349         }
350 
351         /**
352          * Specifies whether to include special "hidden" add-ons in the results.  These are not private
353          * listings; they are add-ons that Atlassian has configured to be invisible on the Marketplace site, but
354          * still discoverable from within applications under some circumstances (such as language packs).
355          * @param includeHidden  the type of hidden add-ons to include, or {@link Option#none()} (the default)
356          *   to exclude them all
357          * @return  the same query builder
358          * @see AddonQuery#getIncludeHidden()
359          */
360         public Builder includeHidden(Option<IncludeHiddenType> includeHidden)
361         {
362             this.includeHidden = checkNotNull(includeHidden);
363             return this;
364         }
365         
366         /**
367          * Specifies whether to include private add-ons in the results.  This will only have an effect if you
368          * are authenticated, and you will only be able to see private add-ons that you would be able to access
369          * in the Marketplace site (that is, unless you are a Marketplace administrator, only private add-ons
370          * from your vendor(s) will be accessible).
371          * @param includePrivate  true to include private add-ons; false (the default) to include only public
372          *   add-ons
373          * @return  the same query builder
374          * @see AddonQuery#isIncludePrivate()
375          */
376         public Builder includePrivate(boolean includePrivate)
377         {
378             this.includePrivate = includePrivate;
379             return this;
380         }
381         
382         /**
383          * Restricts the query to add-ons that have been tagged with the specified label string.
384          * This is an internal identifier, not visible on the Marketplace site, that Atlassian
385          * administrators may use to create subsets of add-ons for any purpose. 
386          * @param label  label string to search for, or {@link Option#none()} for no label search
387          * @return  the same query builder
388          * @see AddonQuery#getLabel()
389          */
390         public Builder label(Option<String> label)
391         {
392             this.label = checkNotNull(label);
393             return this;
394         }
395         
396         /**
397          * Specify how partly free, paid via Atlassian add-ons (those with a free tier) should be treated.
398          * By default none is included.
399          *
400          * @param treatPartlyFreeAs how to treat partly free, PvA add-ons in queries
401          * @return  the same query builder
402          */
403         public Builder treatPartlyFreeAs(Option<TreatPartlyFreeAs> treatPartlyFreeAs)
404         {
405             this.treatPartlyFreeAs = treatPartlyFreeAs;
406             return this;
407         }
408 
409         /**
410          * Restricts the query to add-ons that have the specified text somewhere in their name or
411          * description.
412          * @param searchText  text to search for, or {@link Option#none()} for no text search
413          * @return  the same query builder
414          * @see AddonQuery#getSearchText()
415          */
416         public Builder searchText(Option<String> searchText)
417         {
418             this.searchText = checkNotNull(searchText);
419             return this;
420         }
421         
422         /**
423          * Specifies an {@link View} which determines the overall sort order and/or subset of
424          * add-ons to be queried.
425          * @param view  an {@link View} value, or {@link Option#none()} for the default view
426          * @return  the same query builder
427          * @see AddonQuery#getView()
428          */
429         public Builder view(Option<View> view)
430         {
431             this.view = checkNotNull(view);
432             return this;
433         }
434         
435         @Override
436         public Builder withVersion(boolean withVersion)
437         {
438             this.withVersion = withVersion;
439             return this;
440         }
441         
442         @Override
443         public Builder bounds(QueryBounds bounds)
444         {
445             this.bounds = checkNotNull(bounds);
446             return this;
447         }
448     }
449 
450     /**
451      * Constants representing subsets of add-ons that are normally hidden but may still be queried.
452      * @see AddonQuery.Builder#includeHidden(Option)
453      */
454     public enum IncludeHiddenType implements EnumWithKey
455     {
456         /**
457          * Add-ons that do not appear on the Marketplace site, but that are normally discoverable from within
458          * an application (such as language packs), will be included in the query results.
459          */
460         VISIBLE_IN_APP ("visibleInApp"),
461         
462         /**
463          * Add-ons that do not appear on the Marketplace site will be included in the query results,
464          * even if they are not normally discoverable from within an application (for instance, add-ons
465          * that are bundled within an application but may have updates made available via Marketplace).
466          */
467         ALL ("all");
468         
469         private final String key;
470         
471         private IncludeHiddenType(String key)
472         {
473             this.key = key;
474         }
475         
476         @Override
477         public String getKey()
478         {
479             return key;
480         }
481     }
482     
483     /**
484      * Determines how paid-via-Atlassian add-ons with free tiers, such as those where the vendor has opted into the
485      * Cloud free-for-five tier, are treated in queries.
486      * @see AddonQuery.Builder#treatPartlyFreeAs(Option)
487      */
488     public enum TreatPartlyFreeAs implements EnumWithKey
489     {
490         /**
491          * Add-ons with free tiers will be effectively treated as free in queries. An example of when this should be
492          * used is when the application has a Cloud free for X number of users and there are less than or equal to
493          * X active users.
494          */
495         FREE("free"),
496 
497         /**
498          * Add-ons with free tiers will be effectively treated as paid in queries.
499          */
500         PAID("paid");
501 
502         private final String key;
503 
504         private TreatPartlyFreeAs(String key)
505         {
506             this.key = key;
507         }
508 
509         @Override
510         public String getKey()
511         {
512             return key;
513         }
514     }
515 
516     /**
517      * Constants representing preset add-on list views, which may affect both the set of
518      * add-ons being queried and the sort order of the results.
519      * @see AddonQuery.Builder#view(Option)
520      */
521     public enum View implements EnumWithKey
522     {
523         /**
524          * Restricts the query to add-ons made by Atlassian, with the most recently updated add-ons first.
525          */
526         BY_ATLASSIAN ("atlassian"),
527         /**
528          * Restricts the query to a set of add-ons picked by Atlassian staff, with the most recently
529          * updated add-ons first.
530          */
531         FEATURED ("featured"),
532         /**
533          * Query all add-ons, sorted by rating.
534          */
535         HIGHEST_RATED ("highest-rated"),
536         /**
537          * Queries all add-ons, in descending order of total number of downloads.
538          */
539         POPULAR ("popular"),
540         /**
541          * Queries all add-ons, in descending order of modification date.
542          */
543         RECENTLY_UPDATED ("recent"),
544         /**
545          * Queries all Paid-via-Atlassian add-ons, in descending order of gross sales.
546          */
547         TOP_GROSSING ("top-grossing"),
548         /**
549          * Queries all add-ons, in descending order of number of recent downloads.
550          */
551         TRENDING ("trending");
552         
553         private final String key;
554         
555         private View(String key)
556         {
557             this.key = key;
558         }
559         
560         @Override
561         public String getKey()
562         {
563             return key;
564         }
565     }
566 }