/** * 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; /** * RootResource */ import org.candlepin.common.auth.SecurityHole; import org.candlepin.common.config.Configuration; import org.candlepin.config.ConfigProperties; import com.google.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import io.swagger.annotations.ApiOperation; /** * A root resource, responsible for returning client a struct of links to the * various resources Candlepin exposes. This list will be filtered based on the * permissions of the caller. */ @Path("/") public class RootResource { private static Logger log = LoggerFactory.getLogger(RootResource.class); public static final Map<Object, String> RESOURCE_CLASSES; private Configuration config; private static List<Link> links = null; static { RESOURCE_CLASSES = new HashMap<Object, String>(); addResource(AdminResource.class); addResource(UserResource.class); addResource(AtomFeedResource.class); addResource(CertificateSerialResource.class); addResource(CdnResource.class); addResource(ConsumerResource.class); addResource(ConsumerTypeResource.class); addResource(ContentResource.class); addResource(CrlResource.class); addResource(EntitlementResource.class); addResource(EventResource.class); addResource(JobResource.class); addResource(OwnerResource.class); addResource(PoolResource.class); addResource(ProductResource.class); addResource(RulesResource.class); addResource(StatusResource.class); addResource(SubscriptionResource.class); addResource(ActivationKeyResource.class); addResource(RoleResource.class); addResource(HypervisorResource.class); addResource(EnvironmentResource.class); addResource(RootResource.class); addResource(DistributorVersionResource.class); addResource(DeletedConsumerResource.class); addResource(GuestIdResource.class); addResource(ConsumerContentOverrideResource.class); } @Inject public RootResource(Configuration config) { this.config = config; } protected List<Link> createLinks() { // Hidden resources will be omitted from the supported list we send to // the clients: List<String> hideResources = Arrays.asList( config.getString(ConfigProperties.HIDDEN_RESOURCES).split(" ")); List<Link> newLinks = new LinkedList<Link>(); for (Map.Entry<Object, String> entry : RESOURCE_CLASSES.entrySet()) { add(resourceLink(entry.getKey(), entry.getValue()), hideResources, newLinks); } return newLinks; } protected String generateRel(String href) { int index = href.lastIndexOf("/"); if (index == -1) { return href; } return href.substring(index + 1); } protected Link methodLink(String rel, Method m) { Path resource = m.getDeclaringClass().getAnnotation(Path.class); Path method = m.getAnnotation(Path.class); String href = resource.value() + "/" + method.value(); // Remove doubled slashes and trailing slash href = href.replaceAll("/+", "/").replaceAll("/$", ""); if (rel == null) { rel = generateRel(href); } return new Link(rel, href); } protected Link classLink(String rel, Class clazz) { Path a = (Path) clazz.getAnnotation(Path.class); String href = a.value(); if (rel == null) { rel = generateRel(href); } return new Link(rel, href); } protected Link resourceLink(Object resource, String rel) { if (resource instanceof Method) { return methodLink(rel, (Method) resource); } return classLink(rel, (Class) resource); } private void add(Link link, List<String> hideResources, List<Link> newLinks) { String rel = link.getRel(); if (!hideResources.contains(rel)) { newLinks.add(link); } else { log.debug("Hiding supported resource: " + rel); } } @ApiOperation(notes = "Retrieves a list of links corresponding to Root resources", value = "getRootResources") @GET @Produces(MediaType.APPLICATION_JSON) @SecurityHole(noAuth = true, anon = true) public List<Link> getRootResources() { // Create the links when requested. Although // this is not thread safe, doing this 2 or 3 times // will not hurt anything as it will result in a little // bit more garbage if (links == null) { links = createLinks(); } return links; } private static void addResource(Object resource) { RESOURCE_CLASSES.put(resource, null); } }