diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/Listing.java b/src/main/java/org/eclipsefoundation/marketplace/dto/Listing.java index cbc107c7c80f2b603a6567238a252057df5cdd0a..e70d9fa81f10cf3afebdeded9373962e21c2e652 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/Listing.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/Listing.java @@ -38,11 +38,9 @@ public class Listing extends NodeBase { private boolean foundationMember; @SortableField(name = "installs_count") - @JsonbProperty("installs_count") private long installsTotal; @SortableField(name = "installs_count_recent") - @JsonbProperty("installs_count_recent") private long installsRecent; @SortableField @@ -64,7 +62,7 @@ public class Listing extends NodeBase { private Organization organization; private List<Author> authors; private List<Tag> tags; - private List<SolutionVersion> versions; + private List<ListingVersion> versions; /** * Default constructor, sets lists to empty lists to stop null pointers @@ -180,6 +178,7 @@ public class Listing extends NodeBase { /** * @return the installsTotal */ + @JsonbProperty("installs_count") public long getInstallsTotal() { return installsTotal; } @@ -187,6 +186,7 @@ public class Listing extends NodeBase { /** * @param installsTotal the installsTotal to set */ + @JsonbTransient public void setInstallsTotal(long installsTotal) { this.installsTotal = installsTotal; } @@ -194,6 +194,7 @@ public class Listing extends NodeBase { /** * @return the installsRecent */ + @JsonbProperty("installs_count_recent") public long getInstallsRecent() { return installsRecent; } @@ -201,6 +202,7 @@ public class Listing extends NodeBase { /** * @param installsRecent the installsRecent to set */ + @JsonbTransient public void setInstallsRecent(long installsRecent) { this.installsRecent = installsRecent; } @@ -215,7 +217,6 @@ public class Listing extends NodeBase { /** * @param favoriteCount the favoriteCount to set */ - @JsonbTransient public void setFavoriteCount(long favoriteCount) { this.favoriteCount = favoriteCount; } @@ -368,14 +369,15 @@ public class Listing extends NodeBase { /** * @return the versions */ - public List<SolutionVersion> getVersions() { + public List<ListingVersion> getVersions() { return new ArrayList<>(versions); } /** * @param versions the versions to set */ - public void setVersions(List<SolutionVersion> versions) { + @JsonbTransient + public void setVersions(List<ListingVersion> versions) { Objects.requireNonNull(versions); this.versions = new ArrayList<>(versions); } diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/SolutionVersion.java b/src/main/java/org/eclipsefoundation/marketplace/dto/ListingVersion.java similarity index 77% rename from src/main/java/org/eclipsefoundation/marketplace/dto/SolutionVersion.java rename to src/main/java/org/eclipsefoundation/marketplace/dto/ListingVersion.java index 1968ffbd451d21b5d21b284df9ec7a73a57d7a9c..24d06c97297de748e0c83bcb6c363776084940f8 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/SolutionVersion.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/ListingVersion.java @@ -11,12 +11,14 @@ import java.util.List; import java.util.Objects; /** - * Domain object representing a marketplace listing solution version + * Domain object representing a marketplace listing version * * @author Martin Lowe */ -public class SolutionVersion { +public class ListingVersion { + private String id; + private String listingId; private String version; private List<String> eclipseVersions; private List<String> platforms; @@ -24,12 +26,40 @@ public class SolutionVersion { private String updateSiteUrl; private List<FeatureId> featureIds; - public SolutionVersion() { + public ListingVersion() { this.eclipseVersions = new ArrayList<>(); this.platforms = new ArrayList<>(); this.featureIds = new ArrayList<>(); } + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(String id) { + this.id = id; + } + + /** + * @return the listingId + */ + public String getListingId() { + return listingId; + } + + /** + * @param listingId the listingId to set + */ + public void setListingId(String listingId) { + this.listingId = listingId; + } + /** * @return the versionString */ @@ -106,14 +136,15 @@ public class SolutionVersion { * @return the featureIds */ public List<FeatureId> getFeatureIds() { - return featureIds; + return new ArrayList<>(featureIds); } /** * @param featureIds the featureIds to set */ public void setFeatureIds(List<FeatureId> featureIds) { - this.featureIds = featureIds; + Objects.requireNonNull(featureIds); + this.featureIds = new ArrayList<>(featureIds); } } diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/codecs/ListingCodec.java b/src/main/java/org/eclipsefoundation/marketplace/dto/codecs/ListingCodec.java index 0ba97a394d8329c8c5fdd2ba1fd8ab942dc475c5..9265d119d3df81cc39c7fa914fd1204d7dff4901 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/codecs/ListingCodec.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/codecs/ListingCodec.java @@ -23,7 +23,7 @@ import org.eclipsefoundation.marketplace.dto.Listing; import org.eclipsefoundation.marketplace.dto.converters.AuthorConverter; import org.eclipsefoundation.marketplace.dto.converters.CategoryConverter; import org.eclipsefoundation.marketplace.dto.converters.OrganizationConverter; -import org.eclipsefoundation.marketplace.dto.converters.SolutionVersionConverter; +import org.eclipsefoundation.marketplace.dto.converters.ListingVersionConverter; import org.eclipsefoundation.marketplace.dto.converters.TagConverter; import org.eclipsefoundation.marketplace.namespace.DatabaseFieldNames; @@ -43,7 +43,7 @@ public class ListingCodec implements CollectibleCodec<Listing> { private final AuthorConverter authorConverter; private final OrganizationConverter organizationConverter; private final TagConverter tagConverter; - private final SolutionVersionConverter versionConverter; + private final ListingVersionConverter versionConverter; private final CategoryConverter categoryConverter; /** @@ -55,7 +55,7 @@ public class ListingCodec implements CollectibleCodec<Listing> { this.authorConverter = new AuthorConverter(); this.organizationConverter = new OrganizationConverter(); this.tagConverter = new TagConverter(); - this.versionConverter = new SolutionVersionConverter(); + this.versionConverter = new ListingVersionConverter(); this.categoryConverter = new CategoryConverter(); } @@ -90,8 +90,6 @@ public class ListingCodec implements CollectibleCodec<Listing> { value.getAuthors().stream().map(authorConverter::convert).collect(Collectors.toList())); doc.put(DatabaseFieldNames.LISTING_TAGS, value.getTags().stream().map(tagConverter::convert).collect(Collectors.toList())); - doc.put(DatabaseFieldNames.LISTING_VERSIONS, - value.getVersions().stream().map(versionConverter::convert).collect(Collectors.toList())); documentCodec.encode(writer, doc, encoderContext); } diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/codecs/ListingVersionCodec.java b/src/main/java/org/eclipsefoundation/marketplace/dto/codecs/ListingVersionCodec.java new file mode 100644 index 0000000000000000000000000000000000000000..2bda5745771fcd0d405e83e7f119fe3ec01362f6 --- /dev/null +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/codecs/ListingVersionCodec.java @@ -0,0 +1,81 @@ +/* Copyright (c) 2019 Eclipse Foundation and others. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License 2.0 + * which is available at http://www.eclipse.org/legal/epl-v20.html, + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipsefoundation.marketplace.dto.codecs; + +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.bson.BsonReader; +import org.bson.BsonString; +import org.bson.BsonValue; +import org.bson.BsonWriter; +import org.bson.Document; +import org.bson.codecs.Codec; +import org.bson.codecs.CollectibleCodec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.eclipsefoundation.marketplace.dto.ListingVersion; +import org.eclipsefoundation.marketplace.dto.converters.ListingVersionConverter; + +import com.mongodb.MongoClient; + + +/** + * MongoDB codec for transcoding of {@link ListingVersion} and {@link Document} + * objects. Used when writing or retrieving objects of given type from the + * database. + * + * @author Martin Lowe + */ +public class ListingVersionCodec implements CollectibleCodec<ListingVersion> { + private final Codec<Document> documentCodec; + + private ListingVersionConverter cc; + + /** + * Creates the codec and initializes the codecs and converters needed to create + * a listing from end to end. + */ + public ListingVersionCodec() { + this.documentCodec = MongoClient.getDefaultCodecRegistry().get(Document.class); + this.cc = new ListingVersionConverter(); + } + + @Override + public void encode(BsonWriter writer, ListingVersion value, EncoderContext encoderContext) { + documentCodec.encode(writer, cc.convert(value), encoderContext); + } + + @Override + public Class<ListingVersion> getEncoderClass() { + return ListingVersion.class; + } + + @Override + public ListingVersion decode(BsonReader reader, DecoderContext decoderContext) { + return cc.convert(documentCodec.decode(reader, decoderContext)); + } + + @Override + public ListingVersion generateIdIfAbsentFromDocument(ListingVersion document) { + if (!documentHasId(document)) { + document.setId(UUID.randomUUID().toString()); + } + return document; + } + + @Override + public boolean documentHasId(ListingVersion document) { + return !StringUtils.isBlank(document.getId()); + } + + @Override + public BsonValue getDocumentId(ListingVersion document) { + return new BsonString(document.getId()); + } + +} diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/converters/SolutionVersionConverter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/converters/ListingVersionConverter.java similarity index 72% rename from src/main/java/org/eclipsefoundation/marketplace/dto/converters/SolutionVersionConverter.java rename to src/main/java/org/eclipsefoundation/marketplace/dto/converters/ListingVersionConverter.java index 880f31717d1abfd2fa89374f7b4c5e8472402001..bdc24152004a328f878170c4851df5dc9452bc36 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/converters/SolutionVersionConverter.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/converters/ListingVersionConverter.java @@ -9,21 +9,23 @@ package org.eclipsefoundation.marketplace.dto.converters; import java.util.stream.Collectors; import org.bson.Document; -import org.eclipsefoundation.marketplace.dto.SolutionVersion; +import org.eclipsefoundation.marketplace.dto.ListingVersion; import org.eclipsefoundation.marketplace.namespace.DatabaseFieldNames; /** - * Converter implementation for the {@link SolutionVersion} object. + * Converter implementation for the {@link ListingVersion} object. * * @author Martin Lowe */ -public class SolutionVersionConverter implements Converter<SolutionVersion> { +public class ListingVersionConverter implements Converter<ListingVersion> { private final FeatureIdConverter featureIdConverter = new FeatureIdConverter(); @Override - public SolutionVersion convert(Document src) { - SolutionVersion version = new SolutionVersion(); + public ListingVersion convert(Document src) { + ListingVersion version = new ListingVersion(); + version.setId(src.getString(DatabaseFieldNames.DOCID)); + version.setListingId(src.getString(DatabaseFieldNames.LISTING_ID)); version.setEclipseVersions(src.getList("compatible_versions", String.class)); version.setPlatforms(src.getList("platforms", String.class)); version.setMinJavaVersion(src.getString("min_java_version")); @@ -35,8 +37,10 @@ public class SolutionVersionConverter implements Converter<SolutionVersion> { } @Override - public Document convert(SolutionVersion src) { + public Document convert(ListingVersion src) { Document doc = new Document(); + doc.put(DatabaseFieldNames.DOCID, src.getId()); + doc.put(DatabaseFieldNames.LISTING_ID, src.getListingId()); doc.put("compatible_versions", src.getEclipseVersions()); doc.put("platforms", src.getPlatforms()); doc.put("min_java_version", src.getMinJavaVersion()); diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/CatalogFilter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/CatalogFilter.java index 137bac5f2f5b9f29b3f8b8723ec060bbe9a01a4d..e2aaae11e759b477c0182a58d85366be0b16323a 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/CatalogFilter.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/CatalogFilter.java @@ -30,12 +30,15 @@ import com.mongodb.client.model.Filters; public class CatalogFilter implements DtoFilter<Catalog> { @Override - public List<Bson> getFilters(RequestWrapper wrap) { + public List<Bson> getFilters(RequestWrapper wrap, String root) { List<Bson> filters = new ArrayList<>(); - // ID check - Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); - if (id.isPresent()) { - filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + // perform following checks only if there is no doc root + if (root == null) { + // ID check + Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); + if (id.isPresent()) { + filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + } } return filters; } diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/CategoryFilter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/CategoryFilter.java index 7bdf5620b4407978ea83ff2a141f898f206561e8..3092ecf53f48b7dbeaf00bbf31eb386a8e859034 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/CategoryFilter.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/CategoryFilter.java @@ -29,12 +29,15 @@ import com.mongodb.client.model.Filters; public class CategoryFilter implements DtoFilter<Category> { @Override - public List<Bson> getFilters(RequestWrapper wrap) { + public List<Bson> getFilters(RequestWrapper wrap, String root) { List<Bson> filters = new ArrayList<>(); - // ID check - Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); - if (id.isPresent()) { - filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + // perform following checks only if there is no doc root + if (root == null) { + // ID check + Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); + if (id.isPresent()) { + filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + } } return filters; } diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/DtoFilter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/DtoFilter.java index e5c6d5c064ea6dea6d0da4a062362a08806fd89b..c642a7d6de5155e07c6d15df645dd7361f9d3c4b 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/DtoFilter.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/DtoFilter.java @@ -7,10 +7,14 @@ package org.eclipsefoundation.marketplace.dto.filter; import java.util.List; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.bson.conversions.Bson; import org.eclipsefoundation.marketplace.model.RequestWrapper; +import com.mongodb.client.model.Aggregates; + /** * Filter interface for usage when querying data. * @@ -21,16 +25,19 @@ public interface DtoFilter<T> { /** * Retrieve filter objects for the current arguments. * - * @param wrap wrapper for the current request - * @return list of filters for the current request, or empty if there are no applicable filters. + * @param wrap wrapper for the current request + * @param nestedPath current path for nesting of filters + * @return list of filters for the current request, or empty if there are no + * applicable filters. */ - List<Bson> getFilters(RequestWrapper wrap); + List<Bson> getFilters(RequestWrapper wrap, String nestedPath); /** * Retrieve aggregate filter operations for the current arguments. * - * @param wrap wrapper for the current request - * @return list of aggregates for the current request, or empty if there are no applicable aggregates. + * @param wrap wrapper for the current request + * @return list of aggregates for the current request, or empty if there are no + * applicable aggregates. */ List<Bson> getAggregates(RequestWrapper wrap); @@ -40,4 +47,28 @@ public interface DtoFilter<T> { * @return class of object to filter */ Class<T> getType(); + + /** + * Wraps each of the filters present for a given filter type in an aggregate + * match operation to port filter operations into an aggregate pipeline. This is + * handy when importing nested types and enabling filters. + * + * @param wrap wrapper for the current request + * @param nestedPath current path for nesting of filters + * @return a list of aggregate pipeline operations representing the filters for + * the current request. + */ + default List<Bson> wrapFiltersToAggregate(RequestWrapper wrap, String nestedPath) { + return getFilters(wrap, nestedPath).stream().map(Aggregates::match).collect(Collectors.toList()); + } + + /** + * + * @param root + * @param fieldName + * @return + */ + default String getPath(String root, String fieldName) { + return StringUtils.isBlank(root) ? fieldName : root + '.' + fieldName; + } } diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ErrorReportFilter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ErrorReportFilter.java index 51a30bec9d03f77c8c4c979e3246949809343594..3f1ff92874463f8a42cb744b58941091db114cad 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ErrorReportFilter.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ErrorReportFilter.java @@ -30,7 +30,7 @@ import com.mongodb.client.model.Filters; public class ErrorReportFilter implements DtoFilter<ErrorReport> { @Override - public List<Bson> getFilters(RequestWrapper wrap) { + public List<Bson> getFilters(RequestWrapper wrap, String root) { List<Bson> filters = new ArrayList<>(); // ErrorReport ID check diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/InstallFilter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/InstallFilter.java index baffe76b6748f5cea20afc688465e9818f229f14..29d1e8374bb39fce19f2e2ca169f22d39c94df07 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/InstallFilter.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/InstallFilter.java @@ -32,12 +32,15 @@ import com.mongodb.client.model.Filters; public class InstallFilter implements DtoFilter<Install> { @Override - public List<Bson> getFilters(RequestWrapper wrap) { + public List<Bson> getFilters(RequestWrapper wrap, String root) { List<Bson> filters = new ArrayList<>(); - // Listing ID check - Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); - if (id.isPresent()) { - filters.add(Filters.eq(DatabaseFieldNames.INSTALL_LISTING_ID, id.get())); + // perform following checks only if there is no doc root + if (root == null) { + // ID check + Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); + if (id.isPresent()) { + filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + } } // version check Optional<String> version = wrap.getFirstParam(UrlParameterNames.VERSION); diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ListingFilter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ListingFilter.java index c6d6d79183941fef5ba054f1c4d7787015a2c750..ceac34a0e0a45267c44246f530ea1257b9c8ea9f 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ListingFilter.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ListingFilter.java @@ -11,9 +11,11 @@ import java.util.List; import java.util.Optional; import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; import org.bson.conversions.Bson; import org.eclipsefoundation.marketplace.dto.Listing; +import org.eclipsefoundation.marketplace.dto.ListingVersion; import org.eclipsefoundation.marketplace.model.RequestWrapper; import org.eclipsefoundation.marketplace.namespace.DatabaseFieldNames; import org.eclipsefoundation.marketplace.namespace.DtoTableNames; @@ -23,35 +25,26 @@ import com.mongodb.client.model.Aggregates; import com.mongodb.client.model.Filters; /** - * Filter implementation for the Listing class. Checks the following fields: - * - * <ul> - * <li>platform_version - * <li>java_version - * <li>os - * <li>license_type - * <li>q - * <li>ids - * <li>tags - * </ul> - * - * <p> - * Injects categories into the results by way of aggregate pipeline. - * </p> + * Filter implementation for the {@linkplain Listing} class. * * @author Martin Lowe */ @ApplicationScoped public class ListingFilter implements DtoFilter<Listing> { + @Inject + DtoFilter<ListingVersion> listingVersionFilter; + @Override - public List<Bson> getFilters(RequestWrapper wrap) { + public List<Bson> getFilters(RequestWrapper wrap, String root) { List<Bson> filters = new ArrayList<>(); - - // Listing ID check - Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); - if (id.isPresent()) { - filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + // perform following checks only if there is no doc root + if (root == null) { + // ID check + Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); + if (id.isPresent()) { + filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + } } // select by multiple IDs @@ -66,29 +59,6 @@ public class ListingFilter implements DtoFilter<Listing> { filters.add(Filters.eq(DatabaseFieldNames.LICENSE_TYPE, licType.get())); } - // handle version sub document selection - List<Bson> versionFilters = new ArrayList<>(); - // solution version - OS filter - Optional<String> os = wrap.getFirstParam(UrlParameterNames.OS); - if (os.isPresent()) { - versionFilters.add(Filters.eq("platforms", os.get())); - } - // solution version - eclipse version - Optional<String> eclipseVersion = wrap.getFirstParam(UrlParameterNames.ECLIPSE_VERSION); - if (eclipseVersion.isPresent()) { - versionFilters.add(Filters.eq("compatible_versions", eclipseVersion.get())); - } - // TODO this sorts by naturally by character rather than by actual number (e.g. - // 1.9 is technically greater than 1.10) - // solution version - Java version - Optional<String> javaVersion = wrap.getFirstParam(UrlParameterNames.JAVA_VERSION); - if (javaVersion.isPresent()) { - versionFilters.add(Filters.gte("min_java_version", javaVersion.get())); - } - if (!versionFilters.isEmpty()) { - filters.add(Filters.elemMatch("versions", Filters.and(versionFilters))); - } - // select by multiple tags List<String> tags = wrap.getParams(UrlParameterNames.TAGS); if (!tags.isEmpty()) { @@ -107,6 +77,9 @@ public class ListingFilter implements DtoFilter<Listing> { public List<Bson> getAggregates(RequestWrapper wrap) { List<Bson> aggs = new ArrayList<>(); // adds a $lookup aggregate, joining categories on categoryIDS as "categories" + aggs.add(Aggregates.lookup(DtoTableNames.LISTING_VERSION.getTableName(), DatabaseFieldNames.DOCID, DatabaseFieldNames.LISTING_ID, + DatabaseFieldNames.LISTING_VERSIONS)); + aggs.addAll(listingVersionFilter.wrapFiltersToAggregate(wrap, DatabaseFieldNames.LISTING_VERSIONS)); aggs.add(Aggregates.lookup(DtoTableNames.CATEGORY.getTableName(), DatabaseFieldNames.CATEGORY_IDS, DatabaseFieldNames.DOCID, DatabaseFieldNames.LISTING_CATEGORIES)); List<String> marketIds = wrap.getParams(UrlParameterNames.MARKET_IDS); diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ListingVersionFilter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ListingVersionFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..dc0560f7b4aabfaa27eb45faa3e70fce70d44c40 --- /dev/null +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/ListingVersionFilter.java @@ -0,0 +1,76 @@ +/* Copyright (c) 2019 Eclipse Foundation and others. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License 2.0 + * which is available at http://www.eclipse.org/legal/epl-v20.html, + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipsefoundation.marketplace.dto.filter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import javax.enterprise.context.ApplicationScoped; + +import org.bson.conversions.Bson; +import org.eclipsefoundation.marketplace.dto.ListingVersion; +import org.eclipsefoundation.marketplace.model.RequestWrapper; +import org.eclipsefoundation.marketplace.namespace.DatabaseFieldNames; +import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; + +import com.mongodb.client.model.Filters; + +/** + * Filter implementation for the {@linkplain ListingVersion} class. + * + * @author Martin Lowe + * + */ +@ApplicationScoped +public class ListingVersionFilter implements DtoFilter<ListingVersion> { + + @Override + public List<Bson> getFilters(RequestWrapper wrap, String root) { + List<Bson> filters = new ArrayList<>(); + // perform following checks only if there is no doc root + if (root == null) { + // ID check + Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); + if (id.isPresent()) { + filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + } + } + + // solution version - OS filter + Optional<String> os = wrap.getFirstParam(UrlParameterNames.OS); + if (os.isPresent()) { + filters.add(Filters.eq(getPath(root, "platforms"), os.get())); + } + // solution version - eclipse version + Optional<String> eclipseVersion = wrap.getFirstParam(UrlParameterNames.ECLIPSE_VERSION); + if (eclipseVersion.isPresent()) { + filters.add(Filters.eq(getPath(root, "compatible_versions"), eclipseVersion.get())); + } + // TODO this sorts by naturally by character rather than by actual number (e.g. + // 1.9 is technically greater than 1.10) + // solution version - Java version + Optional<String> javaVersion = wrap.getFirstParam(UrlParameterNames.JAVA_VERSION); + if (javaVersion.isPresent()) { + filters.add(Filters.gte(getPath(root, "min_java_version"), javaVersion.get())); + } + + return filters; + } + + @Override + public List<Bson> getAggregates(RequestWrapper wrap) { + return Collections.emptyList(); + } + + @Override + public Class<ListingVersion> getType() { + return ListingVersion.class; + } + +} diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/MarketFilter.java b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/MarketFilter.java index a73cc5f620de58b3dac4852aacdf79f09817c4b8..2906257162df2b3e0cb88869933ad1f2cff62fe4 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/dto/filter/MarketFilter.java +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/filter/MarketFilter.java @@ -27,6 +27,7 @@ import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; import com.mongodb.client.model.Accumulators; import com.mongodb.client.model.Aggregates; +import com.mongodb.client.model.Filters; import com.mongodb.client.model.Projections; import com.mongodb.client.model.Variable; @@ -39,12 +40,15 @@ import com.mongodb.client.model.Variable; public class MarketFilter implements DtoFilter<Market> { @Override - public List<Bson> getFilters(RequestWrapper wrap) { + public List<Bson> getFilters(RequestWrapper wrap, String root) { List<Bson> filters = new ArrayList<>(); - // ID check - Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); - if (id.isPresent()) { - filters.add(eq(DatabaseFieldNames.DOCID, id.get())); + // perform following checks only if there is no doc root + if (root == null) { + // ID check + Optional<String> id = wrap.getFirstParam(UrlParameterNames.ID); + if (id.isPresent()) { + filters.add(Filters.eq(DatabaseFieldNames.DOCID, id.get())); + } } return filters; } @@ -63,7 +67,7 @@ public class MarketFilter implements DtoFilter<Market> { Projections.fields(Projections.excludeId(), Projections.include(DatabaseFieldNames.CATEGORY_IDS)))); // set up a var reference for the _id - Variable<String> id = new Variable<String>("market_id", "$" + DatabaseFieldNames.DOCID); + Variable<String> id = new Variable<>("market_id", "$" + DatabaseFieldNames.DOCID); // lookup all category IDS from listings with the given market ID aggs.add(Aggregates.lookup(DtoTableNames.LISTING.getTableName(), Arrays.asList(id), pipeline, tempFieldName)); // explode all category IDS for collection diff --git a/src/main/java/org/eclipsefoundation/marketplace/dto/providers/ListingVersionCodecProvider.java b/src/main/java/org/eclipsefoundation/marketplace/dto/providers/ListingVersionCodecProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..f7b19327b4c98e0717519f14cb4e6f14449182dc --- /dev/null +++ b/src/main/java/org/eclipsefoundation/marketplace/dto/providers/ListingVersionCodecProvider.java @@ -0,0 +1,37 @@ +/* Copyright (c) 2019 Eclipse Foundation and others. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License 2.0 + * which is available at http://www.eclipse.org/legal/epl-v20.html, + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipsefoundation.marketplace.dto.providers; + +import org.bson.codecs.Codec; +import org.bson.codecs.configuration.CodecProvider; +import org.bson.codecs.configuration.CodecRegistry; +import org.eclipsefoundation.marketplace.dto.Listing; +import org.eclipsefoundation.marketplace.dto.ListingVersion; +import org.eclipsefoundation.marketplace.dto.codecs.ListingCodec; +import org.eclipsefoundation.marketplace.dto.codecs.ListingVersionCodec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides the {@link ListingCodec} to MongoDB for conversions of + * {@link Listing} objects. + * + * @author Martin Lowe + */ +public class ListingVersionCodecProvider implements CodecProvider { + private static final Logger LOGGER = LoggerFactory.getLogger(ListingVersionCodecProvider.class); + + @SuppressWarnings("unchecked") + @Override + public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) { + if (clazz == ListingVersion.class) { + LOGGER.debug("Registering custom Listing class MongoDB codec"); + return (Codec<T>) new ListingVersionCodec(); + } + return null; + } +} diff --git a/src/main/java/org/eclipsefoundation/marketplace/model/MongoQuery.java b/src/main/java/org/eclipsefoundation/marketplace/model/MongoQuery.java index 4972ca632764105d12ca5bf5bc0ea6b9cdf49fe0..d792d51a0d4a9d27e785fc8f1b01fac02894296f 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/model/MongoQuery.java +++ b/src/main/java/org/eclipsefoundation/marketplace/model/MongoQuery.java @@ -17,7 +17,6 @@ import org.eclipsefoundation.marketplace.dto.filter.DtoFilter; import org.eclipsefoundation.marketplace.helper.SortableHelper; import org.eclipsefoundation.marketplace.helper.SortableHelper.Sortable; import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; -import org.eclipsefoundation.marketplace.resource.AnnotationClassInjectionFilter; import org.eclipsefoundation.marketplace.service.CachingService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +49,6 @@ public class MongoQuery<T> { this.dtoFilter = dtoFilter; this.cache = cache; this.aggregates = new ArrayList<>(); - init(); } @@ -68,7 +66,7 @@ public class MongoQuery<T> { // get the filters for the current DTO List<Bson> filters = new ArrayList<>(); - filters.addAll(dtoFilter.getFilters(wrapper)); + filters.addAll(dtoFilter.getFilters(wrapper, null)); // get fields that make up the required fields to enable pagination and check Optional<String> sortOpt = wrapper.getFirstParam(UrlParameterNames.SORT); @@ -186,7 +184,7 @@ public class MongoQuery<T> { * @return the docType */ public Class<T> getDocType() { - return (Class<T>) wrapper.getAttribute(AnnotationClassInjectionFilter.ATTRIBUTE_NAME).get(); + return dtoFilter.getType(); } /** diff --git a/src/main/java/org/eclipsefoundation/marketplace/model/ResourceDataType.java b/src/main/java/org/eclipsefoundation/marketplace/model/ResourceDataType.java deleted file mode 100644 index 99f725813595b21ce835b9f54c395e7627ab8e81..0000000000000000000000000000000000000000 --- a/src/main/java/org/eclipsefoundation/marketplace/model/ResourceDataType.java +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (c) 2019 Eclipse Foundation and others. - * This program and the accompanying materials are made available - * under the terms of the Eclipse Public License 2.0 - * which is available at http://www.eclipse.org/legal/epl-v20.html, - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipsefoundation.marketplace.model; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * - * @author Martin Lowe - */ -@Retention(RUNTIME) -@Target(TYPE) -public @interface ResourceDataType { - - Class<?> value(); -} diff --git a/src/main/java/org/eclipsefoundation/marketplace/namespace/DtoTableNames.java b/src/main/java/org/eclipsefoundation/marketplace/namespace/DtoTableNames.java index e03c9abcb63f785b607eb3c6c62698dd767cfd41..6c3042818388b1e63c5e86c950e4d9c26be70b99 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/namespace/DtoTableNames.java +++ b/src/main/java/org/eclipsefoundation/marketplace/namespace/DtoTableNames.java @@ -8,10 +8,11 @@ package org.eclipsefoundation.marketplace.namespace; import org.eclipsefoundation.marketplace.dto.Catalog; import org.eclipsefoundation.marketplace.dto.Category; +import org.eclipsefoundation.marketplace.dto.ErrorReport; import org.eclipsefoundation.marketplace.dto.Install; import org.eclipsefoundation.marketplace.dto.Listing; +import org.eclipsefoundation.marketplace.dto.ListingVersion; import org.eclipsefoundation.marketplace.dto.Market; -import org.eclipsefoundation.marketplace.dto.ErrorReport; /** * Mapping of DTO classes to their respective tables in the DB. @@ -20,10 +21,9 @@ import org.eclipsefoundation.marketplace.dto.ErrorReport; * */ public enum DtoTableNames { - LISTING(Listing.class, "listings"), - CATEGORY(Category.class, "categories"), - CATALOG(Catalog.class, "catalogs"), MARKET(Market.class, "markets"), - ERRORREPORT(ErrorReport.class, "errorreports"), INSTALL(Install.class, "installs"); + LISTING(Listing.class, "listings"), CATEGORY(Category.class, "categories"), CATALOG(Catalog.class, "catalogs"), + MARKET(Market.class, "markets"), ERRORREPORT(ErrorReport.class, "errorreports"), INSTALL(Install.class, "installs"), + LISTING_VERSION(ListingVersion.class, "listing_versions"); private Class<?> baseClass; private String tableName; diff --git a/src/main/java/org/eclipsefoundation/marketplace/resource/AnnotationClassInjectionFilter.java b/src/main/java/org/eclipsefoundation/marketplace/resource/AnnotationClassInjectionFilter.java deleted file mode 100644 index 3eaba5680a6a48159dbaf43fd7d2bc3bb6ebbf51..0000000000000000000000000000000000000000 --- a/src/main/java/org/eclipsefoundation/marketplace/resource/AnnotationClassInjectionFilter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2019 Eclipse Foundation and others. - * This program and the accompanying materials are made available - * under the terms of the Eclipse Public License 2.0 - * which is available at http://www.eclipse.org/legal/epl-v20.html, - * SPDX-License-Identifier: EPL-2.0 - */ -package org.eclipsefoundation.marketplace.resource; - -import java.io.IOException; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.core.Context; -import javax.ws.rs.ext.Provider; - -import org.eclipsefoundation.marketplace.model.ResourceDataType; - -/** - * Pre-processes the request to inject the datatype class name into the request. - * This is later used in reflection to circumvent type erasure within Query - * objects. - * - * @author Martin Lowe - */ -@Provider -public class AnnotationClassInjectionFilter implements ContainerRequestFilter { - public static final String ATTRIBUTE_NAME = "enclosed-data-type"; - - @Context - HttpServletRequest request; - - @Override - public void filter(ContainerRequestContext requestContext) throws IOException { - List<Object> resources = requestContext.getUriInfo().getMatchedResources(); - if (!resources.isEmpty()) { - // Quarkus compiles wrapper classes around beans, needs superclass call to get original class - Class<?> clazz = resources.get(0).getClass().getSuperclass(); - // get the resource data type - ResourceDataType[] dataTypes = clazz.getAnnotationsByType(ResourceDataType.class); - if (dataTypes.length > 0) { - ResourceDataType firstType = dataTypes[0]; - request.setAttribute(ATTRIBUTE_NAME, firstType.value()); - } - } - } -} diff --git a/src/main/java/org/eclipsefoundation/marketplace/resource/CatalogResource.java b/src/main/java/org/eclipsefoundation/marketplace/resource/CatalogResource.java index 369e3b159f4f2fac07df766356e4ee4ba67d6a95..49317fa2aacbdcdcafcd188736b5085e867711b4 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/resource/CatalogResource.java +++ b/src/main/java/org/eclipsefoundation/marketplace/resource/CatalogResource.java @@ -29,7 +29,6 @@ import org.eclipsefoundation.marketplace.helper.StreamHelper; import org.eclipsefoundation.marketplace.model.Error; import org.eclipsefoundation.marketplace.model.MongoQuery; import org.eclipsefoundation.marketplace.model.RequestWrapper; -import org.eclipsefoundation.marketplace.model.ResourceDataType; import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; import org.eclipsefoundation.marketplace.service.CachingService; import org.jboss.resteasy.annotations.jaxrs.PathParam; @@ -42,7 +41,6 @@ import com.mongodb.client.result.DeleteResult; * @author martin * */ -@ResourceDataType(Catalog.class) @Path("/catalogs") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) diff --git a/src/main/java/org/eclipsefoundation/marketplace/resource/CategoryResource.java b/src/main/java/org/eclipsefoundation/marketplace/resource/CategoryResource.java index 1879cc06c3a4fe2ec2a7a1752beba99aff5536b1..5152615ec22d63959c7aa5f07a7b6e784d6659d3 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/resource/CategoryResource.java +++ b/src/main/java/org/eclipsefoundation/marketplace/resource/CategoryResource.java @@ -29,7 +29,6 @@ import org.eclipsefoundation.marketplace.helper.StreamHelper; import org.eclipsefoundation.marketplace.model.Error; import org.eclipsefoundation.marketplace.model.MongoQuery; import org.eclipsefoundation.marketplace.model.RequestWrapper; -import org.eclipsefoundation.marketplace.model.ResourceDataType; import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; import org.eclipsefoundation.marketplace.service.CachingService; import org.jboss.resteasy.annotations.jaxrs.PathParam; @@ -42,7 +41,6 @@ import com.mongodb.client.result.DeleteResult; * @author martin * */ -@ResourceDataType(Category.class) @Path("/categories") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) diff --git a/src/main/java/org/eclipsefoundation/marketplace/resource/ErrorReportResource.java b/src/main/java/org/eclipsefoundation/marketplace/resource/ErrorReportResource.java index 0c67ec02b2a95170bd6509d212a19fe49a7bef65..1bcae4c5b0ee1f93a2bd75445e9361749e2fa4c6 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/resource/ErrorReportResource.java +++ b/src/main/java/org/eclipsefoundation/marketplace/resource/ErrorReportResource.java @@ -26,7 +26,6 @@ import org.eclipsefoundation.marketplace.dto.filter.DtoFilter; import org.eclipsefoundation.marketplace.helper.StreamHelper; import org.eclipsefoundation.marketplace.model.MongoQuery; import org.eclipsefoundation.marketplace.model.RequestWrapper; -import org.eclipsefoundation.marketplace.model.ResourceDataType; import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; import org.eclipsefoundation.marketplace.service.CachingService; import org.jboss.resteasy.annotations.jaxrs.PathParam; @@ -40,7 +39,6 @@ import org.slf4j.LoggerFactory; */ @RequestScoped @Path("/error") -@ResourceDataType(ErrorReport.class) @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class ErrorReportResource { diff --git a/src/main/java/org/eclipsefoundation/marketplace/resource/InstallResource.java b/src/main/java/org/eclipsefoundation/marketplace/resource/InstallResource.java index d5882ed583adfbe0a0cae50fbf7e081859db3a5f..8fac56e98b8568cc52a4710aea8bcabea19347c5 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/resource/InstallResource.java +++ b/src/main/java/org/eclipsefoundation/marketplace/resource/InstallResource.java @@ -29,7 +29,6 @@ import org.eclipsefoundation.marketplace.helper.StreamHelper; import org.eclipsefoundation.marketplace.model.Error; import org.eclipsefoundation.marketplace.model.MongoQuery; import org.eclipsefoundation.marketplace.model.RequestWrapper; -import org.eclipsefoundation.marketplace.model.ResourceDataType; import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; import org.eclipsefoundation.marketplace.service.CachingService; import org.jboss.resteasy.annotations.jaxrs.PathParam; @@ -42,7 +41,6 @@ import org.slf4j.LoggerFactory; * @author Martin Lowe */ @RequestScoped -@ResourceDataType(Install.class) @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Path("/installs") diff --git a/src/main/java/org/eclipsefoundation/marketplace/resource/ListingResource.java b/src/main/java/org/eclipsefoundation/marketplace/resource/ListingResource.java index d30a477e3b300a9eb010b14170121788cae0f901..f295a05f398b4a314590f5c7d0847f3c127c951b 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/resource/ListingResource.java +++ b/src/main/java/org/eclipsefoundation/marketplace/resource/ListingResource.java @@ -32,7 +32,6 @@ import org.eclipsefoundation.marketplace.helper.StreamHelper; import org.eclipsefoundation.marketplace.model.Error; import org.eclipsefoundation.marketplace.model.MongoQuery; import org.eclipsefoundation.marketplace.model.RequestWrapper; -import org.eclipsefoundation.marketplace.model.ResourceDataType; import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; import org.eclipsefoundation.marketplace.service.CachingService; import org.jboss.resteasy.annotations.jaxrs.PathParam; @@ -46,7 +45,6 @@ import com.mongodb.client.result.DeleteResult; * * @author Martin Lowe */ -@ResourceDataType(Listing.class) @Path("/listings") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) diff --git a/src/main/java/org/eclipsefoundation/marketplace/resource/ListingVersionResource.java b/src/main/java/org/eclipsefoundation/marketplace/resource/ListingVersionResource.java new file mode 100644 index 0000000000000000000000000000000000000000..cbd82c896110e612af408ea37551e20638220748 --- /dev/null +++ b/src/main/java/org/eclipsefoundation/marketplace/resource/ListingVersionResource.java @@ -0,0 +1,139 @@ +/* Copyright (c) 2019 Eclipse Foundation and others. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License 2.0 + * which is available at http://www.eclipse.org/legal/epl-v20.html, + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipsefoundation.marketplace.resource; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.eclipsefoundation.marketplace.dao.MongoDao; +import org.eclipsefoundation.marketplace.dto.ListingVersion; +import org.eclipsefoundation.marketplace.dto.filter.DtoFilter; +import org.eclipsefoundation.marketplace.helper.StreamHelper; +import org.eclipsefoundation.marketplace.model.Error; +import org.eclipsefoundation.marketplace.model.MongoQuery; +import org.eclipsefoundation.marketplace.model.RequestWrapper; +import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; +import org.eclipsefoundation.marketplace.service.CachingService; +import org.jboss.resteasy.annotations.jaxrs.PathParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mongodb.client.result.DeleteResult; + +/** + * Resource for retrieving {@linkplain ListingVersion}s from the MongoDB + * instance. + * + * @author Martin Lowe + */ +@RequestScoped +@Path("/listing_versions") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class ListingVersionResource { + private static final Logger LOGGER = LoggerFactory.getLogger(ListingVersionResource.class); + + @Inject + MongoDao dao; + @Inject + CachingService<List<ListingVersion>> cachingService; + @Inject + RequestWrapper params; + @Inject + DtoFilter<ListingVersion> dtoFilter; + + @GET + public Response select() { + MongoQuery<ListingVersion> q = new MongoQuery<>(params, dtoFilter, cachingService); + // retrieve the possible cached object + Optional<List<ListingVersion>> cachedResults = cachingService.get("all", params, + () -> StreamHelper.awaitCompletionStage(dao.get(q))); + if (!cachedResults.isPresent()) { + LOGGER.error("Error while retrieving cached ListingVersions"); + return Response.serverError().build(); + } + + // return the results as a response + return Response.ok(cachedResults.get()).build(); + } + + /** + * Endpoint for /ListingVersion/ to post a new ListingVersion to the persistence layer. + * + * @param listingVersion the ListingVersion object to insert into the database. + * @return response for the browser + */ + @PUT + public Response putListingVersion(ListingVersion listingVersion) { + MongoQuery<ListingVersion> q = new MongoQuery<>(params, dtoFilter, cachingService); + // add the object, and await the result + StreamHelper.awaitCompletionStage(dao.add(q, Arrays.asList(listingVersion))); + + // return the results as a response + return Response.ok().build(); + } + + /** + * Endpoint for /listingVersions/\<listingVersionId\> to retrieve a specific ListingVersion from the + * database. + * + * @param listingVersionId the ListingVersion ID + * @return response for the browser + */ + @GET + @Path("/{listingVersionId}") + public Response select(@PathParam("listingVersionId") String listingVersionId) { + params.addParam(UrlParameterNames.ID, listingVersionId); + + MongoQuery<ListingVersion> q = new MongoQuery<>(params, dtoFilter, cachingService); + // retrieve a cached version of the value for the current listing + Optional<List<ListingVersion>> cachedResults = cachingService.get(listingVersionId, params, + () -> StreamHelper.awaitCompletionStage(dao.get(q))); + if (!cachedResults.isPresent()) { + LOGGER.error("Error while retrieving cached listing for ID {}", listingVersionId); + return Response.serverError().build(); + } + + // return the results as a response + return Response.ok(cachedResults.get()).build(); + } + + /** + * Endpoint for /listingVersions/\<listingVersionId\> to retrieve a specific ListingVersion from the + * database. + * + * @param listingVersionId the listingVersion ID + * @return response for the browser + */ + @DELETE + @Path("/{listingVersionId}") + public Response delete(@PathParam("listingVersionId") String listingVersionId) { + params.addParam(UrlParameterNames.ID, listingVersionId); + + MongoQuery<ListingVersion> q = new MongoQuery<>(params, dtoFilter, cachingService); + // delete the currently selected asset + DeleteResult result = StreamHelper.awaitCompletionStage(dao.delete(q)); + if (result.getDeletedCount() == 0 || !result.wasAcknowledged()) { + return new Error(Status.NOT_FOUND, "Did not find an asset to delete for current call").asResponse(); + } + // return the results as a response + return Response.ok().build(); + } +} diff --git a/src/main/java/org/eclipsefoundation/marketplace/resource/MarketResource.java b/src/main/java/org/eclipsefoundation/marketplace/resource/MarketResource.java index 7fd751e3d302ecb7d0e13abca7a009022b279fcf..8229a7221f2ba56f85007eac169f144fe5aeaa32 100644 --- a/src/main/java/org/eclipsefoundation/marketplace/resource/MarketResource.java +++ b/src/main/java/org/eclipsefoundation/marketplace/resource/MarketResource.java @@ -29,7 +29,6 @@ import org.eclipsefoundation.marketplace.helper.StreamHelper; import org.eclipsefoundation.marketplace.model.Error; import org.eclipsefoundation.marketplace.model.MongoQuery; import org.eclipsefoundation.marketplace.model.RequestWrapper; -import org.eclipsefoundation.marketplace.model.ResourceDataType; import org.eclipsefoundation.marketplace.namespace.UrlParameterNames; import org.eclipsefoundation.marketplace.service.CachingService; import org.jboss.resteasy.annotations.jaxrs.PathParam; @@ -42,7 +41,6 @@ import com.mongodb.client.result.DeleteResult; * @author martin * */ -@ResourceDataType(Market.class) @Path("/markets") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) diff --git a/src/main/node/index.js b/src/main/node/index.js index e5ccda6eaf3c57d0eda4fd4220cae7ad7a1476d3..441bdecf9954b16025abc089995a6cf38ab059c5 100644 --- a/src/main/node/index.js +++ b/src/main/node/index.js @@ -1,6 +1,6 @@ const axios = require('axios'); const instance = axios.create({ - timeout: 1000, + timeout: 2500, headers: {'User-Agent': 'mpc/0.0.0'} }); const randomWords = require('random-words'); @@ -65,7 +65,7 @@ function splice(arr) { return out; } -function createListing(count) { +async function createListing(count) { if (count >= max) { return; } @@ -73,14 +73,25 @@ function createListing(count) { console.log(`Generating listing ${count} of ${max}`); var json = generateJSON(uuid.v4()); instance.put(argv.s+"/listings/", json) - .then(() => { - var installs = Math.floor(Math.random()*argv.i); - console.log(`Generating ${installs} install records for listing '${json.id}'`); - createInstall(0, installs, json, () => createListing(count+1)); - }) + .then(listingCallback(json, count)) .catch(err => console.log(err)); } +async function listingCallback(json, count) { + var installs = Math.floor(Math.random()*argv.i); + var solsCount = Math.floor(Math.random()*5) + 1; + var versions = []; + for (var j=0;j<solsCount;j++) { + var v = await createVersion(j, solsCount, json.id); + if (v != null) { + versions.push(v); + } + } + + console.log(`Generating ${installs} install records for listing '${json.id}'`); + createInstall(0, installs, json, versions, () => createListing(count+1)); +} + function createCategory(count) { if (count >= categoryIds.length) { return; @@ -101,28 +112,27 @@ function createMarket(count) { .catch(err => console.log(err)); } -function createInstall(curr, max, listing, callback) { +function createInstall(curr, max, listing, versions, callback) { if (curr >= max) { return callback(); } - var json = generateInstallJSON(listing); + var json = generateInstallJSON(listing, versions); instance.post(`${argv.s}/installs/${json['listing_id']}/${json.version}`, json) - .then(createInstall(curr+1,max,listing,callback)) + .then(createInstall(curr+1,max,listing,versions,callback)) .catch(err => console.log(err)); } -function generateJSON(id) { - var solutions = []; - var solsCount = Math.floor(Math.random()*5) + 1; - for (var i=0; i < solsCount; i++) { - solutions.push({ - "version": i, - "eclipse_versions": splice(eclipseVs), - "min_java_version": javaVs[Math.floor(Math.random()*javaVs.length)], - "platforms": splice(platforms) - }); +async function createVersion(curr, max, id) { + if (curr >= max) { + return; } - + var json = generateVersionJSON(curr, id); + return instance.put(`${argv.s}/listing_versions`, json) + .then(() => {return json}) + .catch(err => console.log(err)); +} + +function generateJSON(id) { return { "id": id, "title": "Sample", @@ -150,7 +160,6 @@ function generateJSON(id) { "url": "" } ], - "versions": solutions, "market_ids": splice(marketIds).splice(0,Math.ceil(Math.random()*2)), "category_ids": splice(categoryIds).splice(0,Math.ceil(Math.random()*5)+1), "screenshots": ["http://www.example.com/img/sample.png"] @@ -160,7 +169,7 @@ function generateJSON(id) { function generateCategoryJSON(id) { return { "id": id, - "name": randomWords({exactly:1, wordsPerString:Math.ceil(Math.random()*4)})[0], + "title": randomWords({exactly:1, wordsPerString:Math.ceil(Math.random()*4)})[0], "url": "https://www.eclipse.org" }; } @@ -168,13 +177,13 @@ function generateCategoryJSON(id) { function generateMarketJSON(id) { return { "id": id, - "name": randomWords({exactly:1, wordsPerString:Math.ceil(Math.random()*4)})[0], + "title": randomWords({exactly:1, wordsPerString:Math.ceil(Math.random()*4)})[0], "url": "https://www.eclipse.org" }; } -function generateInstallJSON(listing) { - var version = listing.versions[Math.floor(Math.random()*listing.versions.length)]; +function generateInstallJSON(listing,versions) { + var version = versions[Math.floor(Math.random()*versions.length)]; var javaVersions = Array.from(javaVs).splice(javaVs.indexOf(version["min_java_version"])); var eclipseVersions = Array.from(eclipseVs).splice(eclipseVs.indexOf(version["eclipse_version"])); @@ -186,3 +195,13 @@ function generateInstallJSON(listing) { "eclipse_version": shuff(eclipseVersions)[0] }; } + +function generateVersionJSON(name, listingId) { + return { + "version": name, + "listing_id": listingId, + "eclipse_versions": splice(eclipseVs), + "min_java_version": javaVs[Math.floor(Math.random()*javaVs.length)], + "platforms": splice(platforms) + }; +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 362434433bec5a6ffb1267224529113db6b3d082..60e41ba7bf6c1d7214d70575c4c27b947176dad2 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -7,7 +7,7 @@ quarkus.log.file.path=/tmp/logs/quarkus.log quarkus.mongodb.connection-string = mongodb://localhost:27017 quarkus.mongodb.credentials.username=root quarkus.mongodb.write-concern.safe=true -quarkus.mongodb.min-pool-size=10 +quarkus.mongodb.min-pool-size=100 quarkus.mongodb.max-pool-size=1000 quarkus.mongodb.write-concern.retry-writes=true mongodb.database=mpc