Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id B81BC200D11 for ; Mon, 2 Oct 2017 14:28:27 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id B6A32160BD5; Mon, 2 Oct 2017 12:28:27 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id AF56C1609EF for ; Mon, 2 Oct 2017 14:28:26 +0200 (CEST) Received: (qmail 51028 invoked by uid 500); 2 Oct 2017 12:28:25 -0000 Mailing-List: contact dev-help@brooklyn.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.apache.org Delivered-To: mailing list dev@brooklyn.apache.org Received: (qmail 50996 invoked by uid 99); 2 Oct 2017 12:28:25 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 02 Oct 2017 12:28:25 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 1AA3BE2F42; Mon, 2 Oct 2017 12:28:25 +0000 (UTC) From: aledsage To: dev@brooklyn.apache.org Reply-To: dev@brooklyn.apache.org References: In-Reply-To: Subject: [GitHub] brooklyn-server pull request #821: REST API for accessing adjuncts (includin... Content-Type: text/plain Message-Id: <20171002122825.1AA3BE2F42@git1-us-west.apache.org> Date: Mon, 2 Oct 2017 12:28:25 +0000 (UTC) archived-at: Mon, 02 Oct 2017 12:28:27 -0000 Github user aledsage commented on a diff in the pull request: https://github.com/apache/brooklyn-server/pull/821#discussion_r142123588 --- Diff: rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java --- @@ -0,0 +1,264 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.rest.resources; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.api.objs.BrooklynObjectType; +import org.apache.brooklyn.api.objs.EntityAdjunct; +import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.api.policy.PolicySpec; +import org.apache.brooklyn.api.sensor.Enricher; +import org.apache.brooklyn.api.sensor.EnricherSpec; +import org.apache.brooklyn.api.sensor.Feed; +import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.ConfigPredicates; +import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.mgmt.entitlement.Entitlements; +import org.apache.brooklyn.rest.api.AdjunctApi; +import org.apache.brooklyn.rest.domain.AdjunctDetail; +import org.apache.brooklyn.rest.domain.AdjunctSummary; +import org.apache.brooklyn.rest.domain.ConfigSummary; +import org.apache.brooklyn.rest.domain.Status; +import org.apache.brooklyn.rest.domain.SummaryComparators; +import org.apache.brooklyn.rest.filter.HaHotStateRequired; +import org.apache.brooklyn.rest.transform.AdjunctTransformer; +import org.apache.brooklyn.rest.transform.ConfigTransformer; +import org.apache.brooklyn.rest.transform.EntityTransformer; +import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils; +import org.apache.brooklyn.rest.util.WebResourceUtils; +import org.apache.brooklyn.util.core.ClassLoaderUtils; +import org.apache.brooklyn.util.core.flags.TypeCoercions; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.text.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +@HaHotStateRequired +public class AdjunctResource extends AbstractBrooklynRestResource implements AdjunctApi { + + private static final Logger log = LoggerFactory.getLogger(AdjunctResource.class); + + private @Context UriInfo ui; + + @Override + public List list(String application, String entityToken, String adjunctType) { + final Entity entity = brooklyn().getEntity(application, entityToken); + Iterable source = Collections.emptyList(); + boolean all = Strings.isBlank(adjunctType); + boolean any = false; + if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.POLICY.name())) { + any = true; + source = Iterables.concat(source, entity.policies()); + } + if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.ENRICHER.name())) { + any = true; + source = Iterables.concat(source, entity.enrichers()); + } + if (all || adjunctType.equalsIgnoreCase(BrooklynObjectType.FEED.name())) { + any = true; + source = Iterables.concat(source, ((EntityInternal)entity).feeds()); + } + if (!any) { + throw WebResourceUtils.badRequest("Unknown adjunct type '%s'; use 'policy', 'enricher', or 'feed'", adjunctType); + } + return FluentIterable.from(source) + .transform(new Function() { + @Override + public AdjunctSummary apply(EntityAdjunct adjunct) { + return AdjunctTransformer.adjunctSummary(entity, adjunct, ui.getBaseUriBuilder()); + } + }) + .toSortedList(SummaryComparators.nameComparator()); + } + + // TODO would like to make 'config' arg optional but jersey complains if we do + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public AdjunctSummary addAdjunct(String application, String entityToken, String adjunctTypeName, Map config) { + Entity entity = brooklyn().getEntity(application, entityToken); + if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_ENTITY, entity)) { + throw WebResourceUtils.forbidden("User '%s' is not authorized to modify entity '%s'", + Entitlements.getEntitlementContext().user(), entity); + } + + RegisteredType rt = brooklyn().getTypeRegistry().get(adjunctTypeName); + AbstractBrooklynObjectSpec spec; + if (rt!=null) { + spec = brooklyn().getTypeRegistry().createSpec(rt, null, null); + } else { + try { + Class type = new ClassLoaderUtils(this, mgmt()).loadClass(adjunctTypeName); + if (Policy.class.isAssignableFrom(type)) spec = PolicySpec.create((Class) type); + else if (Enricher.class.isAssignableFrom(type)) spec = EnricherSpec.create((Class) type); + else if (Feed.class.isAssignableFrom(type)) { + // TODO add FeedSpec ? would be needed even if using the type registry + throw WebResourceUtils.badRequest("Creation of feeds from java type (%s) not supported", adjunctTypeName); + } else { + throw WebResourceUtils.badRequest("Invalid type %s; not a support adjunct type", adjunctTypeName); + } + } catch (ClassNotFoundException e) { + throw WebResourceUtils.badRequest("No adjunct with type %s found", adjunctTypeName); + } catch (ClassCastException e) { + throw WebResourceUtils.badRequest("No adjunct with type %s found", adjunctTypeName); + } catch (Exception e) { + throw Exceptions.propagate(e); + } + } + + spec.configure(config); + + EntityAdjunct instance; + if (spec instanceof PolicySpec) instance = entity.policies().add((PolicySpec)spec); + else if (spec instanceof EnricherSpec) instance = entity.enrichers().add((EnricherSpec)spec); + else { + // TODO add FeedSpec + throw WebResourceUtils.badRequest("Unexpected spec type %s", spec); + } + + log.debug("REST API added adjunct " + instance + " to " + entity); + + return AdjunctTransformer.adjunctDetail(brooklyn(), entity, instance, ui.getBaseUriBuilder()); + } + + @Override + public AdjunctDetail get(String application, String entityToken, String adjunctId) { + Entity entity = brooklyn().getEntity(application, entityToken); + EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctId); + + return AdjunctTransformer.adjunctDetail(brooklyn(), entity, adjunct, ui.getBaseUriBuilder()); + } + + @Override + public Status getStatus(String application, String entityToken, String adjunctId) { + return AdjunctTransformer.inferStatus( brooklyn().getAdjunct(application, entityToken, adjunctId) ); + } + + @Override + public Response start(String application, String entityToken, String adjunctId) { + EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId); + if (adjunct instanceof Policy) ((Policy)adjunct).resume(); + else if (adjunct instanceof Feed) ((Feed)adjunct).resume(); + else throw WebResourceUtils.badRequest("%s does not support start/resume", adjunct); + + return Response.status(Response.Status.NO_CONTENT).build(); + } + + @Override + public Response stop(String application, String entityToken, String adjunctId) { + EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctId); + if (adjunct instanceof Policy) ((Policy)adjunct).suspend(); + else if (adjunct instanceof Feed) ((Feed)adjunct).suspend(); + else throw WebResourceUtils.badRequest("%s does not support suspend", adjunct); + + return Response.status(Response.Status.NO_CONTENT).build(); + } + + @Override + public Response destroy(String application, String entityToken, String adjunctId) { + Entity entity = brooklyn().getEntity(application, entityToken); + EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctId); + + if (adjunct instanceof Policy) { + ((Policy)adjunct).suspend(); + entity.policies().remove((Policy) adjunct); + } else if (adjunct instanceof Enricher) { + entity.enrichers().remove((Enricher) adjunct); + } else if (adjunct instanceof Feed) { + ((Feed)adjunct).suspend(); + ((EntityInternal)entity).feeds().remove((Feed) adjunct); + } else { + throw WebResourceUtils.badRequest("Unexpected adjunct type %s", adjunct); + } + + return Response.status(Response.Status.NO_CONTENT).build(); + } + + // ---- config ---- + + @Override + public List listConfig( + final String application, final String entityToken, final String adjunctToken) { + Entity entity = brooklyn().getEntity(application, entityToken); + EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken); + + List result = Lists.newArrayList(); + for (ConfigKey key : adjunct.config().findKeysPresent(Predicates.alwaysTrue())) { + result.add(ConfigTransformer.of(key).on(entity, adjunct).includeLinks(ui.getBaseUriBuilder(), false, true).transform()); + } + return result; + } + + // TODO support parameters ?show=value,summary&name=xxx &format={string,json,xml} --- End diff -- I'd move that comment to the `AdjunctsApi` interface, rather than in the impl (given it's about the api rather than the implementation). ---