/** * Copyright (c) 2009 - 2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package org.candlepin.hostedtest; import org.candlepin.common.exceptions.NotFoundException; import org.candlepin.common.util.SuppressSwaggerCheck; import org.candlepin.controller.ProductManager; import org.candlepin.model.Content; import org.candlepin.model.Owner; import org.candlepin.model.OwnerContentCurator; import org.candlepin.model.OwnerCurator; import org.candlepin.model.OwnerProductCurator; import org.candlepin.model.Product; import org.candlepin.model.ProductContent; import org.candlepin.model.ProductCurator; import org.candlepin.model.dto.ProductData; import org.candlepin.model.dto.Subscription; import org.candlepin.resource.util.ResolverUtil; import org.candlepin.service.UniqueIdGenerator; import com.google.inject.persist.Transactional; import org.xnap.commons.i18n.I18n; import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.inject.Inject; import javax.persistence.LockModeType; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; /** * The SubscriptionResource class is used to provide an * in-memory upstream source for subscriptions when candlepin is run in hosted * mode, while it is built with candlepin, it is not packaged in candlepin.war, * as the only purpose of this class is to support spec tests. */ @SuppressSwaggerCheck @Path("/hostedtest/subscriptions") public class HostedTestSubscriptionResource { @Inject private HostedTestSubscriptionServiceAdapter adapter; @Inject private UniqueIdGenerator idGenerator; @Inject private ResolverUtil resolverUtil; @Inject private ProductManager productManager; @Inject private ProductCurator productCurator; @Inject private OwnerContentCurator ownerContentCurator; @Inject private OwnerCurator ownerCurator; @Inject private OwnerProductCurator ownerProductCurator; @Inject private I18n i18n; /** * API to check if resource is alive * * @return always returns true */ @GET @Path("/alive") @Produces(MediaType.TEXT_PLAIN) public Boolean isAlive() { return true; } /** * Creates a new subscription from the subscription JSON provided. Any UUID * provided in the JSON will be ignored when creating the new subscription. * * @param subscription * A Subscription object built from the JSON provided in the request * @return * The newly created Subscription object */ @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Subscription createSubscription(Subscription subscription) { if (subscription.getId() == null || subscription.getId().trim().length() == 0) { subscription.setId(this.idGenerator.generateId()); } return adapter.createSubscription(resolverUtil.resolveSubscription(subscription)); } /** * Lists all known subscriptions currently maintained by the subscription service. * * @return * A collection of subscriptions maintained by the subscription service */ @GET @Produces(MediaType.APPLICATION_JSON) public List<Subscription> listSubscriptions() { return adapter.getSubscriptions(); } /** * Retrieves the subscription for the specified subscription id. If the * subscription id cannot be found, this method returns null. * * @param subscriptionId * The id of the subscription to retrieve * @return * The requested Subscription object, or null if the subscription * could not be found */ @GET @Path("/{subscription_id}") @Produces(MediaType.APPLICATION_JSON) public Subscription getSubscription(@PathParam("subscription_id") String subscriptionId) { return adapter.getSubscription(subscriptionId); } /** * Updates the specified subscription with the provided subscription data. * * @param subscriptionNew * A Subscription object built from the JSON provided in the request; * contains the data to use * to update the specified subscription * @return * The updated Subscription object */ @PUT @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Subscription updateSubscription(Subscription subscriptionNew) { return adapter.updateSubscription(resolverUtil.resolveSubscription(subscriptionNew)); } /** * Deletes the specified subscription. * * @param subscriptionId * The id of the subscription to delete * @return * True if the subscription was deleted successfully; false * otherwise */ @DELETE @Path("/{subscription_id}") @Produces(MediaType.APPLICATION_JSON) public boolean deleteSubscription(@PathParam("subscription_id") String subscriptionId) { return adapter.deleteSubscription(subscriptionId); } /** * Deletes all subscriptions. */ @DELETE @Produces(MediaType.APPLICATION_JSON) public void deleteAllSubscriptions() { adapter.deleteAllSubscriptions(); } @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Path("/owners/{owner_key}/products/{product_id}/batch_content") @Transactional public Product addBatchContent( @PathParam("owner_key") String ownerKey, @PathParam("product_id") String productId, Map<String, Boolean> contentMap) { Owner owner = this.getOwnerByKey(ownerKey); Product product = this.fetchProduct(owner, productId); Collection<ProductContent> productContent = new LinkedList<ProductContent>(); this.productCurator.lock(product, LockModeType.PESSIMISTIC_WRITE); for (Entry<String, Boolean> entry : contentMap.entrySet()) { Content content = this.fetchContent(owner, entry.getKey()); productContent.add(new ProductContent(product, content, entry.getValue())); } return this.productManager.addContentToProduct(product, productContent, owner, true); } @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.WILDCARD) @Path("/owners/{owner_key}/products/{product_id}/content/{content_id}") @Transactional public ProductData addContent( @PathParam("owner_key") String ownerKey, @PathParam("product_id") String productId, @PathParam("content_id") String contentId, @QueryParam("enabled") Boolean enabled) { Owner owner = this.getOwnerByKey(ownerKey); Product product = this.fetchProduct(owner, productId); Content content = this.fetchContent(owner, contentId); this.productCurator.lock(product, LockModeType.PESSIMISTIC_WRITE); product = this.productManager.addContentToProduct( product, Arrays.asList(new ProductContent(product, content, enabled)), owner, true ); return product.toDTO(); } @PUT @Path("/owners/{owner_key}/products/{product_id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Transactional public ProductData updateProduct( @PathParam("owner_key") String ownerKey, @PathParam("product_id") String productId, ProductData update) { Owner owner = this.getOwnerByKey(ownerKey); Product existing = this.fetchProduct(owner, productId); Product updated = this.productManager.updateProduct(update, owner, true); return updated.toDTO(); } protected Product fetchProduct(Owner owner, String productId) { Product product = this.ownerProductCurator.getProductById(owner, productId); if (product == null) { throw new NotFoundException( i18n.tr("Product with ID ''{0}'' could not be found.", productId) ); } return product; } protected Owner getOwnerByKey(String key) { Owner owner = this.ownerCurator.lookupByKey(key); if (owner == null) { throw new NotFoundException(i18n.tr("Owner with key \"{0}\" was not found.", key)); } return owner; } protected Content fetchContent(Owner owner, String contentId) { Content content = this.ownerContentCurator.getContentById(owner, contentId); if (content == null) { throw new NotFoundException( i18n.tr("Content with ID \"{0}\" could not be found.", contentId) ); } return content; } }