/* * 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 com.google.common.collect.Iterables.transform; import java.lang.reflect.Field; import java.net.URI; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; 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.SpecParameter; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.render.RendererHints; import org.apache.brooklyn.rest.domain.EntityConfigSummary; import org.apache.brooklyn.rest.domain.EntitySummary; import org.apache.brooklyn.rest.util.WebResourceUtils; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.net.URLParamEncoder; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; /** * @author Adam Lowe */ public class EntityTransformer { public static final Function<? super Entity, EntitySummary> FROM_ENTITY = new Function<Entity, EntitySummary>() { @Override public EntitySummary apply(Entity entity) { return EntityTransformer.entitySummary(entity); } }; public static EntitySummary entitySummary(Entity entity) { String applicationUri = "/v1/applications/" + entity.getApplicationId(); String entityUri = applicationUri + "/entities/" + entity.getId(); ImmutableMap.Builder<String, URI> lb = ImmutableMap.<String, URI>builder() .put("self", URI.create(entityUri)); if (entity.getParent()!=null) lb.put("parent", URI.create(applicationUri+"/entities/"+entity.getParent().getId())); String type = entity.getEntityType().getName(); lb.put("application", URI.create(applicationUri)) .put("children", URI.create(entityUri + "/children")) .put("config", URI.create(entityUri + "/config")) .put("sensors", URI.create(entityUri + "/sensors")) .put("effectors", URI.create(entityUri + "/effectors")) .put("policies", URI.create(entityUri + "/policies")) .put("activities", URI.create(entityUri + "/activities")) .put("locations", URI.create(entityUri + "/locations")) .put("tags", URI.create(entityUri + "/tags")) .put("expunge", URI.create(entityUri + "/expunge")) .put("rename", URI.create(entityUri + "/name")) .put("spec", URI.create(entityUri + "/spec")) ; if (entity.getCatalogItemId() != null) { lb.put("catalog", URI.create("/v1/catalog/entities/" + WebResourceUtils.getPathFromVersionedId(entity.getCatalogItemId()))); } if (entity.getIconUrl()!=null) lb.put("iconUrl", URI.create(entityUri + "/icon")); return new EntitySummary(entity.getId(), entity.getDisplayName(), type, entity.getCatalogItemId(), lb.build()); } public static List<EntitySummary> entitySummaries(Iterable<? extends Entity> entities) { return Lists.newArrayList(transform( entities, new Function<Entity, EntitySummary>() { @Override public EntitySummary apply(Entity entity) { return EntityTransformer.entitySummary(entity); } })); } protected static EntityConfigSummary entityConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) { Map<String, URI> mapOfLinks = links==null ? null : ImmutableMap.copyOf(links); return new EntityConfigSummary(config, label, priority, mapOfLinks); } /** 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 applicaiton */ public static EntityConfigSummary entityConfigSummary(Entity entity, ConfigKey<?> config) { /* * 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()); String label = null; Double priority = null; String applicationUri = "/v1/applications/" + entity.getApplicationId(); String entityUri = applicationUri + "/entities/" + entity.getId(); String selfUri = entityUri + "/config/" + URLParamEncoder.encode(config.getName()); MutableMap.Builder<String, URI> lb = MutableMap.<String, URI>builder() .put("self", URI.create(selfUri)) .put("application", URI.create(applicationUri)) .put("entity", URI.create(entityUri)) .put("action:json", URI.create(selfUri)); Iterable<RendererHints.NamedAction> hints = Iterables.filter(RendererHints.getHintsFor(config), RendererHints.NamedAction.class); for (RendererHints.NamedAction na : hints) { SensorTransformer.addNamedAction(lb, na, entity.getConfig(config), config, entity); } return entityConfigSummary(config, label, priority, lb.build()); } public static String applicationUri(Application entity) { return "/v1/applications/" + entity.getApplicationId(); } public static String entityUri(Entity entity) { return applicationUri(entity.getApplication()) + "/entities/" + entity.getId(); } public static EntityConfigSummary entityConfigSummary(ConfigKey<?> config, Field configKeyField) { CatalogConfig catalogConfig = configKeyField!=null ? configKeyField.getAnnotation(CatalogConfig.class) : null; String label = catalogConfig==null ? null : catalogConfig.label(); Double priority = catalogConfig==null ? null : catalogConfig.priority(); return entityConfigSummary(config, label, priority, null); } 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 // 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 entityConfigSummary(input.getConfigKey(), input.getLabel(), priority, null); } }