/** * 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.resource; import org.candlepin.auth.Verify; import org.candlepin.common.exceptions.ForbiddenException; import org.candlepin.common.exceptions.NotFoundException; import org.candlepin.controller.ContentManager; import org.candlepin.controller.OwnerManager; import org.candlepin.controller.PoolManager; import org.candlepin.jackson.ProductCachedSerializationModule; import org.candlepin.model.CandlepinQuery; import org.candlepin.model.Content; import org.candlepin.model.ContentCurator; import org.candlepin.model.EnvironmentContentCurator; import org.candlepin.model.Owner; import org.candlepin.model.OwnerContentCurator; import org.candlepin.model.OwnerCurator; import org.candlepin.model.ProductCurator; import org.candlepin.model.dto.ContentData; import org.candlepin.service.UniqueIdGenerator; import com.google.inject.Inject; import com.google.inject.persist.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xnap.commons.i18n.I18n; import java.util.Collection; import java.util.LinkedList; import java.util.List; 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.core.MediaType; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import io.swagger.annotations.Authorization; /** * OwnerContentResource * * Manage the content that exists in an organization. */ @Path("/owners/{owner_key}/content") @Api(value = "owners", authorizations = { @Authorization("basic") }) public class OwnerContentResource { private static Logger log = LoggerFactory.getLogger(OwnerContentResource.class); private ContentCurator contentCurator; private ContentManager contentManager; private EnvironmentContentCurator envContentCurator; private I18n i18n; private OwnerCurator ownerCurator; private OwnerContentCurator ownerContentCurator; private PoolManager poolManager; private ProductCurator productCurator; private UniqueIdGenerator idGenerator; private ProductCachedSerializationModule productCachedModule; private OwnerManager ownerManager; @Inject public OwnerContentResource(ContentCurator contentCurator, ContentManager contentManager, EnvironmentContentCurator envContentCurator, I18n i18n, OwnerCurator ownerCurator, OwnerContentCurator ownerContentCurator, PoolManager poolManager, ProductCurator productCurator, UniqueIdGenerator idGenerator, ProductCachedSerializationModule productCachedModule, OwnerManager ownerManager) { this.contentCurator = contentCurator; this.contentManager = contentManager; this.envContentCurator = envContentCurator; this.i18n = i18n; this.ownerCurator = ownerCurator; this.ownerContentCurator = ownerContentCurator; this.poolManager = poolManager; this.productCurator = productCurator; this.idGenerator = idGenerator; this.productCachedModule = productCachedModule; this.ownerManager = ownerManager; } /** * Retrieves an Owner instance for the owner with the specified key/account. If a matching owner * could not be found, this method throws an exception. * * @param key * The key for the owner to retrieve * * @throws NotFoundException * if an owner could not be found for the specified key. * * @return * the Owner instance for the owner with the specified key. */ 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; } /** * Retrieves the content entity with the given content ID for the specified owner. If a * matching entity could not be found, this method throws a NotFoundException. * * @param owner * The owner in which to search for the content * * @param contentId * The Red Hat ID of the content to retrieve * * @throws NotFoundException * If a content with the specified Red Hat ID could not be found * * @return * the content entity with the given owner and content ID */ 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; } @ApiOperation(notes = "Retrieves list of Content", value = "list", response = Content.class, responseContainer = "list") @GET @Produces(MediaType.APPLICATION_JSON) public CandlepinQuery<Content> listContent(@Verify(Owner.class) @PathParam("owner_key") String ownerKey) { final Owner owner = this.getOwnerByKey(ownerKey); return this.ownerContentCurator.getContentByOwner(owner); } @ApiOperation(notes = "Retrieves a single Content", value = "getContent") @ApiResponses({ @ApiResponse(code = 400, message = "") }) @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{content_id}") public ContentData getContent( @Verify(Owner.class) @PathParam("owner_key") String ownerKey, @PathParam("content_id") String contentId) { Owner owner = this.getOwnerByKey(ownerKey); Content content = this.fetchContent(owner, contentId); return content.toDTO(); } /** * Creates or merges the given Content object. * * @param owner * The owner for which to create the new content * * @param content * The content to create or merge * * @return * the newly created and/or merged Content object. */ private Content createContentImpl(Owner owner, ContentData content) { // TODO: check if arches have changed ?? Content entity = null; if (content.getId() == null || content.getId().trim().length() == 0) { content.setId(this.idGenerator.generateId()); entity = this.contentManager.createContent(content, owner); } else { Content existing = this.ownerContentCurator.getContentById(owner, content.getId()); if (existing != null) { if (existing.isLocked()) { throw new ForbiddenException(i18n.tr("content \"{0}\" is locked", existing.getId())); } entity = this.contentManager.updateContent(content, owner, true); } else { entity = this.contentManager.createContent(content, owner); } } return entity; } @ApiOperation(notes = "Creates a Content", value = "createContent") @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public ContentData createContent(@PathParam("owner_key") String ownerKey, @ApiParam(name = "content", required = true) ContentData content) { Owner owner = this.getOwnerByKey(ownerKey); Content entity = this.createContentImpl(owner, content); ownerManager.refreshOwnerForContentAccess(owner); return entity.toDTO(); } @ApiOperation(notes = "Creates Contents in bulk", value = "createBatchContent") @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Path("/batch") @Transactional public Collection<ContentData> createBatchContent(@PathParam("owner_key") String ownerKey, @ApiParam(name = "contents", required = true) List<ContentData> contents) { Collection<ContentData> result = new LinkedList<ContentData>(); Owner owner = this.getOwnerByKey(ownerKey); for (ContentData content : contents) { Content entity = this.createContentImpl(owner, content); result.add(entity.toDTO()); } ownerManager.refreshOwnerForContentAccess(owner); return result; } @ApiOperation(notes = "Updates a Content", value = "updateContent") @PUT @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Path("/{content_id}") public ContentData updateContent(@PathParam("owner_key") String ownerKey, @PathParam("content_id") String contentId, @ApiParam(name = "content", required = true) ContentData content) { Owner owner = this.getOwnerByKey(ownerKey); Content existing = this.fetchContent(owner, contentId); if (existing.isLocked()) { throw new ForbiddenException(i18n.tr("content \"{0}\" is locked", existing.getId())); } existing = this.contentManager.updateContent(content, owner, true); ownerManager.refreshOwnerForContentAccess(owner); return existing.toDTO(); } @ApiOperation(notes = "Deletes a Content", value = "remove") @DELETE @Produces(MediaType.APPLICATION_JSON) @Path("/{content_id}") public void remove(@PathParam("owner_key") String ownerKey, @PathParam("content_id") String contentId) { Owner owner = this.getOwnerByKey(ownerKey); Content content = this.fetchContent(owner, contentId); if (content.isLocked()) { throw new ForbiddenException(i18n.tr("content \"{0}\" is locked", content.getId())); } this.contentManager.removeContent(owner, content, true); ownerManager.refreshOwnerForContentAccess(owner); } }