From 45261c7e155e1022cd172d9816a647ba35f0218c Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Wed, 13 Sep 2017 16:22:56 +0100 Subject: [PATCH 1/6] add adjunct REST API, deprecating policy endpoint --- .../org/apache/brooklyn/api/sensor/Feed.java | 2 +- .../brooklyn/core/entity/AbstractEntity.java | 5 + .../brooklyn/core/entity/EntityInternal.java | 2 +- .../apache/brooklyn/core/policy/Policies.java | 30 +- .../apache/brooklyn/rest/api/AdjunctApi.java | 233 ++++++++++++++++ .../apache/brooklyn/rest/api/PolicyApi.java | 2 + .../brooklyn/rest/api/PolicyConfigApi.java | 27 +- .../brooklyn/rest/domain/AdjunctDetail.java | 72 +++++ .../brooklyn/rest/domain/AdjunctSummary.java | 150 ++++++++++ .../rest/domain/CatalogEnricherSummary.java | 2 + .../rest/domain/CatalogEntitySummary.java | 2 + .../rest/domain/CatalogItemSummary.java | 2 + .../rest/domain/CatalogLocationSummary.java | 2 + .../rest/domain/CatalogPolicySummary.java | 2 + .../rest/domain/EnricherConfigSummary.java | 3 +- .../rest/domain/PolicyConfigSummary.java | 3 +- .../brooklyn/rest/domain/PolicySummary.java | 83 +----- .../apache/brooklyn/rest/domain/Status.java | 7 +- .../apache/brooklyn/rest/BrooklynRestApi.java | 2 + .../rest/resources/AdjunctResource.java | 263 ++++++++++++++++++ .../rest/resources/PolicyConfigResource.java | 1 + .../rest/resources/PolicyResource.java | 1 + .../rest/transform/AdjunctTransformer.java | 117 ++++++++ .../rest/transform/EntityTransformer.java | 21 ++ .../rest/transform/PolicyTransformer.java | 3 + .../rest/util/BrooklynRestResourceUtils.java | 43 +++ 26 files changed, 983 insertions(+), 97 deletions(-) create mode 100644 rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java create mode 100644 rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java create mode 100644 rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java create mode 100644 rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java create mode 100644 rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java diff --git a/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java b/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java index d50e09271d..01a47148fb 100644 --- a/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java +++ b/api/src/main/java/org/apache/brooklyn/api/sensor/Feed.java @@ -43,7 +43,7 @@ public interface Feed extends EntityAdjunct, Rebindable { /** * True if everything has been _started_ (or it is starting) but not stopped, - * even if it is suspended; see also {@link #isActive()} + * even if it is suspended; see also {@link #isRunning()} */ boolean isActivated(); diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java index 08b6591a8d..8c31512f50 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java @@ -1951,6 +1951,11 @@ public boolean removeAllFeeds() { } return changed; } + + @Override + public Iterator iterator() { + return getFeeds().iterator(); + } } // -------- SENSORS -------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java index d6d51a1da4..7377f382d4 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java @@ -189,7 +189,7 @@ public interface SensorSupportInternal extends Entity.SensorSupport { void remove(AttributeSensor attribute); } - public interface FeedSupport { + public interface FeedSupport extends Iterable { Collection getFeeds(); diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java b/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java index db9bece948..4b32dfc218 100644 --- a/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java +++ b/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java @@ -20,7 +20,9 @@ import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntityLocal; +import org.apache.brooklyn.api.objs.EntityAdjunct; import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.api.sensor.Feed; import org.apache.brooklyn.api.sensor.Sensor; import org.apache.brooklyn.api.sensor.SensorEvent; import org.apache.brooklyn.api.sensor.SensorEventListener; @@ -28,6 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.Beta; + import groovy.lang.Closure; @SuppressWarnings({"rawtypes","unchecked"}) @@ -81,11 +85,27 @@ public void setEntity(EntityLocal entity) { } public static Lifecycle getPolicyStatus(Policy p) { - if (p.isRunning()) return Lifecycle.RUNNING; - if (p.isDestroyed()) return Lifecycle.DESTROYED; - if (p.isSuspended()) return Lifecycle.STOPPED; - // TODO could policy be in an error state? - return Lifecycle.CREATED; + return inferAdjunctStatus(p); + } + + @Beta + public static Lifecycle inferAdjunctStatus(EntityAdjunct a) { + if (a.isRunning()) return Lifecycle.RUNNING; + if (a.isDestroyed()) return Lifecycle.DESTROYED; + + // adjuncts don't currently support an "error" state; though that would be useful! + + if (a instanceof Policy) { + if (((Policy)a).isSuspended()) return Lifecycle.STOPPED; + return Lifecycle.CREATED; + } + if (a instanceof Feed) { + if (((Feed)a).isSuspended()) return Lifecycle.STOPPED; + if (((Feed)a).isActivated()) return Lifecycle.STARTING; + return Lifecycle.CREATED; + } + + return Lifecycle.STOPPED; } } diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java new file mode 100644 index 0000000000..5fc13663e6 --- /dev/null +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java @@ -0,0 +1,233 @@ +/* + * 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.api; + +import java.util.List; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +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; +import javax.ws.rs.core.Response; + +import org.apache.brooklyn.rest.domain.AdjunctConfigSummary; +import org.apache.brooklyn.rest.domain.AdjunctDetail; +import org.apache.brooklyn.rest.domain.AdjunctSummary; +import org.apache.brooklyn.rest.domain.Status; + +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; + +@Path("/applications/{application}/entities/{entity}/adjuncts") +@Api("Entity Adjuncts (policies, enrichers, feeds)") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public interface AdjunctApi { + + @GET + @ApiOperation(value = "Fetch the adjuncts attached to a specific application entity", + response = org.apache.brooklyn.rest.domain.AdjunctSummary.class, + responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application or entity") + }) + public List list( + @ApiParam(value = "Application ID or name", required = true) + @PathParam("application") final String application, + @ApiParam(value = "Entity ID or name", required = true) + @PathParam("entity") final String entityToken, + @ApiParam(value = "Filter by adjunct type", required = false) + @QueryParam("adjunctType") final String adjunctType); + + @POST + @ApiOperation(value = "Add an adjunct (policy, enricher, or feed)", notes = "Returns a summary of the added adjunct") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application or entity"), + @ApiResponse(code = 400, message = "Type is not a suitable adjunct") + }) + public AdjunctSummary addAdjunct( + @ApiParam(name = "application", value = "Application ID or name", required = true) + @PathParam("application") String application, + + @ApiParam(name = "entity", value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + + @ApiParam(name = "type", value = "Adjunct from the type registry to instantiate and add", required = true) + @QueryParam("type") + String adjunctRegisteredTypeName, + + // TODO would like to make this optional but jersey complains if we do + @ApiParam(name = "config", value = "Configuration for the adjunct (as key value pairs)", required = true) + Map config); + + @GET + @Path("/{adjunct}") + @ApiOperation(value = "Gets detail of an adjunct") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application, entity or adjunct") + }) + public AdjunctDetail get( + @ApiParam(name = "application", value = "Application ID or name", required = true) + @PathParam("application") String application, + + @ApiParam(name = "entity", value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + + @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true) + @PathParam("adjunct") String adjunctId); + + @GET + @Path("/{adjunct}/status") + @ApiOperation(value = "Gets status of an adjunct (RUNNING / SUSPENDED)") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application, entity or adjunct") + }) + public Status getStatus( + @ApiParam(name = "application", value = "Application ID or name", required = true) + @PathParam("application") String application, + + @ApiParam(name = "entity", value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + + @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true) + @PathParam("adjunct") String adjunctId); + + @POST + @Path("/{adjunct}/start") + @ApiOperation(value = "Start or resume an adjunct") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application, entity or adjunct") + }) + public Response start( + @ApiParam(name = "application", value = "Application ID or name", required = true) + @PathParam("application") String application, + + @ApiParam(name = "entity", value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + + @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true) + @PathParam("adjunct") String adjunctId); + + @POST + @Path("/{adjunct}/stop") + @ApiOperation(value = "Suspends an adjunct") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application, entity or adjunct") + }) + public Response stop( + @ApiParam(name = "application", value = "Application ID or name", required = true) + @PathParam("application") String application, + + @ApiParam(name = "entity", value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + + @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true) + @PathParam("adjunct") String adjunctId); + + @DELETE + @Path("/{adjunct}") + @ApiOperation(value = "Destroy an adjunct", notes="Removes an adjunct from being associated with the entity and destroys it (stopping first if running)") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application, entity or adjunct") + }) + public Response destroy( + @ApiParam(name = "application", value = "Application ID or name", required = true) + @PathParam("application") String application, + + @ApiParam(name = "entity", value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + + @ApiParam(name = "adjunct", value = "Adjunct ID or name", required = true) + @PathParam("adjunct") String adjunctId); + + /// ---------- config --------------- + + @GET + @Path("/{adjunct}/config") + @ApiOperation(value = "Fetch the config keys for a specific adjunct", + response = org.apache.brooklyn.rest.domain.AdjunctConfigSummary.class, + responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application or entity or adjunct") + }) + public List listConfig( + @ApiParam(value = "Application ID or name", required = true) + @PathParam("application") final String application, + @ApiParam(value = "Entity ID or name", required = true) + @PathParam("entity") final String entityToken, + @ApiParam(value = "Adjunct ID or name", required = true) + @PathParam("adjunct") final String adjunctToken); + + // TODO support parameters ?show=value,summary&name=xxx &format={string,json,xml} + // (and in sensors class) + @GET + @Path("/{adjunct}/config-current") + @ApiOperation(value = "Fetch config key values in batch", notes="Returns a map of config name to value") + public Map batchConfigRead( + @ApiParam(value = "Application ID or name", required = true) + @PathParam("application") String application, + @ApiParam(value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + @ApiParam(value = "Adjunct ID or name", required = true) + @PathParam("adjunct") String adjunctToken) ; + + @GET + @Path("/{adjunct}/config/{config}") + @ApiOperation(value = "Fetch config value", response = Object.class) + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application, entity, adjunct or config key") + }) + public String getConfig( + @ApiParam(value = "Application ID or name", required = true) + @PathParam("application") String application, + @ApiParam(value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + @ApiParam(value = "Adjunct ID or name", required = true) + @PathParam("adjunct") String adjunctToken, + @ApiParam(value = "Config key ID", required = true) + @PathParam("config") String configKeyName); + + @POST + @Path("/{adjunct}/config/{config}") + @Consumes(value = {"*/*"}) + @ApiOperation(value = "Sets the given config on this adjunct") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "Could not find application, entity, adjunct or config key") + }) + public Response setConfig( + @ApiParam(value = "Application ID or name", required = true) + @PathParam("application") String application, + @ApiParam(value = "Entity ID or name", required = true) + @PathParam("entity") String entityToken, + @ApiParam(value = "Adjunct ID or name", required = true) + @PathParam("adjunct") String adjunctToken, + @ApiParam(value = "Config key ID", required = true) + @PathParam("config") String configKeyName, + @ApiParam(name = "value", value = "New value for the configuration", required = true) + Object value); +} diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java index a698f7de65..329c0e1cbb 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java @@ -36,6 +36,8 @@ @Api("Entity Policies") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) +/** @deprecated since 0.12.0 use AdjunctApi */ +@Deprecated public interface PolicyApi { @GET diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java index 1e6bfe67a7..06a4b86c33 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java @@ -18,23 +18,32 @@ */ package org.apache.brooklyn.rest.api; -import io.swagger.annotations.Api; -import org.apache.brooklyn.rest.domain.PolicyConfigSummary; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; +import java.util.List; +import java.util.Map; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.util.List; -import java.util.Map; + +import org.apache.brooklyn.rest.domain.PolicyConfigSummary; + +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; @Path("/applications/{application}/entities/{entity}/policies/{policy}/config") @Api("Entity Policy Config") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) +/** @deprecated since 0.12.0 use AdjunctApi */ +@Deprecated public interface PolicyConfigApi { @GET diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java new file mode 100644 index 0000000000..ddce5f4348 --- /dev/null +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctDetail.java @@ -0,0 +1,72 @@ +/* + * 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.domain; + +import java.util.Map; +import java.util.Set; + +import org.apache.brooklyn.api.objs.EntityAdjunct; +import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.collections.MutableSet; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +public class AdjunctDetail extends AdjunctSummary { + + private static final long serialVersionUID = -5086680835225136768L; + + @JsonInclude(Include.NON_EMPTY) + private String functionallyUniqueIdentifier; + @JsonInclude(Include.NON_EMPTY) + private Set tags; + @JsonInclude(Include.NON_EMPTY) + final Set parameters = MutableSet.of(); + final Map config = MutableMap.of(); + + // for json + protected AdjunctDetail() {} + + public AdjunctDetail(EntityAdjunct a) { + super(a); + this.functionallyUniqueIdentifier = a.getUniqueTag(); + this.tags = a.tags().getTags(); + } + + public String getFunctionallyUniqueIdentifier() { + return functionallyUniqueIdentifier; + } + + public Set getTags() { + return tags; + } + + public AdjunctDetail parameter(AdjunctConfigSummary p) { + parameters.add(p); return this; + } + + public AdjunctDetail config(String key, Object val) { + config.put(key, val); return this; + } + + public AdjunctDetail config(Map vals) { + config.putAll(vals); return this; + } + +} diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java new file mode 100644 index 0000000000..ca80644cbd --- /dev/null +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java @@ -0,0 +1,150 @@ +/* + * 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.domain; + +import java.io.Serializable; +import java.net.URI; +import java.util.Map; +import java.util.Objects; + +import org.apache.brooklyn.api.objs.BrooklynObjectType; +import org.apache.brooklyn.api.objs.EntityAdjunct; +import org.apache.brooklyn.api.objs.HighlightTuple; +import org.apache.brooklyn.api.objs.Identifiable; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.google.common.collect.ImmutableMap; + +public class AdjunctSummary implements HasName, Serializable, Identifiable { + + private static final long serialVersionUID = -8106551648118942612L; + + private String id; + private String name; + private BrooklynObjectType adjunctType; + @JsonInclude(Include.NON_EMPTY) + private String catalogItemId; + private Status state; + @JsonInclude(Include.NON_EMPTY) + private Map highlights; + + private Map links; + + // for json + protected AdjunctSummary() {} + + public AdjunctSummary(EntityAdjunct a) { + id = a.getId(); + name = a.getDisplayName(); + adjunctType = BrooklynObjectType.of(a); + catalogItemId = a.getCatalogItemId(); + highlights = a.getHighlights(); + } + + /** @deprecated since 0.12.0 only for legacy type-specific summary classes */ + @Deprecated + protected AdjunctSummary( + String id, + String name, + BrooklynObjectType adjunctType, + String catalogItemId, + Status state, + Map highlights, + Map links) { + this.id = id; + this.name = name; + this.adjunctType = adjunctType; + this.catalogItemId = catalogItemId; + this.state = state; + this.highlights = (highlights == null) ? ImmutableMap.of() : ImmutableMap.copyOf(highlights); + this.links = (links == null) ? ImmutableMap. of() : ImmutableMap.copyOf(links); + } + + @Override + public String getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + public BrooklynObjectType getAdjunctType() { + return adjunctType; + } + + public String getCatalogItemId() { + return catalogItemId; + } + + public Status getState() { + return state; + } + + public Map getHighlights() { + return highlights; + } + + public Map getLinks() { + return links; + } + + public AdjunctSummary state(Status state) { + this.state = state; return this; + } + + public AdjunctSummary links(Map links) { + this.links = links; return this; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AdjunctSummary)) return false; + AdjunctSummary that = (AdjunctSummary) o; + return Objects.equals(id, that.id) && + Objects.equals(name, that.name) && + Objects.equals(adjunctType, that.adjunctType) && + Objects.equals(catalogItemId, that.catalogItemId) && + Objects.equals(state, that.state) && + Objects.equals(highlights, that.highlights) && + Objects.equals(links, that.links) ; + } + + @Override + public int hashCode() { + return Objects.hash(id, name, adjunctType, catalogItemId, state, highlights, links); + } + + @Override + public String toString() { + return (adjunctType!=null ? adjunctType.name() : "AdjunctSummary")+"{" + + "id='" + id + '\'' + + ", name='" + name + '\'' + + ", catalogItemId='" + catalogItemId + '\'' + + ", state='" + state + '\'' + + ", highlights=" + highlights + + ", links=" + links + + '}'; + } + +} diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java index 2e81ae1709..c65551533a 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java @@ -27,6 +27,8 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.collect.ImmutableSet; +/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +@Deprecated public class CatalogEnricherSummary extends CatalogItemSummary { private static final long serialVersionUID = -588856488327394445L; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java index 5947b7f06c..7dbc1beebf 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java @@ -27,6 +27,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +@Deprecated public class CatalogEntitySummary extends CatalogItemSummary { private static final long serialVersionUID = 1063908984191424539L; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java index cdb86d4eec..cd85c13bba 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java @@ -36,6 +36,8 @@ * see also, subclasses */ @JsonIgnoreProperties(ignoreUnknown = true) // ignore unknown, ie properties from subclasses (entity) +/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +@Deprecated public class CatalogItemSummary implements HasId, HasName, Serializable { private static final long serialVersionUID = -823483595879417681L; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java index 0213a0c890..5fb1a4b59c 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java @@ -26,6 +26,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableSet; +/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +@Deprecated public class CatalogLocationSummary extends CatalogItemSummary { private static final long serialVersionUID = 8420991584336514673L; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java index 37e5786d2b..ad67786a9c 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java @@ -27,6 +27,8 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.collect.ImmutableSet; +/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +@Deprecated public class CatalogPolicySummary extends CatalogItemSummary { private static final long serialVersionUID = -588856488327394445L; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java index c868fb82c0..7b402060e8 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java @@ -23,7 +23,8 @@ import org.apache.brooklyn.config.ConfigKey; -// TODO remove? this class has no value over its super +/** @deprecated since 0.12.0 new {@link AdjunctConfigSummary}; this class does nothing additional */ +@Deprecated public class EnricherConfigSummary extends AdjunctConfigSummary { private static final long serialVersionUID = 4339330833863794513L; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java index 5dfb898bc4..797bd0c8c0 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java @@ -23,7 +23,8 @@ import org.apache.brooklyn.config.ConfigKey; -//TODO remove? this class has no value over its super +/** @deprecated since 0.12.0 new {@link AdjunctConfigSummary}; this class does nothing additional */ +@Deprecated public class PolicyConfigSummary extends AdjunctConfigSummary { private static final long serialVersionUID = 4339330833863794513L; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java index ce9c9e0ca1..da4a86a05e 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java @@ -18,29 +18,20 @@ */ package org.apache.brooklyn.rest.domain; -import java.io.Serializable; import java.net.URI; import java.util.Map; -import java.util.Objects; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.google.common.collect.ImmutableMap; +import org.apache.brooklyn.api.objs.BrooklynObjectType; import org.apache.brooklyn.api.objs.HighlightTuple; -public class PolicySummary implements HasName, HasId, Serializable { +import com.fasterxml.jackson.annotation.JsonProperty; + +/** @deprecated since 0.12.0 use {@link AdjunctSummary}; this class is identical */ +@Deprecated +public class PolicySummary extends AdjunctSummary { private static final long serialVersionUID = -5086680835225136768L; - private final String id; - private final String name; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) - private final String catalogItemId; - private final Status state; - private final Map links; - private final Map highlights; - public PolicySummary( @JsonProperty("id") String id, @JsonProperty("name") String name, @@ -48,67 +39,7 @@ public PolicySummary( @JsonProperty("state") Status state, @JsonProperty("highlights") Map highlights, @JsonProperty("links") Map links) { - this.id = id; - this.name = name; - this.catalogItemId = catalogItemId; - this.state = state; - this.links = (links == null) ? ImmutableMap. of() : ImmutableMap.copyOf(links); - this.highlights = (highlights == null) ? ImmutableMap.of() : ImmutableMap.copyOf(highlights); - } - - @Override - public String getId() { - return id; - } - - @Override - public String getName() { - return name; - } - - public String getCatalogItemId() { - return catalogItemId; + super(id, name, BrooklynObjectType.POLICY, catalogItemId, state, highlights, links); } - public Status getState() { - return state; - } - - public Map getLinks() { - return links; - } - - public Map getHighlights() { - return highlights; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof PolicySummary)) return false; - PolicySummary that = (PolicySummary) o; - return Objects.equals(id, that.id) && - Objects.equals(name, that.name) && - Objects.equals(catalogItemId, that.catalogItemId) && - state == that.state && - Objects.equals(highlights, that.highlights) && - Objects.equals(links, that.links) ; - } - - @Override - public int hashCode() { - return Objects.hash(id, name, catalogItemId, state, highlights, links); - } - - @Override - public String toString() { - return "PolicySummary{" + - "id='" + id + '\'' + - ", name='" + name + '\'' + - ", catalogItemId='" + catalogItemId + '\'' + - ", state=" + state + - ", highlights=" + highlights + - ", links=" + links + - '}'; - } } diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java index e2b2ce4d3e..4a998c7ab4 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/Status.java @@ -18,9 +18,10 @@ */ package org.apache.brooklyn.rest.domain; -/** - * @author Adam Lowe - */ +import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; + +/** Canonical set, similar to {@link Lifecycle}, but cleaned up for outside consumption + * and more appropriate for adjunct types */ public enum Status { ACCEPTED, STARTING, diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java index b3eb4e48cd..233d717242 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java @@ -24,6 +24,7 @@ import org.apache.brooklyn.rest.resources.AbstractBrooklynRestResource; import org.apache.brooklyn.rest.resources.AccessResource; import org.apache.brooklyn.rest.resources.ActivityResource; +import org.apache.brooklyn.rest.resources.AdjunctResource; import org.apache.brooklyn.rest.resources.ApidocResource; import org.apache.brooklyn.rest.resources.ApplicationResource; import org.apache.brooklyn.rest.resources.BundleResource; @@ -63,6 +64,7 @@ public static Iterable getBrooklynRestResources() resources.add(new EntityConfigResource()); resources.add(new SensorResource()); resources.add(new EffectorResource()); + resources.add(new AdjunctResource()); resources.add(new PolicyResource()); resources.add(new PolicyConfigResource()); resources.add(new ActivityResource()); diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java new file mode 100644 index 0000000000..9dd4c10ec8 --- /dev/null +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java @@ -0,0 +1,263 @@ +/* + * 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.AdjunctConfigSummary; +import org.apache.brooklyn.rest.domain.AdjunctDetail; +import org.apache.brooklyn.rest.domain.AdjunctSummary; +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.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(AdjunctTransformer.configSummary(brooklyn(), entity, adjunct, key, ui.getBaseUriBuilder())); + } + return result; + } + + // TODO support parameters ?show=value,summary&name=xxx &format={string,json,xml} + // (and in sensors class) + @Override + public Map batchConfigRead(String application, String entityToken, String adjunctToken) { + // TODO: add test + return EntityTransformer.getConfigValues(brooklyn(), brooklyn().getAdjunct(application, entityToken, adjunctToken) ); + } + + @Override + public String getConfig(String application, String entityToken, String adjunctToken, String configKeyName) { + EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctToken); + Set> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName))); + if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken); + + return brooklyn().getStringValueForDisplay(adjunct.config().get(cki.iterator().next())); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Response setConfig(String application, String entityToken, String adjunctToken, String configKeyName, Object value) { + 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); + } + + EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken); + Set> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName))); + if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken); + ConfigKey ck = cki.iterator().next(); + + adjunct.config().set((ConfigKey) cki, TypeCoercions.coerce(value, ck.getTypeToken())); + + return Response.status(Response.Status.OK).build(); + } + + public static String getStringValueForDisplay(BrooklynRestResourceUtils utils, EntityAdjunct policy, Object value) { + return utils.getStringValueForDisplay(value); + } + +} diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java index 6dcdf197fa..1fca535196 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java @@ -41,6 +41,7 @@ import com.google.common.collect.Maps; @HaHotStateRequired +@Deprecated public class PolicyConfigResource extends AbstractBrooklynRestResource implements PolicyConfigApi { @Override diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java index 0b8d2c25c3..125b0b7181 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java @@ -47,6 +47,7 @@ import com.google.common.collect.Maps; @HaHotStateRequired +@Deprecated public class PolicyResource extends AbstractBrooklynRestResource implements PolicyApi { private static final Logger log = LoggerFactory.getLogger(PolicyResource.class); diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java new file mode 100644 index 0000000000..db7d4cda0c --- /dev/null +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java @@ -0,0 +1,117 @@ +/* + * 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.transform; + +import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder; + +import java.net.URI; +import java.util.Map; + +import javax.ws.rs.core.UriBuilder; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.objs.EntityAdjunct; +import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.api.sensor.Feed; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.policy.Policies; +import org.apache.brooklyn.rest.api.AdjunctApi; +import org.apache.brooklyn.rest.api.ApplicationApi; +import org.apache.brooklyn.rest.api.EntityApi; +import org.apache.brooklyn.rest.domain.AdjunctConfigSummary; +import org.apache.brooklyn.rest.domain.AdjunctDetail; +import org.apache.brooklyn.rest.domain.AdjunctSummary; +import org.apache.brooklyn.rest.domain.ApplicationSummary; +import org.apache.brooklyn.rest.domain.Status; +import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils; +import org.apache.brooklyn.util.collections.MutableMap; + +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableMap; + +/** + * Converts from Brooklyn entities to restful API summary objects + */ +public class AdjunctTransformer { + + public static AdjunctSummary adjunctSummary(Entity entity, EntityAdjunct adjunct, UriBuilder ub) { + return embellish(new AdjunctSummary(adjunct), entity, adjunct, ub); + } + + @SuppressWarnings("unchecked") + private static T embellish(T adjunctSummary, Entity entity, EntityAdjunct adjunct, UriBuilder ub) { + return (T) adjunctSummary.state(inferStatus(adjunct)).links( buildLinks(entity, adjunct, ub, adjunctSummary instanceof AdjunctDetail) ); + } + + public static AdjunctDetail adjunctDetail(BrooklynRestResourceUtils utils, Entity entity, EntityAdjunct adjunct, UriBuilder ub) { + AdjunctDetail result = embellish(new AdjunctDetail(adjunct), entity, adjunct, ub); + for (ConfigKey key: adjunct.config().findKeysDeclared(Predicates.alwaysTrue())) { + result.parameter(configSummary(utils, entity, adjunct, key, ub)); + } + result.config(EntityTransformer.getConfigValues(utils, adjunct)); + return result; + } + + protected static Map buildLinks(Entity entity, EntityAdjunct adjunct, UriBuilder ub, boolean detail) { + MutableMap links = MutableMap.of(); + + links.put("self", serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); + + if (detail) { + links.put("application", serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId())); + links.put("entity", serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId())); + links.put("config", serviceUriBuilder(ub, AdjunctApi.class, "listConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); + links.put("status", serviceUriBuilder(ub, AdjunctApi.class, "getStatus").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); + if (adjunct instanceof Policy || adjunct instanceof Feed) { + links.put("start", serviceUriBuilder(ub, AdjunctApi.class, "start").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); + links.put("stop", serviceUriBuilder(ub, AdjunctApi.class, "stop").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); + } + links.put("destroy", serviceUriBuilder(ub, AdjunctApi.class, "destroy").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); + } + + return links.asUnmodifiable(); + } + + public static Status inferStatus(EntityAdjunct adjunct) { + return ApplicationTransformer.statusFromLifecycle( Policies.inferAdjunctStatus(adjunct) ); + } + + public static AdjunctConfigSummary configSummary(BrooklynRestResourceUtils utils, ApplicationSummary application, Entity entity, EntityAdjunct adjunct, ConfigKey config, UriBuilder ub) { + return configSummary(utils, entity, adjunct, config, ub); + } + + public static AdjunctConfigSummary configSummary(BrooklynRestResourceUtils utils, Entity entity, EntityAdjunct adjunct, ConfigKey config, UriBuilder ub) { + URI applicationUri = serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId()); + URI entityUri = serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId()); + URI adjunctUri = serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId()); + URI configUri = serviceUriBuilder(ub, AdjunctApi.class, "getConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId(), config.getName()); + + Map links = ImmutableMap.builder() + .put("self", configUri) + .put("application", applicationUri) + .put("entity", entityUri) + .put("policy", adjunctUri) + .build(); + + return new AdjunctConfigSummary(config.getName(), config.getTypeName(), config.getDescription(), + utils.getStringValueForDisplay(config.getDefaultValue()), + config.isReconfigurable(), + links); + } +} diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java index 6bf3f19aa0..cb7877fcd5 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java @@ -32,10 +32,12 @@ import org.apache.brooklyn.api.catalog.CatalogConfig; import org.apache.brooklyn.api.entity.Application; import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.objs.SpecParameter; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.config.render.RendererHints; +import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.apache.brooklyn.core.typereg.RegisteredTypes; import org.apache.brooklyn.rest.api.ApplicationApi; import org.apache.brooklyn.rest.api.CatalogApi; @@ -46,12 +48,15 @@ import org.apache.brooklyn.rest.domain.EntityConfigSummary; import org.apache.brooklyn.rest.domain.EntitySummary; import org.apache.brooklyn.rest.domain.PolicyConfigSummary; +import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.config.ConfigBag; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; /** * @author Adam Lowe @@ -84,6 +89,7 @@ public static EntitySummary entitySummary(Entity entity, UriBuilder ub) { .put("config", URI.create(entityUri + "/config")) .put("sensors", URI.create(entityUri + "/sensors")) .put("effectors", URI.create(entityUri + "/effectors")) + .put("adjuncts", URI.create(entityUri + "/adjuncts")) .put("policies", URI.create(entityUri + "/policies")) .put("activities", URI.create(entityUri + "/activities")) .put("locations", URI.create(entityUri + "/locations")) @@ -212,4 +218,19 @@ public static EnricherConfigSummary enricherConfigSummary(SpecParameter input Double priority = input.isPinned() ? Double.valueOf(1d) : null; return enricherConfigSummary(input.getConfigKey(), input.getLabel(), priority, null); } + + public static Map getConfigValues(BrooklynRestResourceUtils utils, BrooklynObject obj) { + // alternatively could do this - should be the same ? +// for (ConfigKey key: adjunct.config().findKeysPresent(Predicates.alwaysTrue())) { +// result.config(key.getName(), utils.getStringValueForDisplay( adjunct.config().get(key) )); +// } + + Map source = ConfigBag.newInstance( + ((BrooklynObjectInternal)obj).config().getInternalConfigMap().getAllConfigInheritedRawValuesIgnoringErrors() ).getAllConfig(); + Map result = Maps.newLinkedHashMap(); + for (Map.Entry ek : source.entrySet()) { + result.put(ek.getKey(), utils.getStringValueForDisplay(ek.getValue())); + } + return result; + } } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java index 8dad949188..294fd41f04 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java @@ -25,6 +25,7 @@ import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.policy.Policies; +import org.apache.brooklyn.rest.domain.AdjunctSummary; import org.apache.brooklyn.rest.domain.ApplicationSummary; import org.apache.brooklyn.rest.domain.PolicyConfigSummary; import org.apache.brooklyn.rest.domain.PolicySummary; @@ -42,7 +43,9 @@ /** * Converts from Brooklyn entities to restful API summary objects + * @deprecated since 0.12.0 use {@link AdjunctTransformer} and {@link AdjunctSummary} */ +@Deprecated public class PolicyTransformer { public static PolicySummary policySummary(Entity entity, Policy policy, UriBuilder ub) { diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java index 9e1ce53670..9b0a3d46ff 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java @@ -38,7 +38,10 @@ import org.apache.brooklyn.api.location.LocationRegistry; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.Task; +import org.apache.brooklyn.api.objs.EntityAdjunct; import org.apache.brooklyn.api.policy.Policy; +import org.apache.brooklyn.api.sensor.Enricher; +import org.apache.brooklyn.api.sensor.Feed; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry; import org.apache.brooklyn.api.typereg.RegisteredType; import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants; @@ -112,6 +115,16 @@ public LocationRegistry getLocationRegistry() { public Policy getPolicy(String application, String entity, String policy) { return getPolicy(getEntity(application, entity), policy); } + + /** finds the policy indicated by the given ID or name. + * @see {@link #getEntity(String,String)}; it then searches the policies of that + * entity for one whose ID or name matches that given. + *

+ * + * @throws 404 or 412 (unless input is null in which case output is null) */ + public EntityAdjunct getAdjunct(String application, String entity, String adjunct) { + return getAdjunct(getEntity(application, entity), adjunct); + } /** finds the policy indicated by the given ID or name. * @see {@link #getPolicy(String,String,String)}. @@ -130,6 +143,36 @@ public Policy getPolicy(Entity entity, String policy) { throw WebResourceUtils.notFound("Cannot find policy '%s' in entity '%s'", policy, entity); } + + /** finds the policy indicated by the given ID or name. + * @see {@link #getAdjunct(String,String,String)}. + *

+ * + * @throws 404 or 412 (unless input is null in which case output is null) */ + public EntityAdjunct getAdjunct(Entity entity, String adjunct) { + if (adjunct==null) return null; + + for (Policy p: entity.policies()) { + if (adjunct.equals(p.getId())) return p; + } + for (Policy p: entity.policies()) { + if (adjunct.equals(p.getDisplayName())) return p; + } + for (Enricher p: entity.enrichers()) { + if (adjunct.equals(p.getId())) return p; + } + for (Enricher p: entity.enrichers()) { + if (adjunct.equals(p.getDisplayName())) return p; + } + for (Feed p: ((EntityInternal)entity).feeds()) { + if (adjunct.equals(p.getId())) return p; + } + for (Feed p: ((EntityInternal)entity).feeds()) { + if (adjunct.equals(p.getDisplayName())) return p; + } + + throw WebResourceUtils.notFound("Cannot find adjunct '%s' in entity '%s'", adjunct, entity); + } /** finds the entity indicated by the given ID or name *

From 83c3d5006e653d4d70ebbf46759bf7ecd29c581a Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Mon, 25 Sep 2017 13:00:46 +0100 Subject: [PATCH 2/6] clean up config rest utils following deprecation of config classes --- .../rest/resources/AdjunctResource.java | 3 +- .../rest/resources/CatalogResource.java | 21 ++- .../rest/resources/EntityConfigResource.java | 4 +- .../rest/transform/AdjunctTransformer.java | 34 +--- .../rest/transform/CatalogTransformer.java | 30 +-- .../rest/transform/ConfigTransformer.java | 173 ++++++++++++++++++ .../rest/transform/EntityTransformer.java | 114 ++---------- .../rest/transform/SensorTransformer.java | 21 ++- .../rest/transform/TypeTransformer.java | 6 +- .../brooklyn/cli/lister/ItemDescriptors.java | 10 +- 10 files changed, 257 insertions(+), 159 deletions(-) create mode 100644 rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java index 3b5185a354..08f3698c73 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java @@ -49,6 +49,7 @@ 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; @@ -215,7 +216,7 @@ public List listConfig( List result = Lists.newArrayList(); for (ConfigKey key : adjunct.config().findKeysPresent(Predicates.alwaysTrue())) { - result.add(AdjunctTransformer.configSummary(brooklyn(), ui.getBaseUriBuilder(), entity, adjunct, key)); + result.add(ConfigTransformer.of(key).on(entity, adjunct).includeLinks(ui.getBaseUriBuilder(), false, true).transform()); } return result; } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java index 65e695675c..f95c1ee3b9 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java @@ -84,6 +84,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat private static final Logger log = LoggerFactory.getLogger(CatalogResource.class); private static final String LATEST = "latest"; + @Deprecated private Function toCatalogItemSummary(final UriInfo ui) { return new Function() { @Override @@ -202,11 +203,13 @@ private Response buildCreateResponse(Iterable catalogItems) { } @Override + @Deprecated public void deleteApplication(String symbolicName, String version) throws Exception { deleteEntity(symbolicName, version); } @Override + @Deprecated public void deleteEntity(String symbolicName, String version) throws Exception { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(symbolicName+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog", @@ -226,6 +229,7 @@ public void deleteEntity(String symbolicName, String version) throws Exception { } @Override + @Deprecated public void deletePolicy(String policyId, String version) throws Exception { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(policyId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog", @@ -245,6 +249,7 @@ public void deletePolicy(String policyId, String version) throws Exception { } @Override + @Deprecated public void deleteLocation(String locationId, String version) throws Exception { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(locationId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog", @@ -264,6 +269,7 @@ public void deleteLocation(String locationId, String version) throws Exception { } @Override + @Deprecated public List listEntities(String regex, String fragment, boolean allVersions) { Predicate filter = Predicates.and( @@ -274,6 +280,7 @@ public List listEntities(String regex, String fragment, bo } @Override + @Deprecated public List listApplications(String regex, String fragment, boolean allVersions) { @SuppressWarnings("unchecked") Predicate filter = @@ -285,6 +292,7 @@ public List listApplications(String regex, String fragment, } @Override + @Deprecated public CatalogEntitySummary getEntity(String symbolicName, String version) { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, symbolicName+(Strings.isBlank(version)?"":":"+version))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry", @@ -302,11 +310,13 @@ public CatalogEntitySummary getEntity(String symbolicName, String version) { } @Override + @Deprecated public CatalogEntitySummary getApplication(String symbolicName, String version) { return getEntity(symbolicName, version); } @Override + @Deprecated public List listPolicies(String regex, String fragment, boolean allVersions) { Predicate filter = Predicates.and( @@ -317,6 +327,7 @@ public List listPolicies(String regex, String fragment, bo } @Override + @Deprecated public CatalogPolicySummary getPolicy(String policyId, String version) throws Exception { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, policyId+(Strings.isBlank(version)?"":":"+version))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry", @@ -333,6 +344,7 @@ public CatalogPolicySummary getPolicy(String policyId, String version) throws Ex } @Override + @Deprecated public List listLocations(String regex, String fragment, boolean allVersions) { Predicate filter = Predicates.and( @@ -343,6 +355,7 @@ public List listLocations(String regex, String fragment, } @Override + @Deprecated public CatalogLocationSummary getLocation(String locationId, String version) throws Exception { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, locationId+(Strings.isBlank(version)?"":":"+version))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry", @@ -359,6 +372,7 @@ public CatalogLocationSummary getLocation(String locationId, String version) thr } @SuppressWarnings({ "unchecked", "rawtypes" }) + @Deprecated private List getCatalogItemSummariesMatchingRegexFragment( Predicate type, String regex, String fragment, boolean allVersions) { List> filters = new ArrayList(); @@ -390,8 +404,8 @@ public Response getIcon(String itemId, String version) { return getCatalogItemIcon(mgmt().getTypeRegistry().get(itemId, version)); } - @SuppressWarnings("deprecation") @Override + @Deprecated public void setDeprecated(String itemId, boolean deprecated) { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(itemId, "deprecated"))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog", @@ -400,8 +414,8 @@ public void setDeprecated(String itemId, boolean deprecated) { CatalogUtils.setDeprecated(mgmt(), itemId, deprecated); } - @SuppressWarnings("deprecation") @Override + @Deprecated public void setDisabled(String itemId, boolean disabled) { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(itemId, "disabled"))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog", @@ -411,6 +425,7 @@ public void setDisabled(String itemId, boolean disabled) { } @Override + @Deprecated public List listEnrichers(@ApiParam(name = "regex", value = "Regular expression to search for") @DefaultValue("") String regex, @ApiParam(name = "fragment", value = "Substring case-insensitive to search for") @DefaultValue("") String fragment, @ApiParam(name = "allVersions", value = "Include all versions (defaults false, only returning the best version)") @DefaultValue("false") boolean includeAllVersions) { Predicate filter = Predicates.and( @@ -421,6 +436,7 @@ public List listEnrichers(@ApiParam(name = "regex", valu } @Override + @Deprecated public CatalogEnricherSummary getEnricher(@ApiParam(name = "enricherId", value = "The ID of the enricher to retrieve", required = true) String enricherId, @ApiParam(name = "version", value = "The version identifier of the enricher to retrieve", required = true) String version) throws Exception { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, enricherId+(Strings.isBlank(version)?"":":"+version))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry", @@ -436,6 +452,7 @@ public CatalogEnricherSummary getEnricher(@ApiParam(name = "enricherId", value = } @Override + @Deprecated public void deleteEnricher(@ApiParam(name = "enricherId", value = "The ID of the enricher to delete", required = true) String enricherId, @ApiParam(name = "version", value = "The version identifier of the enricher to delete", required = true) String version) throws Exception { if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(enricherId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) { throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog", diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java index dd909e4c75..3431b99f5d 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java @@ -34,7 +34,7 @@ import org.apache.brooklyn.rest.api.EntityConfigApi; import org.apache.brooklyn.rest.domain.ConfigSummary; import org.apache.brooklyn.rest.filter.HaHotStateRequired; -import org.apache.brooklyn.rest.transform.EntityTransformer; +import org.apache.brooklyn.rest.transform.ConfigTransformer; import org.apache.brooklyn.rest.util.WebResourceUtils; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.core.task.Tasks; @@ -70,7 +70,7 @@ public List list(final String application, final String entityTok new Object[] {Entitlements.getEntitlementContext().user(), key.getName(), entity}); continue; } - result.add(EntityTransformer.configSummary(brooklyn(), ui.getBaseUriBuilder(), entity, key)); + result.add(ConfigTransformer.of(key).on(entity).includeLinks(ui.getBaseUriBuilder(), true, true).transform()); } return result; diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java index f841f33919..a00cb6e355 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java @@ -23,22 +23,17 @@ import java.net.URI; import java.util.Map; -import javax.annotation.Nullable; import javax.ws.rs.core.UriBuilder; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.objs.EntityAdjunct; -import org.apache.brooklyn.api.objs.SpecParameter; import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.sensor.Feed; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.policy.Policies; import org.apache.brooklyn.rest.api.AdjunctApi; -import org.apache.brooklyn.rest.api.ApplicationApi; -import org.apache.brooklyn.rest.api.EntityApi; 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.util.BrooklynRestResourceUtils; import org.apache.brooklyn.util.collections.MutableMap; @@ -62,7 +57,7 @@ private static T embellish(T adjunctSummary, Entity e public static AdjunctDetail adjunctDetail(BrooklynRestResourceUtils utils, Entity entity, EntityAdjunct adjunct, UriBuilder ub) { AdjunctDetail result = embellish(new AdjunctDetail(adjunct), entity, adjunct, ub); for (ConfigKey key: adjunct.config().findKeysDeclared(Predicates.alwaysTrue())) { - result.parameter(configSummary(utils, ub, entity, adjunct, key)); + result.parameter(ConfigTransformer.of(key).on(entity, adjunct).includeLinks(ub, false, true).transform()); } result.config(EntityTransformer.getConfigValues(utils, adjunct)); return result; @@ -74,8 +69,10 @@ protected static Map buildLinks(Entity entity, EntityAdjunct adjunc links.put("self", serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); if (detail) { - links.put("application", serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId())); - links.put("entity", serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId())); + links.put("application", EntityTransformer.applicationUri(entity.getApplication(), ub) ); + links.put("entity", EntityTransformer.entityUri(entity, ub) ); + links.put("adjunct", adjunctUri(entity, adjunct, ub) ); + links.put("config", serviceUriBuilder(ub, AdjunctApi.class, "listConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); links.put("status", serviceUriBuilder(ub, AdjunctApi.class, "getStatus").build(entity.getApplicationId(), entity.getId(), adjunct.getId())); if (adjunct instanceof Policy || adjunct instanceof Feed) { @@ -92,25 +89,8 @@ public static Status inferStatus(EntityAdjunct adjunct) { return ApplicationTransformer.statusFromLifecycle( Policies.inferAdjunctStatus(adjunct) ); } - public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, @Nullable Entity entity, @Nullable EntityAdjunct adjunct, SpecParameter input) { - Double priority = input.isPinned() ? Double.valueOf(1d) : null; - return configSummary(utils, ub, entity, adjunct, input.getConfigKey(), input.getLabel(), priority, input.isPinned()); + public static URI adjunctUri(Entity entity, EntityAdjunct adjunct, UriBuilder ub) { + return serviceUriBuilder(ub, AdjunctApi.class, "get").build(entity.getApplicationId(), entity.getId(), adjunct.getId()); } - public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, EntityAdjunct adjunct, ConfigKey config) { - // TODO get catalog info from other sources? - // see EntityTransformer.configSummary - return configSummary(utils, ub, entity, adjunct, config, null, null, null); - } - public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, @Nullable Entity entity, @Nullable EntityAdjunct adjunct, ConfigKey config, String label, Double priority, Boolean pinned) { - URI configUri = entity==null ? null : serviceUriBuilder(ub, AdjunctApi.class, "getConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId(), config.getName()); - Map links = MutableMap.builder() - .putIfNotNull("self", configUri) - // no point in including app/entity on every summary shown in a list - // (this is only ever used in a list, as self points at the value) - .build(); - - // TODO get actions, see EntityTransformer.configSummary - return new ConfigSummary(config, label, priority, pinned, links); - } } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java index aa30dd5112..6eeaeb82cd 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java @@ -71,6 +71,8 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; +/** @deprecated since 0.13.0 use RegisteredType methods */ +@Deprecated public class CatalogTransformer { private static final org.slf4j.Logger log = LoggerFactory.getLogger(CatalogTransformer.class); @@ -87,9 +89,9 @@ public static CatalogEntitySummary catalogEntitySummary(Brook EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType()); EntityType type = typeMap.getSnapshot(); - AtomicInteger paramPriorityCnt = new AtomicInteger(); + AtomicInteger priority = new AtomicInteger(); for (SpecParameter input: spec.getParameters()) - config.add(EntityTransformer.entityConfigSummary(input, paramPriorityCnt)); + config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyEntityConfig()); for (Sensor x: type.getSensors()) sensors.add(SensorTransformer.sensorSummaryForCatalog(x)); for (Effector x: type.getEffectors()) @@ -149,8 +151,9 @@ public static CatalogPolicySummary catalogPolicySummary(BrooklynRestResourceUtil PolicySpec spec = null; try{ spec = b.getTypeRegistry().createSpec(item, null, PolicySpec.class); - for (final SpecParameter input : spec.getParameters()){ - config.add(EntityTransformer.policyConfigSummary(input)); + AtomicInteger priority = new AtomicInteger(); + for (SpecParameter input: spec.getParameters()) { + config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyPolicyConfig()); } }catch (Exception e) { Exceptions.propagateIfFatal(e); @@ -169,8 +172,9 @@ public static CatalogEnricherSummary catalogEnricherSummary(BrooklynRestResource EnricherSpec spec = null; try{ spec = b.getTypeRegistry().createSpec(item, null, EnricherSpec.class); - for (final SpecParameter input : spec.getParameters()){ - config.add(EntityTransformer.enricherConfigSummary(input)); + AtomicInteger priority = new AtomicInteger(); + for (SpecParameter input: spec.getParameters()) { + config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyEnricherConfig()); } }catch (Exception e) { Exceptions.propagateIfFatal(e); @@ -257,9 +261,9 @@ public static CatalogEntitySummary catalogEntitySummary(Brook EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType()); EntityType type = typeMap.getSnapshot(); - AtomicInteger paramPriorityCnt = new AtomicInteger(); + AtomicInteger priority = new AtomicInteger(); for (SpecParameter input: spec.getParameters()) - config.add(EntityTransformer.entityConfigSummary(input, paramPriorityCnt)); + config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyEntityConfig()); for (Sensor x: type.getSensors()) sensors.add(SensorTransformer.sensorSummaryForCatalog(x)); for (Effector x: type.getEffectors()) @@ -315,8 +319,9 @@ public static CatalogPolicySummary catalogPolicySummary(BrooklynRestResourceUtil final Set config = Sets.newLinkedHashSet(); try{ final PolicySpec spec = (PolicySpec) b.getCatalog().peekSpec(item); - for (final SpecParameter input : spec.getParameters()){ - config.add(EntityTransformer.policyConfigSummary(input)); + AtomicInteger priority = new AtomicInteger(); + for (SpecParameter input: spec.getParameters()) { + config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyPolicyConfig()); } }catch (Exception e) { Exceptions.propagateIfFatal(e); @@ -333,8 +338,9 @@ public static CatalogEnricherSummary catalogEnricherSummary(BrooklynRestResource final Set config = Sets.newLinkedHashSet(); try{ final EnricherSpec spec = (EnricherSpec) b.getCatalog().peekSpec(item); - for (final SpecParameter input : spec.getParameters()){ - config.add(EntityTransformer.enricherConfigSummary(input)); + AtomicInteger priority = new AtomicInteger(); + for (SpecParameter input: spec.getParameters()) { + config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transformLegacyEnricherConfig()); } }catch (Exception e) { Exceptions.propagateIfFatal(e); diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java new file mode 100644 index 0000000000..22d429972e --- /dev/null +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java @@ -0,0 +1,173 @@ +/* + * 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.transform; + +import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder; + +import java.lang.reflect.Field; +import java.net.URI; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.ws.rs.core.UriBuilder; + +import org.apache.brooklyn.api.catalog.CatalogConfig; +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.api.objs.EntityAdjunct; +import org.apache.brooklyn.api.objs.SpecParameter; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.render.RendererHints; +import org.apache.brooklyn.rest.api.AdjunctApi; +import org.apache.brooklyn.rest.api.EntityConfigApi; +import org.apache.brooklyn.rest.domain.ConfigSummary; +import org.apache.brooklyn.util.collections.MutableMap; + +import com.google.common.collect.Iterables; + +public class ConfigTransformer { + + private final ConfigKey key; + + UriBuilder ub; + boolean includeContextLinks, includeActionLinks; + Entity entity; + EntityAdjunct adjunct; + + String label; + Double priority; + Boolean pinned; + + public static ConfigTransformer of(ConfigKey key) { + return new ConfigTransformer(key); + } + + public static ConfigTransformer of(SpecParameter param) { + ConfigTransformer result = of(param.getConfigKey()); + result.label = param.getLabel(); + result.pinned = param.isPinned(); + return result; + } + + private ConfigTransformer(ConfigKey key) { + this.key = key; + } + + public ConfigTransformer on(Entity entity) { + this.entity = entity; + return this; + } + + public ConfigTransformer on(Entity entity, EntityAdjunct adjunct) { + this.entity = entity; + this.adjunct = adjunct; + return this; + } + + public ConfigTransformer includeLinks(UriBuilder ub, boolean includeContextLinks, boolean includeActionLinks) { + this.ub = ub; + this.includeContextLinks = includeContextLinks; + this.includeActionLinks = includeActionLinks; + return this; + } + + public ConfigTransformer uiMetadata(String label, Double priority, Boolean pinned) { + this.label = label; + this.priority = priority; + this.pinned = pinned; + return this; + } + + public ConfigTransformer uiMetadata(String label, Boolean pinned) { + return uiMetadata(label, Boolean.TRUE.equals(pinned) ? 1.0d : 0, pinned); + } + + public ConfigTransformer uiIncrementAndSetPriorityIfPinned(AtomicInteger lastPriority) { + if (Boolean.TRUE.equals(pinned)) { + this.priority = (double) lastPriority.incrementAndGet(); + } + return this; + } + + public ConfigTransformer uiMetadata(Field keyField) { + if (keyField==null) return this; + return uiMetadata(keyField.getDeclaredAnnotation(CatalogConfig.class)); + } + + public ConfigTransformer uiMetadata(CatalogConfig annotation) { + if (annotation==null) return this; + return uiMetadata(annotation.label(), annotation.priority(), annotation.pinned()); + } + + public ConfigSummary transform() { + MutableMap.Builder lb = new MutableMap.Builder(); + + if (ub!=null && entity!=null) { + URI self; + if (adjunct!=null) { + self = serviceUriBuilder(ub, AdjunctApi.class, "getConfig").build(entity.getApplicationId(), entity.getId(), adjunct.getId(), key.getName()); + } else { + self = serviceUriBuilder(ub, EntityConfigApi.class, "get").build(entity.getApplicationId(), entity.getId(), key.getName()); + } + lb.put("self", self); + + if (includeContextLinks) { + // TODO wasteful including these + lb.put("application", EntityTransformer.applicationUri(entity.getApplication(), ub) ); + lb.put("entity", EntityTransformer.entityUri(entity, ub) ); + if (adjunct!=null) { + lb.put("adjunct", AdjunctTransformer.adjunctUri(entity, adjunct, ub) ); + } + } + if (includeActionLinks) { + // TODO is this json or a display value? + lb.put("action:json", self); + + Iterable hints = Iterables.filter(RendererHints.getHintsFor(key), RendererHints.NamedAction.class); + BrooklynObject context = adjunct!=null ? adjunct : entity; + for (RendererHints.NamedAction na : hints) { + SensorTransformer.addNamedAction(lb, na, context.getConfig(key), key, context); + } + } + + } + + // TODO if ui metadata not set try to infer or get more info from caller ? + + return new ConfigSummary(key, label, priority, pinned, lb.build()); + } + + @Deprecated + public org.apache.brooklyn.rest.domain.EntityConfigSummary transformLegacyEntityConfig() { + ConfigSummary v2 = transform(); + return new org.apache.brooklyn.rest.domain.EntityConfigSummary(key, v2.getLabel(), v2.getPriority(), v2.isPinned(), v2.getLinks()); + } + + @Deprecated + public org.apache.brooklyn.rest.domain.EnricherConfigSummary transformLegacyEnricherConfig() { + ConfigSummary v2 = transform(); + return new org.apache.brooklyn.rest.domain.EnricherConfigSummary(key, v2.getLabel(), v2.getPriority(), v2.getLinks()); + } + + @Deprecated + public org.apache.brooklyn.rest.domain.PolicyConfigSummary transformLegacyPolicyConfig() { + ConfigSummary v2 = transform(); + return new org.apache.brooklyn.rest.domain.PolicyConfigSummary(key, v2.getLabel(), v2.getPriority(), v2.getLinks()); + } + +} diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java index 9359bb5c67..1537f07164 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java @@ -36,25 +36,21 @@ import org.apache.brooklyn.api.objs.SpecParameter; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; -import org.apache.brooklyn.core.config.render.RendererHints; import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.apache.brooklyn.core.typereg.RegisteredTypes; import org.apache.brooklyn.rest.api.ApplicationApi; import org.apache.brooklyn.rest.api.CatalogApi; import org.apache.brooklyn.rest.api.EntityApi; -import org.apache.brooklyn.rest.api.EntityConfigApi; import org.apache.brooklyn.rest.domain.ConfigSummary; import org.apache.brooklyn.rest.domain.EnricherConfigSummary; import org.apache.brooklyn.rest.domain.EntityConfigSummary; import org.apache.brooklyn.rest.domain.EntitySummary; import org.apache.brooklyn.rest.domain.PolicyConfigSummary; import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils; -import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.config.ConfigBag; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -126,89 +122,39 @@ public EntitySummary apply(Entity entity) { })); } - /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, String, Double, Boolean) */ + public static URI applicationUri(Application entity, UriBuilder ub) { + return serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId()); + } + + public static URI entityUri(Entity entity, UriBuilder ub) { + return serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId()); + } + + /** @deprecated since 0.13.0 use {@link ConfigTransformer} */ @Deprecated public static EntityConfigSummary entityConfigSummary(ConfigKey config, String label, Double priority, Boolean pinned, Map links) { return new EntityConfigSummary(config, label, priority, pinned, links); } - /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, ConfigKey, String, Double, Boolean)} */ + /** @deprecated since 0.13.0 use {@link ConfigTransformer} */ @Deprecated public static PolicyConfigSummary policyConfigSummary(ConfigKey config, String label, Double priority, Map links) { return new PolicyConfigSummary(config, label, priority, links); } - /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, ConfigKey, String, Double, Boolean)} */ + /** @deprecated since 0.13.0 use {@link ConfigTransformer} */ @Deprecated public static EnricherConfigSummary enricherConfigSummary(ConfigKey config, String label, Double priority, Map links) { return new EnricherConfigSummary(config, label, priority, links); } - /** generates a representation for a given config key, - * with label inferred from annoation in the entity class, - * and links pointing to the entity and the application - * @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey)} */ + /** @deprecated since 0.13.0 use {@link ConfigTransformer} */ @Deprecated - public static EntityConfigSummary entityConfigSummary(Entity entity, ConfigKey config, UriBuilder ub) { - return (EntityConfigSummary) configSummary(null, ub, entity, config); + public static ConfigSummary entityConfigSummary(Entity entity, ConfigKey config, UriBuilder ub) { + return ConfigTransformer.of(config).on(entity).includeLinks(ub, true, true).transform(); } - - public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey config) { - // TODO get catalog/display info - - /* - * following code nearly there to get the @CatalogConfig annotation - * in the class and use that to populate a label - */ - -// EntityDynamicType typeMap = -// ((AbstractEntity)entity).getMutableEntityType(); -// // above line works if we can cast; line below won't work, but there should some way -// // to get back the handle to the spec from an entity local, which then *would* work -// EntityTypes.getDefinedEntityType(entity.getClass()); -// String label = typeMap.getConfigKeyField(config.getName()); - return configSummary(null, ub, entity, config, null); - } - public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey config, CatalogConfig annotation) { - String label = annotation==null ? null : annotation.label(); - Double priority = annotation==null ? null : annotation.priority(); - boolean pinned = annotation!=null && annotation.pinned(); - return configSummary(utils, ub, entity, config, label, priority, pinned); - } - public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, ConfigKey config, String label, Double priority, Boolean pinned) { - // entity can be null if coming from catalog - URI applicationUri = entity==null ? null : serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId()); - URI entityUri = entity==null ? null : serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId()); - URI selfUri = entity==null ? null : serviceUriBuilder(ub, EntityConfigApi.class, "get").build(entity.getApplicationId(), entity.getId(), config.getName()); - - MutableMap.Builder lb = MutableMap.builder() - .putIfNotNull("self", selfUri) - // TODO wasteful including these on every item as it is just a list, remove - .putIfNotNull("application", applicationUri) - .putIfNotNull("entity", entityUri) - // TODO is this json or a display value? - .putIfNotNull("action:json", selfUri); - - Iterable hints = Iterables.filter(RendererHints.getHintsFor(config), RendererHints.NamedAction.class); - for (RendererHints.NamedAction na : hints) { - if (entity!=null) { - SensorTransformer.addNamedAction(lb, na, entity.getConfig(config), config, entity); - } - } - - return new EntityConfigSummary(config, label, priority, pinned, lb.build()); - } - - public static URI applicationUri(Application entity, UriBuilder ub) { - return serviceUriBuilder(ub, ApplicationApi.class, "get").build(entity.getApplicationId()); - } - - public static URI entityUri(Entity entity, UriBuilder ub) { - return serviceUriBuilder(ub, EntityApi.class, "get").build(entity.getApplicationId(), entity.getId()); - } - - /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, CatalogConfig) */ + /** @deprecated since 0.13.0 use {@link ConfigTransformer} */ @Deprecated public static EntityConfigSummary entityConfigSummary(ConfigKey config, Field configKeyField) { CatalogConfig catalogConfig = configKeyField!=null ? configKeyField.getAnnotation(CatalogConfig.class) : null; @@ -218,7 +164,7 @@ public static EntityConfigSummary entityConfigSummary(ConfigKey config, Field return entityConfigSummary(config, label, priority, pinned, null); } - /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, ConfigKey, AtomicInteger) */ + /** @deprecated since 0.13.0 use {@link ConfigTransformer} */ @Deprecated public static EntityConfigSummary entityConfigSummary(SpecParameter input, AtomicInteger paramPriorityCnt) { // Increment the priority because the config container is a set. Server-side we are using an ordered set @@ -228,38 +174,14 @@ public static EntityConfigSummary entityConfigSummary(SpecParameter input, At return entityConfigSummary(input.getConfigKey(), input.getLabel(), priority, input.isPinned(), null); } - /** @deprecated since 0.13.0 use {@link #configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, SpecParameter) */ - @Deprecated - public static ConfigSummary configSummary(SpecParameter input) { - // TODO could increment priority, or take from annotation, or introduce new field - Double priority = input.isPinned() ? Double.valueOf(1d) : null; - return new EntityConfigSummary(input.getConfigKey(), input.getLabel(), priority, input.isPinned(), null); - } - - - public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, SpecParameter input, AtomicInteger paramPriorityCnt) { - // Increment the priority because the config container is a set. Server-side we are using an ordered set - // which results in correctly ordered items on the wire (as a list). Clients which use the java bindings - // though will push the items in an unordered set - so give them means to recover the correct order. - Double priority = input.isPinned() ? Double.valueOf(paramPriorityCnt.incrementAndGet()) : null; - return configSummary(utils, ub, entity, input.getConfigKey(), input.getLabel(), priority, input.isPinned()); - } - - public static ConfigSummary configSummary(BrooklynRestResourceUtils utils, UriBuilder ub, Entity entity, SpecParameter input) { - // TODO allow taking priority from a setting somewhere? - // (this just sets priority 1 if no value specified) - return configSummary(utils, ub, entity, input, new AtomicInteger(0)); - } - - - /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, SpecParameter)} */ + /** @deprecated since 0.13.0 use {@link ConfigTransformer} */ @Deprecated public static PolicyConfigSummary policyConfigSummary(SpecParameter input) { Double priority = input.isPinned() ? Double.valueOf(1d) : null; return policyConfigSummary(input.getConfigKey(), input.getLabel(), priority, null); } - /** @deprecated since 0.13.0 use {@link AdjunctTransformer#configSummary(BrooklynRestResourceUtils, UriBuilder, Entity, org.apache.brooklyn.api.objs.EntityAdjunct, SpecParameter)} */ + /** @deprecated since 0.13.0 use {@link ConfigTransformer} */ @Deprecated public static EnricherConfigSummary enricherConfigSummary(SpecParameter input) { Double priority = input.isPinned() ? Double.valueOf(1d) : null; diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java index 19820d0f97..e4971ff80d 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/SensorTransformer.java @@ -18,25 +18,28 @@ */ package org.apache.brooklyn.rest.transform; +import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder; + import java.net.URI; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import javax.ws.rs.core.UriBuilder; + import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.api.sensor.Sensor; import org.apache.brooklyn.core.config.render.RendererHints; +import org.apache.brooklyn.rest.api.ApplicationApi; +import org.apache.brooklyn.rest.api.EntityApi; +import org.apache.brooklyn.rest.api.SensorApi; import org.apache.brooklyn.rest.domain.SensorSummary; import org.apache.brooklyn.util.collections.MutableMap; 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.collect.Iterables; -import javax.ws.rs.core.UriBuilder; -import org.apache.brooklyn.rest.api.ApplicationApi; -import org.apache.brooklyn.rest.api.EntityApi; -import org.apache.brooklyn.rest.api.SensorApi; -import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder; public class SensorTransformer { @@ -71,7 +74,7 @@ private static void addNamedAction(MutableMap.Builder lb, Rende } @SuppressWarnings("unchecked") - static void addNamedAction(MutableMap.Builder lb, RendererHints.NamedAction na, T value, Object context, Entity contextEntity) { + static void addNamedAction(MutableMap.Builder lb, RendererHints.NamedAction na, T value, Object contextKeyOrSensor, BrooklynObject contextObject) { if (na instanceof RendererHints.NamedActionWithUrl) { try { String v = ((RendererHints.NamedActionWithUrl) na).getUrlFromValue(value); @@ -81,7 +84,7 @@ static void addNamedAction(MutableMap.Builder lb, RendererHints } } catch (Exception e) { Exceptions.propagateIfFatal(e); - log.warn("Unable to make action "+na+" from "+context+" on "+contextEntity+": "+e, e); + log.warn("Unable to make action "+na+" from "+contextKeyOrSensor+" on "+contextObject+": "+e, e); } } } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java index d081efdf72..736ee83911 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java @@ -100,7 +100,7 @@ private static T embellish(T result, RegisteredType item AbstractBrooklynObjectSpec spec = b.getTypeRegistry().createSpec(item, null, null); AtomicInteger priority = new AtomicInteger(0); for (final SpecParameter input : spec.getParameters()){ - config.add(EntityTransformer.configSummary(null, null, null, input, priority)); + config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transform()); } result.setExtraField("config", config); @@ -127,9 +127,9 @@ protected static void embellishEntity(T result, Register EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType()); EntityType type = typeMap.getSnapshot(); - AtomicInteger paramPriorityCnt = new AtomicInteger(); + AtomicInteger priority = new AtomicInteger(); for (SpecParameter input: spec.getParameters()) - config.add(EntityTransformer.configSummary(null, null, null, input, paramPriorityCnt)); + config.add(ConfigTransformer.of(input).uiIncrementAndSetPriorityIfPinned(priority).transform()); for (Sensor x: type.getSensors()) sensors.add(SensorTransformer.sensorSummaryForCatalog(x)); for (Effector x: type.getEffectors()) diff --git a/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java b/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java index 61a7a2a5fd..1a4ad31208 100644 --- a/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java +++ b/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java @@ -18,7 +18,6 @@ */ package org.apache.brooklyn.cli.lister; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -29,7 +28,6 @@ import org.apache.brooklyn.api.catalog.BrooklynCatalog; import org.apache.brooklyn.api.catalog.Catalog; -import org.apache.brooklyn.api.catalog.CatalogConfig; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.effector.Effector; import org.apache.brooklyn.api.entity.EntityType; @@ -47,8 +45,8 @@ import org.apache.brooklyn.rest.domain.EffectorSummary; import org.apache.brooklyn.rest.domain.SensorSummary; import org.apache.brooklyn.rest.domain.SummaryComparators; +import org.apache.brooklyn.rest.transform.ConfigTransformer; import org.apache.brooklyn.rest.transform.EffectorTransformer; -import org.apache.brooklyn.rest.transform.EntityTransformer; import org.apache.brooklyn.rest.transform.SensorTransformer; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException; @@ -138,9 +136,7 @@ public static Map toItemDescriptor(Class effectors = Sets.newTreeSet(SummaryComparators.nameComparator()); for (ConfigKey x: type.getConfigKeys()) { - Field field = dynamicType.getConfigKeyField(x.getName()); - CatalogConfig annotation = field==null ? null : field.getAnnotation(CatalogConfig.class); - config.add(EntityTransformer.configSummary(null, null, null, x, annotation)); + config.add(ConfigTransformer.of(x).uiMetadata(dynamicType.getConfigKeyField(x.getName())).transform()); } result.put("config", config); @@ -205,7 +201,7 @@ public static Map toItemDescriptor(BrooklynCatalog catalog, Cata if (!headingsOnly) { AtomicInteger priority = new AtomicInteger(0); for (SpecParameter param: spec.getParameters()) { - config.add(EntityTransformer.configSummary(null, null, null, param, priority)); + config.add(ConfigTransformer.of(param).uiIncrementAndSetPriorityIfPinned(priority).transform()); } itemDescriptor.put("config", config); } From e0160538fee0dd8f0308ed4d6787d54bf813d7dc Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Tue, 3 Oct 2017 09:31:52 +0100 Subject: [PATCH 3/6] add deprecation notes to description for REST endpoints so they appear in swagger --- .../apache/brooklyn/rest/api/CatalogApi.java | 34 ++++++++++--------- .../apache/brooklyn/rest/api/PolicyApi.java | 14 ++++---- .../brooklyn/rest/api/PolicyConfigApi.java | 8 ++--- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java index 6499f14818..2c115df5b2 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java @@ -58,7 +58,7 @@ public interface CatalogApi { @Consumes("application/json-deprecated") // prevent this from taking things @POST @ApiOperation( - value = "Add a catalog items (e.g. new type of entity, policy or location) by uploading YAML descriptor.", + value = "Add a catalog items (e.g. new type of entity, policy or location) by uploading YAML descriptor (deprecated, use POST of yaml or ZIP/JAR instead)", notes = "Return value is map of ID to CatalogItemSummary.", response = String.class, hidden = true @@ -159,7 +159,7 @@ public Response createFromUpload( @DELETE @Path("/applications/{symbolicName}/{version}") @ApiOperation( - value = "Deletes a specific version of an application's definition from the catalog", + value = "Deletes a specific version of an application's definition from the catalog (deprecated, use /catalog/bundles endpoint instead)", notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" + "pick up the latest version for the given 'symbolicName'" ) @@ -179,7 +179,7 @@ public void deleteApplication( @DELETE @Path("/entities/{symbolicName}/{version}") @ApiOperation( - value = "Deletes a specific version of an entity's definition from the catalog", + value = "Deletes a specific version of an entity's definition from the catalog (deprecated, use /catalog/bundles endpoint instead, as we add/delete bundles now)", notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" + "pick up the latest version for the given 'symbolicName'" ) @@ -199,7 +199,7 @@ public void deleteEntity( @DELETE @Path("/policies/{policyId}/{version}") @ApiOperation( - value = "Deletes a specific version of an policy's definition from the catalog", + value = "Deletes a specific version of an policy's definition from the catalog (deprecated, use /catalog/bundles endpoint instead, as we add/delete bundles now)", notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" + "pick up the latest version for the given 'policyId'") @ApiResponses(value = { @@ -218,7 +218,7 @@ public void deletePolicy( @DELETE @Path("/locations/{locationId}/{version}") @ApiOperation( - value = "Deletes a specific version of an location's definition from the catalog", + value = "Deletes a specific version of an location's definition from the catalog (deprecated, use /catalog/bundles endpoint instead, as we add/delete bundles now)", notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" + "pick up the latest version for the given 'locationId'" ) @@ -237,7 +237,7 @@ public void deleteLocation( @Deprecated @GET @Path("/entities") - @ApiOperation(value = "List available entity types optionally matching a query", + @ApiOperation(value = "List available entity types optionally matching a query (deprecated, use /catalog/types endpoint instead, with supertype=entity)", response = CatalogItemSummary.class, responseContainer = "List") public List listEntities( @@ -254,7 +254,7 @@ public List listEntities( @Deprecated @GET @Path("/applications") - @ApiOperation(value = "Fetch a list of templates (for applications) optionally matching a query", + @ApiOperation(value = "Fetch a list of templates (for applications) optionally matching a query (deprecated, use /catalog/types endpoint instead, with supertype=application; note some semantics of templates are changing as definition becomes more precise)", response = CatalogItemSummary.class, responseContainer = "List") public List listApplications( @@ -271,7 +271,7 @@ public List listApplications( @GET @Path("/entities/{symbolicName}/{version}") @ApiOperation( - value = "Fetch a specific version of an entity's definition from the catalog", + value = "Fetch a specific version of an entity's definition from the catalog (deprecated, use /catalog/types endpoint instead)", notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" + "pick up the latest version for the given 'symbolicName'", response = CatalogEntitySummary.class, @@ -292,7 +292,7 @@ public CatalogEntitySummary getEntity( @GET @Path("/applications/{symbolicName}/{version}") @ApiOperation( - value = "Fetch a specific version of an application's definition from the catalog", + value = "Fetch a specific version of an application's definition from the catalog (deprecated, use /catalog/types endpoint instead)", notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" + "pick up the latest version for the given 'symbolicName'", response = CatalogEntitySummary.class, @@ -312,7 +312,7 @@ public CatalogEntitySummary getApplication( @Deprecated @GET @Path("/policies") - @ApiOperation(value = "List available policies optionally matching a query", + @ApiOperation(value = "List available policies optionally matching a query (deprecated, use /catalog/types endpoint instead)", response = CatalogPolicySummary.class, responseContainer = "List") public List listPolicies( @@ -329,7 +329,7 @@ public List listPolicies( @GET @Path("/policies/{policyId}/{version}") @ApiOperation( - value = "Fetch a policy's definition from the catalog", + value = "Fetch a policy's definition from the catalog (deprecated, use /catalog/types endpoint instead)", notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" + "pick up the latest version for the given 'policyId'", response = CatalogItemSummary.class, @@ -348,7 +348,7 @@ public CatalogPolicySummary getPolicy( @Deprecated @GET @Path("/locations") - @ApiOperation(value = "List available locations optionally matching a query", + @ApiOperation(value = "List available locations optionally matching a query (deprecated, use /catalog/types endpoint instead)", response = CatalogLocationSummary.class, responseContainer = "List") public List listLocations( @@ -365,7 +365,7 @@ public List listLocations( @GET @Path("/locations/{locationId}/{version}") @ApiOperation( - value = "Fetch a location's definition from the catalog", + value = "Fetch a location's definition from the catalog (deprecated, use /catalog/types endpoint instead)", notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" + "pick up the latest version for the given 'locationId'", response = CatalogItemSummary.class, @@ -406,6 +406,7 @@ public Response getIcon( @ApiResponses(value = { @ApiResponse(code = 404, message = "Undefined catalog item"), }) + @ApiOperation(value = "Deprecate an item (deprecated, use /catalog/types endpoint instead, but disabled/deprecating is not supported for individual types)") @Path("/entities/{itemId}/deprecated") public void setDeprecated( @ApiParam(name = "itemId", value = "The ID of the catalog item to be deprecated", required = true) @@ -419,6 +420,7 @@ public void setDeprecated( @Deprecated @POST @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN}) + @ApiOperation(value = "Disable an item (deprecated, use /catalog/types endpoint instead, but disabled/deprecating is not supported for individual types)") @ApiResponses(value = { @ApiResponse(code = 404, message = "Undefined catalog item"), }) @@ -434,7 +436,7 @@ public void setDisabled( @Deprecated @GET @Path("/enrichers") - @ApiOperation(value = "List available enrichers types optionally matching a query", + @ApiOperation(value = "List available enrichers types optionally matching a query (deprecated, use /catalog/types endpoint instead)", response = CatalogItemSummary.class, responseContainer = "List") public List listEnrichers( @@ -450,7 +452,7 @@ public List listEnrichers( @Deprecated @GET @Path("/enrichers/{enricherId}/{version}") - @ApiOperation(value = "Fetch an enricher's definition from the catalog", + @ApiOperation(value = "Fetch an enricher's definition from the catalog (deprecated, use /catalog/types endpoint instead)", response = CatalogItemSummary.class, responseContainer = "List") @ApiResponses(value = { @@ -467,7 +469,7 @@ public CatalogEnricherSummary getEnricher( @Deprecated @DELETE @Path("/enrichers/{enricherId}/{version}") - @ApiOperation(value = "Deletes a specific version of an enricher's definition from the catalog") + @ApiOperation(value = "Deletes a specific version of an enricher's definition from the catalog (deprecated, use /catalog/types endpoint instead)") @ApiResponses(value = { @ApiResponse(code = 404, message = "Enricher not found") }) diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java index 329c0e1cbb..95f41db681 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java @@ -41,7 +41,7 @@ public interface PolicyApi { @GET - @ApiOperation(value = "Fetch the policies attached to a specific application entity", + @ApiOperation(value = "Fetch the policies attached to a specific application entity (deprecated, use adjuncts/ endpoint instead)", response = org.apache.brooklyn.rest.domain.PolicySummary.class, responseContainer = "List") @ApiResponses(value = { @@ -57,7 +57,7 @@ public List list( // (and in sensors class) @GET @Path("/current-state") - @ApiOperation(value = "Fetch policy states in batch", notes="Returns a map of policy ID to whether it is active") + @ApiOperation(value = "Fetch policy states in batch", notes="Returns a map of policy ID to whether it is active (deprecated, use adjuncts/ endpoint instead)") // FIXME method name -- this is nothing to do with config! public Map batchConfigRead( @ApiParam(value = "Application ID or name", required = true) @@ -66,7 +66,7 @@ public Map batchConfigRead( @PathParam("entity") String entityToken) ; @POST - @ApiOperation(value = "Add a policy", notes = "Returns a summary of the new policy") + @ApiOperation(value = "Add a policy", notes = "Returns a summary of the new policy (deprecated, use adjuncts/ endpoint instead)") @ApiResponses(value = { @ApiResponse(code = 404, message = "Could not find application or entity"), @ApiResponse(code = 400, message = "Type is not a class implementing Policy") @@ -88,7 +88,7 @@ public PolicySummary addPolicy( @GET @Path("/{policy}") - @ApiOperation(value = "Gets status of a policy (RUNNING / SUSPENDED)") + @ApiOperation(value = "Gets status of a policy (RUNNING / SUSPENDED) (deprecated, use adjuncts/ endpoint instead)") @ApiResponses(value = { @ApiResponse(code = 404, message = "Could not find application, entity or policy") }) @@ -104,7 +104,7 @@ public Status getStatus( @POST @Path("/{policy}/start") - @ApiOperation(value = "Start or resume a policy") + @ApiOperation(value = "Start or resume a policy (deprecated, use adjuncts/ endpoint instead)") @ApiResponses(value = { @ApiResponse(code = 404, message = "Could not find application, entity or policy") }) @@ -120,7 +120,7 @@ public Response start( @POST @Path("/{policy}/stop") - @ApiOperation(value = "Suspends a policy") + @ApiOperation(value = "Suspends a policy (deprecated, use adjuncts/ endpoint instead)") @ApiResponses(value = { @ApiResponse(code = 404, message = "Could not find application, entity or policy") }) @@ -137,7 +137,7 @@ public Response stop( // TODO: Should be DELETE /policy, not POST /policy/destroy @POST @Path("/{policy}/destroy") - @ApiOperation(value = "Destroy a policy", notes="Removes a policy from being associated with the entity and destroys it (stopping first if running)") + @ApiOperation(value = "Destroy a policy (deprecated, use adjuncts/ endpoint instead)", notes="Removes a policy from being associated with the entity and destroys it (stopping first if running)") @ApiResponses(value = { @ApiResponse(code = 404, message = "Could not find application, entity or policy") }) diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java index 06a4b86c33..8d061dd405 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java @@ -47,7 +47,7 @@ public interface PolicyConfigApi { @GET - @ApiOperation(value = "Fetch the config keys for a specific policy", + @ApiOperation(value = "Fetch the config keys for a specific policy (deprecated, use adjuncts/ endpoint instead)", response = org.apache.brooklyn.rest.domain.ConfigSummary.class, responseContainer = "List") @ApiResponses(value = { @@ -65,7 +65,7 @@ public List list( // (and in sensors class) @GET @Path("/current-state") - @ApiOperation(value = "Fetch config key values in batch", notes="Returns a map of config name to value") + @ApiOperation(value = "Fetch config key values in batch (deprecated, use adjuncts/ endpoint instead)", notes="Returns a map of config name to value") public Map batchConfigRead( @ApiParam(value = "Application ID or name", required = true) @PathParam("application") String application, @@ -76,7 +76,7 @@ public Map batchConfigRead( @GET @Path("/{config}") - @ApiOperation(value = "Fetch config value", response = Object.class) + @ApiOperation(value = "Fetch config value (deprecated, use adjuncts/ endpoint instead)", response = Object.class) @ApiResponses(value = { @ApiResponse(code = 404, message = "Could not find application, entity, policy or config key") }) @@ -93,7 +93,7 @@ public String get( @POST @Path("/{config}") @Consumes(value = {"*/*"}) - @ApiOperation(value = "Sets the given config on this policy") + @ApiOperation(value = "Sets the given config on this policy (deprecated, use adjuncts/ endpoint instead)") @ApiResponses(value = { @ApiResponse(code = 404, message = "Could not find application, entity, policy or config key") }) From dd4f05e04efc1bbfa70d024f6ad4191017291e5f Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Tue, 3 Oct 2017 09:50:39 +0100 Subject: [PATCH 4/6] steps toward bringing FeedSupport in line with other AdjunctSupport classes deprecating more methods which need to change or should go will need to add FeedSpec in future to bring it fully in line --- .../apache/brooklyn/api/entity/Entity.java | 3 ++ .../brooklyn/core/entity/AbstractEntity.java | 29 +++++++++++++++---- .../brooklyn/core/entity/EntityInternal.java | 14 ++++----- .../brooklyn/core/feed/AbstractFeed.java | 2 +- .../core/entity/EntityConcurrencyTest.java | 2 +- .../launcher/CleanOrphanedAdjunctsTest.java | 6 ++-- 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java index da9169ec78..bbee0ade6c 100644 --- a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java +++ b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java @@ -286,7 +286,10 @@ public interface Entity extends BrooklynObject { /** * Adds the given feed to this entity. Also calls feed.setEntity if available. + * + * @deprecated since 0.13.0; see {@link FeedSupport#add(Feed)} */ + @Deprecated T addFeed(T feed); SensorSupport sensors(); diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java index d221c162cf..bd7df0698b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java @@ -1871,7 +1871,8 @@ public boolean removeAllEnrichers() { */ @Override public T addFeed(T feed) { - return feeds().add(feed); + feeds().add(feed); + return feed; } @Override @@ -1896,8 +1897,9 @@ public Collection getFeeds() { public T add(T feed) { return addFeed(feed); } - - @Override + + /** @deprecated since 0.13.0 use {@link #add(Feed)} */ + @Deprecated public T addFeed(T feed) { Feed old = findApparentlyEqualAndWarnIfNotSameUniqueTag(feedsInternal, feed); if (old != null) { @@ -1921,7 +1923,7 @@ public T addFeed(T feed) { getManagementContext().getRebindManager().getChangeListener().onManaged(feed); getManagementSupport().getEntityChangeListener().onFeedAdded(feed); // TODO Could add equivalent of AbstractEntity.POLICY_ADDED for feeds; no use-case for that yet - + return feed; } @@ -1930,7 +1932,8 @@ public boolean remove(Feed feed) { return removeFeed(feed); } - @Override + /** @deprecated since 0.13.0 use {@link #remove(Feed)} */ + @Deprecated public boolean removeFeed(Feed feed) { feed.stop(); boolean changed = feedsInternal.remove(feed); @@ -1960,6 +1963,22 @@ public boolean removeAllFeeds() { public Iterator iterator() { return getFeeds().iterator(); } + + // TODO add these back when we implement AdjunctSupport (after 0.13.0) +// @Override +// public int size() { +// return getFeeds().size(); +// } +// +// @Override +// public boolean isEmpty() { +// return getFeeds().isEmpty(); +// } +// +// @Override +// public List asList() { +// return ImmutableList.copyOf(getFeeds()); +// } } // -------- SENSORS -------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java index 7377f382d4..46d10aba79 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java @@ -189,29 +189,27 @@ public interface SensorSupportInternal extends Entity.SensorSupport { void remove(AttributeSensor attribute); } + // TODO extend AdjunctSupport, after 0.13.0 public interface FeedSupport extends Iterable { Collection getFeeds(); /** * Adds the given feed to this entity. The feed will automatically be re-added on brooklyn restart. + * + * @deprecated since 0.13.0 will change to return type 'void', for consistency with other {@link AdjunctSupport} */ - T add(T feed); - - /** @deprecated since 0.10.0; use {@link #add()} */ @Deprecated - T addFeed(T feed); +// @Override + T add(T feed); /** * Removes the given feed from this entity. * @return True if the feed existed at this entity; false otherwise */ +// @Override boolean remove(Feed feed); - /** @deprecated since 0.10.0; use {@link #remove()} */ - @Deprecated - boolean removeFeed(Feed feed); - /** * Removes all feeds from this entity. * Use with caution as some entities automatically register feeds; this will remove those feeds as well. diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java b/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java index 84165eae17..316d269597 100644 --- a/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java +++ b/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java @@ -62,7 +62,7 @@ public AbstractFeed() { public void setEntity(EntityLocal entity) { super.setEntity(entity); if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_FEED_REGISTRATION_PROPERTY)) { - ((EntityInternal)entity).feeds().addFeed(this); + ((EntityInternal)entity).feeds().add(this); } } diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java index f6062262aa..a4a77c082d 100644 --- a/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntityConcurrencyTest.java @@ -261,7 +261,7 @@ public void testConcurrentAddFeed() throws Exception { for (int i = 0; i < NUM_TASKS; i++) { ListenableFuture future = executor.submit(new Runnable() { @Override public void run() { - entity.feeds().addFeed(new MyFeed()); + entity.feeds().add(new MyFeed()); }}); futures.add(future); } diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java index f9e772adfd..b8f8fef13c 100644 --- a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java +++ b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedAdjunctsTest.java @@ -54,7 +54,8 @@ public void testDeletesOrphanedPolicies() throws Exception { @Test public void testDeletesOrphanedFeeds() throws Exception { EntityInternal entity = origApp.addChild(EntitySpec.create(TestEntity.class).impl(MyEntity.class)); - Feed feed = entity.feeds().add(new MyFeed()); + Feed feed = new MyFeed(); + entity.feeds().add(feed); MementoTweaker tweaker = new MementoTweaker(new Deletions().entities(entity.getId())); assertTransformDeletes(new Deletions().feeds(feed.getId()), tweaker); } @@ -63,7 +64,8 @@ public void testDeletesOrphanedFeeds() throws Exception { public void testKeepsReachableAdjuncts() throws Exception { MyPolicy policy = origApp.policies().add(PolicySpec.create(MyPolicy.class)); MyEnricher enricher = origApp.enrichers().add(EnricherSpec.create(MyEnricher.class)); - Feed feed = origApp.feeds().add(new MyFeed()); + Feed feed = new MyFeed(); + origApp.feeds().add(feed); // Double-check we have the state we expected for the assertions that it is unmodified! BrooklynMementoRawData origData = getRawData(); From 28dbb83e0d52a978b4756b7a1c379da309ee820a Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Tue, 3 Oct 2017 10:24:47 +0100 Subject: [PATCH 5/6] address PR comments, note deprecation now since 0.13.0, and remove/update other deprecated --- .../brooklyn/core/entity/EntityAdjuncts.java | 28 +++++- .../apache/brooklyn/core/policy/Policies.java | 86 ++----------------- .../apache/brooklyn/rest/api/AdjunctApi.java | 14 +-- .../apache/brooklyn/rest/api/PolicyApi.java | 2 +- .../brooklyn/rest/api/PolicyConfigApi.java | 2 +- .../brooklyn/rest/domain/AdjunctSummary.java | 2 - .../brooklyn/rest/domain/ApplicationSpec.java | 12 +-- .../rest/domain/CatalogEnricherSummary.java | 4 +- .../rest/domain/CatalogEntitySummary.java | 4 +- .../rest/domain/CatalogItemSummary.java | 4 +- .../rest/domain/CatalogLocationSummary.java | 4 +- .../rest/domain/CatalogPolicySummary.java | 4 +- .../brooklyn/rest/domain/EffectorSummary.java | 9 +- .../brooklyn/rest/domain/EntityDetail.java | 14 +-- .../brooklyn/rest/domain/EntitySummary.java | 11 +-- .../rest/domain/PolicyConfigSummary.java | 2 +- .../brooklyn/rest/domain/PolicySummary.java | 2 +- .../rest/domain/ScriptExecutionSummary.java | 11 +-- .../brooklyn/rest/domain/SensorSummary.java | 7 +- .../rest/resources/AdjunctResource.java | 48 +++++++---- .../rest/transform/AdjunctTransformer.java | 4 +- .../rest/transform/CatalogTransformer.java | 2 +- .../rest/transform/ConfigTransformer.java | 2 + .../rest/transform/PolicyTransformer.java | 2 +- .../rest/util/BrooklynRestResourceUtils.java | 13 +-- .../testing/BrooklynRestResourceTest.java | 2 +- 26 files changed, 139 insertions(+), 156 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java index fc1daf45e2..8c06384da3 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityAdjuncts.java @@ -23,13 +23,17 @@ import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.objs.EntityAdjunct; +import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.sensor.Enricher; +import org.apache.brooklyn.api.sensor.Feed; +import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers; import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ComputeServiceState; import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.guava.Maybe; +import com.google.common.annotations.Beta; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -66,5 +70,27 @@ public static boolean isSystemEnricher(Enricher enr) { if (SYSTEM_ENRICHER_UNIQUE_TAGS.contains(enr.getUniqueTag())) return true; return false; } - + + @Beta + public static Lifecycle inferAdjunctStatus(EntityAdjunct a) { + if (a.isRunning()) return Lifecycle.RUNNING; + if (a.isDestroyed()) return Lifecycle.DESTROYED; + + // adjuncts don't currently support an "error" state; though that would be useful! + + if (a instanceof Policy) { + if (((Policy)a).isSuspended()) return Lifecycle.STOPPED; + return Lifecycle.CREATED; + } + if (a instanceof Feed) { + if (((Feed)a).isSuspended()) return Lifecycle.STOPPED; + if (((Feed)a).isActivated()) return Lifecycle.STARTING; + return Lifecycle.CREATED; + } + + // Enricher doesn't support suspend so if not running or destroyed then + // it is just created + return Lifecycle.CREATED; + } + } diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java b/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java index 4b32dfc218..0af5c6a18d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java +++ b/core/src/main/java/org/apache/brooklyn/core/policy/Policies.java @@ -18,94 +18,18 @@ */ package org.apache.brooklyn.core.policy; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.objs.EntityAdjunct; import org.apache.brooklyn.api.policy.Policy; -import org.apache.brooklyn.api.sensor.Feed; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.api.sensor.SensorEventListener; +import org.apache.brooklyn.core.entity.EntityAdjuncts; import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.google.common.annotations.Beta; - -import groovy.lang.Closure; - -@SuppressWarnings({"rawtypes","unchecked"}) +/** @deprecated since 0.13.0 use {@link EntityAdjuncts} */ +@Deprecated public class Policies { - private static final Logger LOG = LoggerFactory.getLogger(Policies.class); - - /** - * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted. - */ + /** @deprecated since 0.13.0, use {@link EntityAdjuncts#inferAdjunctStatus(org.apache.brooklyn.api.objs.EntityAdjunct)} */ @Deprecated - public static SensorEventListener listenerFromValueClosure(final Closure code) { - LOG.warn("Use of groovy.lang.Closure is deprecated in Policies.listenerFromValueClosure()"); - return new SensorEventListener() { - @Override - public void onEvent(SensorEvent event) { - code.call(event.getValue()); - } - }; - } - - /** - * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted. - */ - @Deprecated - public static Policy newSingleSensorValuePolicy(final Sensor sensor, final Closure code) { - LOG.warn("Use of groovy.lang.Closure is deprecated in Policies.newSingleSensorValuePolicy()"); - return new AbstractPolicy() { - @Override - public void setEntity(EntityLocal entity) { - super.setEntity(entity); - entity.subscriptions().subscribe(entity, sensor, listenerFromValueClosure(code)); - } - }; - } - - /** - * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted. - */ - @Deprecated - public static Policy newSingleSensorValuePolicy(final Entity remoteEntity, final Sensor remoteSensor, - final Closure code) { - LOG.warn("Use of groovy.lang.Closure is deprecated in Policies.newSingleSensorValuePolicy()"); - return new AbstractPolicy() { - @Override - public void setEntity(EntityLocal entity) { - super.setEntity(entity); - entity.subscriptions().subscribe(remoteEntity, remoteSensor, listenerFromValueClosure(code)); - } - }; - } - public static Lifecycle getPolicyStatus(Policy p) { - return inferAdjunctStatus(p); - } - - @Beta - public static Lifecycle inferAdjunctStatus(EntityAdjunct a) { - if (a.isRunning()) return Lifecycle.RUNNING; - if (a.isDestroyed()) return Lifecycle.DESTROYED; - - // adjuncts don't currently support an "error" state; though that would be useful! - - if (a instanceof Policy) { - if (((Policy)a).isSuspended()) return Lifecycle.STOPPED; - return Lifecycle.CREATED; - } - if (a instanceof Feed) { - if (((Feed)a).isSuspended()) return Lifecycle.STOPPED; - if (((Feed)a).isActivated()) return Lifecycle.STARTING; - return Lifecycle.CREATED; - } - - return Lifecycle.STOPPED; + return EntityAdjuncts.inferAdjunctStatus(p); } } diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java index 1886f6390b..da5c1bf7f5 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java @@ -54,18 +54,20 @@ public interface AdjunctApi { response = org.apache.brooklyn.rest.domain.AdjunctSummary.class, responseContainer = "List") @ApiResponses(value = { - @ApiResponse(code = 404, message = "Could not find application or entity") + @ApiResponse(code = 404, message = "Could not find application or entity"), + @ApiResponse(code = 400, message = "Type is not known adjunct kind") }) public List list( @ApiParam(value = "Application ID or name", required = true) @PathParam("application") final String application, @ApiParam(value = "Entity ID or name", required = true) @PathParam("entity") final String entityToken, - @ApiParam(value = "Filter by adjunct type", required = false) + @ApiParam(value = "Filter by adjunct type (policy, enricher, feed)", required = false) @QueryParam("adjunctType") final String adjunctType); + // TODO support YAML ? @POST - @ApiOperation(value = "Add an adjunct (policy, enricher, or feed)", notes = "Returns a summary of the added adjunct") + @ApiOperation(value = "Create and add an adjunct (e.g. a policy, enricher, or feed) to this entity", notes = "Returns a summary of the added adjunct") @ApiResponses(value = { @ApiResponse(code = 404, message = "Could not find application or entity"), @ApiResponse(code = 400, message = "Type is not a suitable adjunct") @@ -121,7 +123,8 @@ public Status getStatus( @Path("/{adjunct}/start") @ApiOperation(value = "Start or resume an adjunct") @ApiResponses(value = { - @ApiResponse(code = 404, message = "Could not find application, entity or adjunct") + @ApiResponse(code = 404, message = "Could not find application, entity or adjunct"), + @ApiResponse(code = 400, message = "Adjunct does not support start/stop") }) public Response start( @ApiParam(name = "application", value = "Application ID or name", required = true) @@ -137,7 +140,8 @@ public Response start( @Path("/{adjunct}/stop") @ApiOperation(value = "Suspends an adjunct") @ApiResponses(value = { - @ApiResponse(code = 404, message = "Could not find application, entity or adjunct") + @ApiResponse(code = 404, message = "Could not find application, entity or adjunct"), + @ApiResponse(code = 400, message = "Adjunct does not support start/stop") }) public Response stop( @ApiParam(name = "application", value = "Application ID or name", required = true) diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java index 95f41db681..1bee2f84a5 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyApi.java @@ -36,7 +36,7 @@ @Api("Entity Policies") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -/** @deprecated since 0.12.0 use AdjunctApi */ +/** @deprecated since 0.13.0 use AdjunctApi */ @Deprecated public interface PolicyApi { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java index 8d061dd405..f38d9d41fe 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/PolicyConfigApi.java @@ -42,7 +42,7 @@ @Api("Entity Policy Config") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -/** @deprecated since 0.12.0 use AdjunctApi */ +/** @deprecated since 0.13.0 use AdjunctApi */ @Deprecated public interface PolicyConfigApi { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java index ca80644cbd..97ce1b23f2 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AdjunctSummary.java @@ -58,8 +58,6 @@ public AdjunctSummary(EntityAdjunct a) { highlights = a.getHighlights(); } - /** @deprecated since 0.12.0 only for legacy type-specific summary classes */ - @Deprecated protected AdjunctSummary( String id, String name, diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java index 52f7efd82e..172f66f6d7 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java @@ -27,8 +27,9 @@ import java.util.Objects; import java.util.Set; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -85,12 +86,13 @@ public ApplicationSpec build() { } private final String name; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_NULL) private final String type; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_NULL) private final Set entities; + @JsonInclude(Include.NON_NULL) private final Set locations; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + @JsonInclude(Include.NON_EMPTY) private final Map config; public ApplicationSpec( @@ -106,7 +108,7 @@ public ApplicationSpec( } else { this.entities = (entities.isEmpty() && type!=null) ? null : ImmutableSet.copyOf(entities); } - this.locations = ImmutableSet.copyOf(checkNotNull(locations, "locations must be provided for an application spec")); + this.locations = locations == null ? Collections.emptySet() : ImmutableSet.copyOf(locations); this.config = config == null ? Collections.emptyMap() : ImmutableMap.copyOf(config); if (this.entities!=null && this.type!=null) throw new IllegalStateException("cannot supply both type and entities for an application spec"); // valid for both to be null, e.g. for an anonymous type diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java index c65551533a..56ff0ff334 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java @@ -23,11 +23,13 @@ import java.util.Objects; import java.util.Set; +import org.apache.brooklyn.rest.api.TypeApi; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.collect.ImmutableSet; -/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */ @Deprecated public class CatalogEnricherSummary extends CatalogItemSummary { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java index 7dbc1beebf..6df6b383a1 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java @@ -23,11 +23,13 @@ import java.util.Objects; import java.util.Set; +import org.apache.brooklyn.rest.api.TypeApi; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */ @Deprecated public class CatalogEntitySummary extends CatalogItemSummary { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java index cd85c13bba..19a1749011 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java @@ -26,6 +26,8 @@ import java.util.Objects; import java.util.Set; +import org.apache.brooklyn.rest.api.TypeApi; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -36,7 +38,7 @@ * see also, subclasses */ @JsonIgnoreProperties(ignoreUnknown = true) // ignore unknown, ie properties from subclasses (entity) -/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */ @Deprecated public class CatalogItemSummary implements HasId, HasName, Serializable { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java index 5fb1a4b59c..1b769489af 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java @@ -23,10 +23,12 @@ import java.util.Objects; import java.util.Set; +import org.apache.brooklyn.rest.api.TypeApi; + import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableSet; -/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */ @Deprecated public class CatalogLocationSummary extends CatalogItemSummary { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java index ad67786a9c..dafa6bb1a9 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java @@ -23,11 +23,13 @@ import java.util.Objects; import java.util.Set; +import org.apache.brooklyn.rest.api.TypeApi; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.collect.ImmutableSet; -/** @deprecated since 0.12.0 new TypeApi returns TypeSummary */ +/** @deprecated since 0.13.0 new {@link TypeApi} returns {@link TypeSummary} */ @Deprecated public class CatalogPolicySummary extends CatalogItemSummary { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java index 3e09c73f3f..7f38438cd1 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java @@ -23,8 +23,9 @@ import java.util.Map; import java.util.Set; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.ImmutableMap; @@ -38,7 +39,7 @@ public static class ParameterSummary implements HasName, Serializable { private final String name; private final String type; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_NULL) private final String description; private final T defaultValue; private final boolean shouldSanitize; @@ -110,9 +111,9 @@ public String toString() { private final String name; private final String returnType; private final Set> parameters; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_EMPTY) private final String description; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_EMPTY) private final Map links; public EffectorSummary( diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java index 567c40bda4..f49bb81362 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityDetail.java @@ -18,23 +18,25 @@ */ package org.apache.brooklyn.rest.domain; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.google.common.collect.ImmutableList; -import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; - import java.net.URI; import java.util.Collections; import java.util.List; import java.util.Map; +import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableList; + public class EntityDetail extends EntitySummary { private static final long serialVersionUID = 100490507982229165L; private final String applicationId; private final String parentId; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + @JsonInclude(Include.NON_EMPTY) private final List children; private final List groupIds; private final List> members; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java index e0a585a116..ae123ef421 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java @@ -18,15 +18,16 @@ */ package org.apache.brooklyn.rest.domain; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.google.common.collect.ImmutableMap; - import java.io.Serializable; import java.net.URI; import java.util.Map; import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableMap; + public class EntitySummary implements HasId, HasName, Serializable { private static final long serialVersionUID = 100490507982229165L; @@ -34,7 +35,7 @@ public class EntitySummary implements HasId, HasName, Serializable { private final String id; private final String name; private final String type; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_NULL) private final String catalogItemId; private final Map links; diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java index 338604514b..4098ee17c1 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicyConfigSummary.java @@ -26,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; -/** @deprecated since 0.13.0 no different to ConfigSummary, use that */ +/** @deprecated since 0.13.0 no different to {@link ConfigSummary}, use that */ @Deprecated public class PolicyConfigSummary extends ConfigSummary { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java index da4a86a05e..1d0e9307d2 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/PolicySummary.java @@ -26,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; -/** @deprecated since 0.12.0 use {@link AdjunctSummary}; this class is identical */ +/** @deprecated since 0.13.0 use {@link AdjunctSummary}; this class is identical */ @Deprecated public class PolicySummary extends AdjunctSummary { diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java index c84573c3d9..326601895e 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ScriptExecutionSummary.java @@ -21,20 +21,21 @@ import java.io.Serializable; import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; public class ScriptExecutionSummary implements Serializable { private static final long serialVersionUID = -7707936602991185960L; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_NULL) private final Object result; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + @JsonInclude(Include.NON_EMPTY) private final String problem; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + @JsonInclude(Include.NON_EMPTY) private final String stdout; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + @JsonInclude(Include.NON_EMPTY) private final String stderr; public ScriptExecutionSummary( diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java index 11a4d2f519..9442f33e16 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/SensorSummary.java @@ -23,8 +23,9 @@ import java.util.Map; import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.collect.ImmutableMap; public class SensorSummary implements HasName, Serializable { @@ -33,9 +34,9 @@ public class SensorSummary implements HasName, Serializable { private final String name; private final String type; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_NULL) private final String description; - @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) + @JsonInclude(Include.NON_NULL) private final Map links; public SensorSummary( diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java index 08f3698c73..6090e6d310 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java @@ -51,7 +51,6 @@ 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; @@ -121,9 +120,11 @@ public AdjunctSummary addAdjunct(String application, String entityToken, String } 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)) { + 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 { @@ -141,9 +142,11 @@ else if (Feed.class.isAssignableFrom(type)) { 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 { + 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); } @@ -169,9 +172,13 @@ public Status getStatus(String application, String entityToken, String 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); + 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(); } @@ -179,9 +186,13 @@ public Response start(String application, String entityToken, String adjunctId) @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); + 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(); } @@ -200,6 +211,7 @@ public Response destroy(String application, String entityToken, String adjunctId ((Feed)adjunct).suspend(); ((EntityInternal)entity).feeds().remove((Feed) adjunct); } else { + // shouldn't come here throw WebResourceUtils.badRequest("Unexpected adjunct type %s", adjunct); } @@ -233,7 +245,8 @@ public Map batchConfigRead(String application, String entityToke public String getConfig(String application, String entityToken, String adjunctToken, String configKeyName) { EntityAdjunct adjunct = brooklyn().getAdjunct(application, entityToken, adjunctToken); Set> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName))); - if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken); + // TODO try deprecated names? + if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in adjunct '%s' of entity '%s'", configKeyName, adjunctToken, entityToken); return brooklyn().getStringValueForDisplay(adjunct.config().get(cki.iterator().next())); } @@ -249,7 +262,8 @@ public Response setConfig(String application, String entityToken, String adjunct EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken); Set> cki = adjunct.config().findKeysDeclared(ConfigPredicates.nameSatisfies(Predicates.equalTo(configKeyName))); - if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in policy '%s' of entity '%s'", configKeyName, adjunctToken, entityToken); + // TODO try deprecated names? + if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in adjunct '%s' of entity '%s'", configKeyName, adjunctToken, entityToken); ConfigKey ck = cki.iterator().next(); adjunct.config().set((ConfigKey) cki, TypeCoercions.coerce(value, ck.getTypeToken())); @@ -257,8 +271,4 @@ public Response setConfig(String application, String entityToken, String adjunct return Response.status(Response.Status.OK).build(); } - public static String getStringValueForDisplay(BrooklynRestResourceUtils utils, EntityAdjunct policy, Object value) { - return utils.getStringValueForDisplay(value); - } - } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java index a00cb6e355..f6598ecd4c 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/AdjunctTransformer.java @@ -30,7 +30,7 @@ import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.sensor.Feed; import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.policy.Policies; +import org.apache.brooklyn.core.entity.EntityAdjuncts; import org.apache.brooklyn.rest.api.AdjunctApi; import org.apache.brooklyn.rest.domain.AdjunctDetail; import org.apache.brooklyn.rest.domain.AdjunctSummary; @@ -86,7 +86,7 @@ protected static Map buildLinks(Entity entity, EntityAdjunct adjunc } public static Status inferStatus(EntityAdjunct adjunct) { - return ApplicationTransformer.statusFromLifecycle( Policies.inferAdjunctStatus(adjunct) ); + return ApplicationTransformer.statusFromLifecycle( EntityAdjuncts.inferAdjunctStatus(adjunct) ); } public static URI adjunctUri(Entity entity, EntityAdjunct adjunct, UriBuilder ub) { diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java index 6eeaeb82cd..8bff9f14fd 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/CatalogTransformer.java @@ -71,7 +71,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; -/** @deprecated since 0.13.0 use RegisteredType methods */ +/** @deprecated since 0.13.0 use {@link RegisteredType} methods in {@link TypeTransformer} */ @Deprecated public class CatalogTransformer { diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java index 22d429972e..314ce3c3d8 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/ConfigTransformer.java @@ -79,6 +79,8 @@ public ConfigTransformer on(Entity entity, EntityAdjunct adjunct) { return this; } + /** configures this transformer to be able to include links, and which types of links to include; + * note {@link #on(Entity)} or {@link #on(Entity, EntityAdjunct)} is needed to construct most links. */ public ConfigTransformer includeLinks(UriBuilder ub, boolean includeContextLinks, boolean includeActionLinks) { this.ub = ub; this.includeContextLinks = includeContextLinks; diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java index 2cb5dc7e07..577e4f1aaa 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java @@ -43,7 +43,7 @@ /** * Converts from Brooklyn entities to restful API summary objects - * @deprecated since 0.12.0 use {@link AdjunctTransformer} and {@link AdjunctSummary} + * @deprecated since 0.13.0 use {@link AdjunctTransformer} and {@link AdjunctSummary} */ @Deprecated public class PolicyTransformer { diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java index 9b0a3d46ff..d382205b0e 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtils.java @@ -155,18 +155,19 @@ public EntityAdjunct getAdjunct(Entity entity, String adjunct) { for (Policy p: entity.policies()) { if (adjunct.equals(p.getId())) return p; } - for (Policy p: entity.policies()) { - if (adjunct.equals(p.getDisplayName())) return p; - } for (Enricher p: entity.enrichers()) { if (adjunct.equals(p.getId())) return p; } - for (Enricher p: entity.enrichers()) { - if (adjunct.equals(p.getDisplayName())) return p; - } for (Feed p: ((EntityInternal)entity).feeds()) { if (adjunct.equals(p.getId())) return p; } + + for (Policy p: entity.policies()) { + if (adjunct.equals(p.getDisplayName())) return p; + } + for (Enricher p: entity.enrichers()) { + if (adjunct.equals(p.getDisplayName())) return p; + } for (Feed p: ((EntityInternal)entity).feeds()) { if (adjunct.equals(p.getDisplayName())) return p; } diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java index 30d6697ede..183f3de9fd 100644 --- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java +++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java @@ -152,7 +152,7 @@ public Boolean call() throws Exception { .run(); if (!started) { - log.warn("Did not start application "+applicationRef+":"); + log.warn("Did not start application "+applicationRef+" ("+getApplicationStatus(applicationRef)+"):"); Collection apps = getManagementContext().getApplications(); for (Application app: apps) Entities.dumpInfo(app); From d5d72cb9d98430112b93559a7f51d6c5b3e6a62f Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Tue, 3 Oct 2017 13:18:20 +0100 Subject: [PATCH 6/6] add adjuncts rest test, and minor fixes --- .../apache/brooklyn/rest/api/AdjunctApi.java | 2 +- .../rest/resources/AdjunctResource.java | 7 +- .../rest/resources/PolicyResource.java | 1 - .../rest/resources/AdjunctResourceTest.java | 198 ++++++++++++++++++ 4 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/AdjunctResourceTest.java diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java index da5c1bf7f5..ee43441565 100644 --- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java +++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/AdjunctApi.java @@ -72,7 +72,7 @@ public List list( @ApiResponse(code = 404, message = "Could not find application or entity"), @ApiResponse(code = 400, message = "Type is not a suitable adjunct") }) - public AdjunctSummary addAdjunct( + public AdjunctDetail addAdjunct( @ApiParam(name = "application", value = "Application ID or name", required = true) @PathParam("application") String application, diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java index 6090e6d310..111119303e 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/AdjunctResource.java @@ -106,7 +106,7 @@ public AdjunctSummary apply(EntityAdjunct adjunct) { // 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) { + public AdjunctDetail 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'", @@ -227,7 +227,7 @@ public List listConfig( EntityAdjunct adjunct = brooklyn().getAdjunct(entity, adjunctToken); List result = Lists.newArrayList(); - for (ConfigKey key : adjunct.config().findKeysPresent(Predicates.alwaysTrue())) { + for (ConfigKey key : adjunct.config().findKeysDeclared(Predicates.alwaysTrue())) { result.add(ConfigTransformer.of(key).on(entity, adjunct).includeLinks(ui.getBaseUriBuilder(), false, true).transform()); } return result; @@ -237,7 +237,6 @@ public List listConfig( // (and in sensors class) @Override public Map batchConfigRead(String application, String entityToken, String adjunctToken) { - // TODO: add test return EntityTransformer.getConfigValues(brooklyn(), brooklyn().getAdjunct(application, entityToken, adjunctToken) ); } @@ -266,7 +265,7 @@ public Response setConfig(String application, String entityToken, String adjunct if (cki.isEmpty()) throw WebResourceUtils.notFound("Cannot find config key '%s' in adjunct '%s' of entity '%s'", configKeyName, adjunctToken, entityToken); ConfigKey ck = cki.iterator().next(); - adjunct.config().set((ConfigKey) cki, TypeCoercions.coerce(value, ck.getTypeToken())); + adjunct.config().set((ConfigKey) ck, TypeCoercions.coerce(value, ck.getTypeToken())); return Response.status(Response.Status.OK).build(); } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java index 125b0b7181..924d3fd0c0 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java @@ -71,7 +71,6 @@ public PolicySummary apply(Policy policy) { // (and in sensors class) @Override public Map batchConfigRead( String application, String entityToken) { - // TODO: add test Entity entity = brooklyn().getEntity(application, entityToken); Map result = Maps.newLinkedHashMap(); for (Policy p : entity.policies()) { diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/AdjunctResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/AdjunctResourceTest.java new file mode 100644 index 0000000000..2bd9f2d622 --- /dev/null +++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/AdjunctResourceTest.java @@ -0,0 +1,198 @@ +/* + * 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 static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.brooklyn.api.objs.HighlightTuple; +import org.apache.brooklyn.rest.domain.AdjunctDetail; +import org.apache.brooklyn.rest.domain.AdjunctSummary; +import org.apache.brooklyn.rest.domain.ApplicationSpec; +import org.apache.brooklyn.rest.domain.ConfigSummary; +import org.apache.brooklyn.rest.domain.EntitySpec; +import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest; +import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity; +import org.apache.brooklyn.rest.testing.mocks.RestMockSimplePolicy; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.util.collections.MutableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +@Test(singleThreaded = true, + // by using a different suite name we disallow interleaving other tests between the methods of this test class, which wrecks the test fixtures + suiteName = "AdjunctResourceTest") +public class AdjunctResourceTest extends BrooklynRestResourceTest { + + private static final Logger log = LoggerFactory.getLogger(AdjunctResourceTest.class); + + private static final String ENDPOINT = "/applications/simple-app/entities/simple-ent/adjuncts/"; + + private final ApplicationSpec simpleSpec = ApplicationSpec.builder().name("simple-app").entities( + ImmutableSet.of(new EntitySpec("simple-ent", RestMockSimpleEntity.class.getName()))).locations( + ImmutableSet.of("localhost")).build(); + + private String policyId; + + @BeforeClass(alwaysRun = true) + public void setUp() throws Exception { + startServer(); + Response aResponse = clientDeploy(simpleSpec); + waitForApplicationToBeRunning(aResponse.getLocation()); + + Response pResponse = client().path(ENDPOINT) + .query("type", RestMockSimplePolicy.class.getCanonicalName()) + .type(MediaType.APPLICATION_JSON_TYPE) + .post(toJsonEntity(ImmutableMap.of())); + + AdjunctDetail response = pResponse.readEntity(AdjunctDetail.class); + assertNotNull(response.getId()); + policyId = response.getId(); + + } + + @Test + public void testListAdjuncts() throws Exception { + Set adjuncts = client().path(ENDPOINT) + .get(new GenericType>() {}); + + AdjunctSummary policy = null; + List others = MutableList.of(); + for (AdjunctSummary adj : adjuncts) { + if (adj.getId().equals(policyId)) { + policy = adj; + } else { + others.add(adj); + } + } + + log.info("Non-policy adjuncts: "+others); + Asserts.assertSize(others, 4); + + assertEquals(policy.getName(), RestMockSimplePolicy.class.getName()); + } + + + @Test + public void testGetDetail() throws Exception { + AdjunctDetail policy = client().path(ENDPOINT+policyId) + .get(AdjunctDetail.class); + + assertEquals(policy.getName(), RestMockSimplePolicy.class.getName()); + } + + @Test + public void testListConfig() throws Exception { + Set config = client().path(ENDPOINT + policyId + "/config") + .get(new GenericType>() {}); + + Set configNames = Sets.newLinkedHashSet(); + for (ConfigSummary conf : config) { + configNames.add(conf.getName()); + } + + assertEquals(configNames, ImmutableSet.of( + RestMockSimplePolicy.SAMPLE_CONFIG.getName(), + RestMockSimplePolicy.INTEGER_CONFIG.getName())); + } + + @Test + public void testGetNonExistentConfigReturns404() throws Exception { + String invalidConfigName = "doesnotexist"; + try { + ConfigSummary summary = client().path(ENDPOINT + policyId + "/config/" + invalidConfigName) + .get(ConfigSummary.class); + fail("Should have thrown 404, but got "+summary); + } catch (Exception e) { + if (!e.toString().contains("404")) throw e; + } + } + + @Test + public void testGetDefaultValue() throws Exception { + String configName = RestMockSimplePolicy.SAMPLE_CONFIG.getName(); + String expectedVal = RestMockSimplePolicy.SAMPLE_CONFIG.getDefaultValue(); + + String configVal = client().path(ENDPOINT + policyId + "/config/" + configName) + .get(String.class); + assertEquals(configVal, expectedVal); + } + + @Test(dependsOnMethods = "testGetDefaultValue") + public void testReconfigureConfig() throws Exception { + String configName = RestMockSimplePolicy.SAMPLE_CONFIG.getName(); + + Response response = client().path(ENDPOINT + policyId + "/config/" + configName) + .post(toJsonEntity("newval")); + + assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); + } + + @Test(dependsOnMethods = "testReconfigureConfig") + public void testGetConfigValue() throws Exception { + String configName = RestMockSimplePolicy.SAMPLE_CONFIG.getName(); + String expectedVal = "newval"; + + Map allState = client().path(ENDPOINT + policyId + "/config-current") + .get(new GenericType>() {}); + assertEquals(allState, ImmutableMap.of(configName, expectedVal)); + + String configVal = client().path(ENDPOINT + policyId + "/config/" + configName) + .get(String.class); + assertEquals(configVal, expectedVal); + } + + @Test + public void testHighlights() throws Exception { + Set policies = client().path(ENDPOINT) + .query("adjunctType", "policy") + .get(new GenericType>() {}); + + assertEquals(policies.size(), 1); + AdjunctSummary policySummary = policies.iterator().next(); + + Map highlights = policySummary.getHighlights(); + + assertEquals(highlights.size(), 2); + HighlightTuple highlightTupleTask = highlights.get("testNameTask"); + assertEquals(highlightTupleTask.getDescription(), "testDescription"); + assertEquals(highlightTupleTask.getTime(), 123L); + assertEquals(highlightTupleTask.getTaskId(), "testTaskId"); + + HighlightTuple highlightTupleNoTask = highlights.get("testNameNoTask"); + assertEquals(highlightTupleNoTask.getDescription(), "testDescription"); + assertEquals(highlightTupleNoTask.getTime(), 123L); + assertEquals(highlightTupleNoTask.getTaskId(), null); + } +}