You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2017/09/25 09:29:33 UTC
[02/11] brooklyn-server git commit: REST API for bundles, types,
and subtypes
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9b337035/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynRestApi.java
----------------------------------------------------------------------
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 01e8ad5..b3eb4e4 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
@@ -26,6 +26,7 @@ import org.apache.brooklyn.rest.resources.AccessResource;
import org.apache.brooklyn.rest.resources.ActivityResource;
import org.apache.brooklyn.rest.resources.ApidocResource;
import org.apache.brooklyn.rest.resources.ApplicationResource;
+import org.apache.brooklyn.rest.resources.BundleResource;
import org.apache.brooklyn.rest.resources.CatalogResource;
import org.apache.brooklyn.rest.resources.EffectorResource;
import org.apache.brooklyn.rest.resources.EntityConfigResource;
@@ -37,6 +38,8 @@ import org.apache.brooklyn.rest.resources.PolicyResource;
import org.apache.brooklyn.rest.resources.ScriptResource;
import org.apache.brooklyn.rest.resources.SensorResource;
import org.apache.brooklyn.rest.resources.ServerResource;
+import org.apache.brooklyn.rest.resources.SubtypeResource;
+import org.apache.brooklyn.rest.resources.TypeResource;
import org.apache.brooklyn.rest.resources.UsageResource;
import org.apache.brooklyn.rest.util.DefaultExceptionMapper;
import org.apache.brooklyn.rest.util.FormMapProvider;
@@ -46,14 +49,15 @@ import com.google.common.collect.Iterables;
import io.swagger.jaxrs.listing.SwaggerSerializers;
-
-@SuppressWarnings("deprecation")
public class BrooklynRestApi {
public static Iterable<AbstractBrooklynRestResource> getBrooklynRestResources() {
List<AbstractBrooklynRestResource> resources = new ArrayList<>();
resources.add(new LocationResource());
resources.add(new CatalogResource());
+ resources.add(new TypeResource());
+ resources.add(new SubtypeResource());
+ resources.add(new BundleResource());
resources.add(new ApplicationResource());
resources.add(new EntityResource());
resources.add(new EntityConfigResource());
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9b337035/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/BundleResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/BundleResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/BundleResource.java
new file mode 100644
index 0000000..a2a6532
--- /dev/null
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/BundleResource.java
@@ -0,0 +1,186 @@
+/*
+ * 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.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.brooklyn.api.typereg.ManagedBundle;
+import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
+import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
+import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.rest.api.BundleApi;
+import org.apache.brooklyn.rest.domain.ApiError;
+import org.apache.brooklyn.rest.domain.BundleInstallationRestResult;
+import org.apache.brooklyn.rest.domain.BundleSummary;
+import org.apache.brooklyn.rest.filter.HaHotStateRequired;
+import org.apache.brooklyn.rest.transform.TypeTransformer;
+import org.apache.brooklyn.rest.util.WebResourceUtils;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.ReferenceWithError;
+import org.apache.brooklyn.util.osgi.VersionedName;
+import org.apache.brooklyn.util.osgi.VersionedName.VersionedNameComparator;
+import org.apache.brooklyn.util.yaml.Yamls;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+@HaHotStateRequired
+public class BundleResource extends AbstractBrooklynRestResource implements BundleApi {
+
+ private static final Logger log = LoggerFactory.getLogger(BundleResource.class);
+ private static final String LATEST = "latest";
+
+ @Override
+ public List<BundleSummary> list(String versions) {
+ return list(TypeResource.isLatestOnly(versions, true), Predicates.alwaysTrue());
+ }
+
+ private List<BundleSummary> list(boolean onlyLatest, Predicate<String> symbolicNameFilter) {
+
+ Map<VersionedName,ManagedBundle> bundles = new TreeMap<>(VersionedNameComparator.INSTANCE);
+ for (ManagedBundle b: ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundles().values()) {
+ if (symbolicNameFilter.apply(b.getSymbolicName())) {
+ // TODO entitlements for bundles
+ VersionedName key = onlyLatest ? new VersionedName(b.getSymbolicName(), LATEST) : b.getVersionedName();
+ ManagedBundle oldBundle = bundles.get(key);
+ if (oldBundle==null || oldBundle.getVersionedName().compareTo(b.getVersionedName()) > 0) {
+ bundles.put(key, b);
+ }
+ }
+ }
+ return toBundleSummary(bundles.values());
+ }
+
+ private List<BundleSummary> toBundleSummary(Iterable<ManagedBundle> sortedItems) {
+ List<BundleSummary> result = MutableList.of();
+ for (ManagedBundle t: sortedItems) {
+ result.add(TypeTransformer.bundleSummary(brooklyn(), t, ui.getBaseUriBuilder(), mgmt()));
+ }
+ return result;
+ }
+
+ @Override
+ public List<BundleSummary> listVersions(String symbolicName) {
+ return list(false, Predicates.equalTo(symbolicName));
+ }
+
+ @Override
+ public BundleSummary detail(String symbolicName, String version) {
+ ManagedBundle b = lookup(symbolicName, version);
+ return TypeTransformer.bundleDetails(brooklyn(), b, ui.getBaseUriBuilder(), mgmt());
+ }
+
+ protected ManagedBundle lookup(String symbolicName, String version) {
+ // TODO entitlements for bundles
+
+ ManagedBundle b = ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundle(new VersionedName(symbolicName, version));
+ if (b==null) {
+ throw WebResourceUtils.notFound("Bundle with id '%s:%s' not found", symbolicName, version);
+ }
+ return b;
+ }
+
+ @Override
+ public BundleInstallationRestResult remove(String symbolicName, String version, Boolean force) {
+ ManagedBundle b = lookup(symbolicName, version);
+ log.info("REST removing "+symbolicName+":"+version);
+ if (force==null) force = false;
+ ReferenceWithError<OsgiBundleInstallationResult> r = ((ManagementContextInternal)mgmt()).getOsgiManager().get().uninstallUploadedBundle(b, force);
+ return TypeTransformer.bundleInstallationResult(r.getWithoutError(), mgmt(), brooklyn(), ui);
+ }
+
+
+ @Override
+ public Response createFromYaml(String yaml, Boolean force) {
+ if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.ADD_CATALOG_ITEM, yaml)) {
+ throw WebResourceUtils.forbidden("User '%s' is not authorized to add catalog items",
+ Entitlements.getEntitlementContext().user());
+ }
+ if (force==null) force = false;
+
+ try {
+ return Response.status(Status.CREATED).entity(
+ TypeTransformer.bundleInstallationResult(
+ ((BasicBrooklynCatalog)brooklyn().getCatalog()).addItemsBundleResult(yaml, force), mgmt(), brooklyn(), ui)).build();
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ return badRequest(e);
+ }
+ }
+
+ @Override
+ public Response createFromArchive(byte[] zipInput, Boolean force) {
+ if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.ROOT, null)) {
+ throw WebResourceUtils.forbidden("User '%s' is not authorized to add catalog items",
+ Entitlements.getEntitlementContext().user());
+ }
+ if (force==null) force = false;
+
+ ReferenceWithError<OsgiBundleInstallationResult> result = ((ManagementContextInternal)mgmt()).getOsgiManager().get()
+ .install(null, new ByteArrayInputStream(zipInput), true, true, force);
+
+ if (OsgiBundleInstallationResult.ResultCode.IGNORING_BUNDLE_AREADY_INSTALLED.equals(result.getWithoutError().getCode())) {
+ result = ReferenceWithError.newInstanceThrowingError(result.getWithoutError(), new IllegalStateException(
+ "Cannot add bundle" + result.getWithoutError().getMetadata().getVersionedName() +
+ "; different bundle with same name already installed"));
+ }
+
+ if (result.hasError()) {
+ // (rollback already done as part of install, if necessary)
+ if (log.isTraceEnabled()) {
+ log.trace("Unable to create from archive, returning 400: "+result.getError().getMessage(), result.getError());
+ }
+ return ApiError.builder().errorCode(Status.BAD_REQUEST).message(result.getWithoutError().getMessage())
+ .data(TypeTransformer.bundleInstallationResult(result.getWithoutError(), mgmt(), brooklyn(), ui)).build().asJsonResponse();
+ }
+
+ BundleInstallationRestResult resultR = TypeTransformer.bundleInstallationResult(result.get(), mgmt(), brooklyn(), ui);
+ return Response.status(Status.CREATED).entity( resultR ).build();
+ }
+
+ @Override
+ public Response createAutodetecting(byte[] item, Boolean force) {
+ Throwable yamlException = null;
+ try {
+ MutableList.copyOf( Yamls.parseAll(new InputStreamReader(new ByteArrayInputStream(item))) );
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ yamlException = e;
+ }
+
+ if (yamlException==null) {
+ // treat as yaml if it parsed
+ return createFromYaml(new String(item), force);
+ }
+
+ return createFromArchive(item, force);
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9b337035/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
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 d327e40..65e6956 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
@@ -35,7 +35,6 @@ import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.apache.brooklyn.api.catalog.CatalogItem;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.typereg.RegisteredType;
import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
@@ -46,6 +45,7 @@ import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
import org.apache.brooklyn.core.typereg.RegisteredTypes;
import org.apache.brooklyn.rest.api.CatalogApi;
import org.apache.brooklyn.rest.domain.ApiError;
+import org.apache.brooklyn.rest.domain.BundleInstallationRestResult;
import org.apache.brooklyn.rest.domain.CatalogEnricherSummary;
import org.apache.brooklyn.rest.domain.CatalogEntitySummary;
import org.apache.brooklyn.rest.domain.CatalogItemSummary;
@@ -53,7 +53,7 @@ import org.apache.brooklyn.rest.domain.CatalogLocationSummary;
import org.apache.brooklyn.rest.domain.CatalogPolicySummary;
import org.apache.brooklyn.rest.filter.HaHotStateRequired;
import org.apache.brooklyn.rest.transform.CatalogTransformer;
-import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
+import org.apache.brooklyn.rest.transform.TypeTransformer;
import org.apache.brooklyn.rest.util.WebResourceUtils;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
@@ -149,36 +149,6 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
}
}
- public static class BundleInstallationRestResult {
- // as Osgi result, but without bundle, and with maps of catalog items installed
-
- String message;
- String bundle;
- OsgiBundleInstallationResult.ResultCode code;
-
- Map<String,Object> types;
-
- public String getMessage() {
- return message;
- }
-
- public static BundleInstallationRestResult of(OsgiBundleInstallationResult in, ManagementContext mgmt, BrooklynRestResourceUtils brooklynU, UriInfo ui) {
- BundleInstallationRestResult result = new BundleInstallationRestResult();
- result.message = in.getMessage();
- result.bundle = in.getVersionedName() != null ? in.getVersionedName().toString() : "";
- result.code = in.getCode();
- if (in.getCatalogItemsInstalled()!=null) {
- result.types = MutableMap.of();
- for (String id: in.getCatalogItemsInstalled()) {
- RegisteredType ci = mgmt.getTypeRegistry().get(id);
- CatalogItemSummary summary = CatalogTransformer.catalogItemSummary(brooklynU, ci, ui.getBaseUriBuilder());
- result.types.put(id, summary);
- }
- }
- return result;
- }
- }
-
@Override
@Beta
public Response createFromArchive(byte[] zipInput, boolean detail, boolean forceUpdate) {
@@ -202,11 +172,11 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
log.trace("Unable to create from archive, returning 400: "+result.getError().getMessage(), result.getError());
}
return ApiError.builder().errorCode(Status.BAD_REQUEST).message(result.getWithoutError().getMessage())
- .data(BundleInstallationRestResult.of(result.getWithoutError(), mgmt(), brooklyn(), ui)).build().asJsonResponse();
+ .data(TypeTransformer.bundleInstallationResult(result.getWithoutError(), mgmt(), brooklyn(), ui)).build().asJsonResponse();
}
- BundleInstallationRestResult resultR = BundleInstallationRestResult.of(result.get(), mgmt(), brooklyn(), ui);
- return Response.status(Status.CREATED).entity( detail ? resultR : resultR.types ).build();
+ BundleInstallationRestResult resultR = TypeTransformer.bundleInstallationResult(result.get(), mgmt(), brooklyn(), ui);
+ return Response.status(Status.CREATED).entity( detail ? resultR : resultR.getTypes() ).build();
}
private Response buildCreateResponse(Iterable<RegisteredType> catalogItems) {
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9b337035/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/SubtypeResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/SubtypeResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/SubtypeResource.java
new file mode 100644
index 0000000..12716b3
--- /dev/null
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/SubtypeResource.java
@@ -0,0 +1,82 @@
+/*
+ * 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.List;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
+import org.apache.brooklyn.core.typereg.RegisteredTypes;
+import org.apache.brooklyn.rest.api.SubtypeApi;
+import org.apache.brooklyn.rest.domain.TypeSummary;
+import org.apache.brooklyn.rest.filter.HaHotStateRequired;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.text.StringPredicates;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+
+@HaHotStateRequired
+public class SubtypeResource extends AbstractBrooklynRestResource implements SubtypeApi {
+
+ @SuppressWarnings("unused")
+ private static final Logger log = LoggerFactory.getLogger(SubtypeResource.class);
+
+ @Override
+ public List<TypeSummary> list(String supertype, String versions, String regex, String fragment) {
+ List<Predicate<RegisteredType>> filters = MutableList.<Predicate<RegisteredType>>of()
+ .append(RegisteredTypePredicates.entitledToSee(mgmt()))
+ .append(RegisteredTypePredicates.subtypeOf(supertype));
+ if (TypeResource.isLatestOnly(versions, true)) {
+ // TODO inefficient - does n^2 comparisons where n is sufficient
+ // create RegisteredTypes.filterBestVersions to do a list after the initial parse
+ // (and javadoc in predicate method below)
+ filters.add(RegisteredTypePredicates.isBestVersion(mgmt()));
+ }
+ if (Strings.isNonEmpty(regex)) {
+ filters.add(RegisteredTypePredicates.nameOrAlias(StringPredicates.containsRegex(regex)));
+ }
+ if (Strings.isNonEmpty(fragment)) {
+ filters.add(RegisteredTypePredicates.nameOrAlias(StringPredicates.containsLiteralIgnoreCase(fragment)));
+ }
+ Predicate<RegisteredType> filter = Predicates.and(filters);
+ ImmutableList<RegisteredType> sortedItems =
+ FluentIterable.from(brooklyn().getTypeRegistry().getMatching(filter))
+ .toSortedList(RegisteredTypes.RegisteredTypeNameThenBestFirstComparator.INSTANCE);
+ return TypeResource.toTypeSummary(brooklyn(), sortedItems, ui.getBaseUriBuilder());
+ }
+
+ @Override public List<TypeSummary> listApplications(String versions, String regex, String fragment) { return list(Application.class.getName(), versions, regex, fragment); }
+ @Override public List<TypeSummary> listEntities(String versions, String regex, String fragment) { return list(Entity.class.getName(), versions, regex, fragment); }
+ @Override public List<TypeSummary> listPolicies(String versions, String regex, String fragment) { return list(Policy.class.getName(), versions, regex, fragment); }
+ @Override public List<TypeSummary> listEnrichers(String versions, String regex, String fragment) { return list(Enricher.class.getName(), versions, regex, fragment); }
+ @Override public List<TypeSummary> listLocations(String versions, String regex, String fragment) { return list(Location.class.getName(), versions, regex, fragment); }
+
+}
+
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9b337035/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/TypeResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/TypeResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/TypeResource.java
new file mode 100644
index 0000000..86de57d
--- /dev/null
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/TypeResource.java
@@ -0,0 +1,186 @@
+/*
+ * 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.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
+import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
+import org.apache.brooklyn.core.typereg.RegisteredTypes;
+import org.apache.brooklyn.rest.api.TypeApi;
+import org.apache.brooklyn.rest.domain.TypeDetail;
+import org.apache.brooklyn.rest.domain.TypeSummary;
+import org.apache.brooklyn.rest.filter.HaHotStateRequired;
+import org.apache.brooklyn.rest.transform.TypeTransformer;
+import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
+import org.apache.brooklyn.rest.util.WebResourceUtils;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.StringPredicates;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.Files;
+
+@HaHotStateRequired
+public class TypeResource extends AbstractBrooklynRestResource implements TypeApi {
+
+ private static final Logger log = LoggerFactory.getLogger(TypeResource.class);
+ private static final String LATEST = "latest";
+ private static final String ALL = "all";
+
+ private static Set<String> missingIcons = MutableSet.of();
+
+ static boolean isLatestOnly(String versions, boolean defaultValue) {
+ if (ALL.equalsIgnoreCase(versions)) return false;
+ if (LATEST.equalsIgnoreCase(versions)) return true;
+ if (Strings.isNonBlank(versions)) {
+ log.warn("Invalid 'versions' argument '"+versions+"' when listing types; should be 'all' or 'latest'");
+ }
+ return defaultValue;
+ }
+
+ @Override
+ public List<TypeSummary> list(String versions, String regex, String fragment) {
+ List<Predicate<RegisteredType>> filters = MutableList.<Predicate<RegisteredType>>of()
+ .append(RegisteredTypePredicates.entitledToSee(mgmt()));
+ if (TypeResource.isLatestOnly(versions, true)) {
+ // TODO inefficient - does n^2 comparisons where n is sufficient
+ // create RegisteredTypes.filterBestVersions to do a list after the initial parse
+ // (and javadoc in predicate method below)
+ filters.add(RegisteredTypePredicates.isBestVersion(mgmt()));
+ }
+ if (Strings.isNonEmpty(regex)) {
+ filters.add(RegisteredTypePredicates.nameOrAlias(StringPredicates.containsRegex(regex)));
+ }
+ if (Strings.isNonEmpty(fragment)) {
+ filters.add(RegisteredTypePredicates.nameOrAlias(StringPredicates.containsLiteralIgnoreCase(fragment)));
+ }
+ Predicate<RegisteredType> filter = Predicates.and(filters);
+
+ ImmutableList<RegisteredType> sortedItems =
+ FluentIterable.from(brooklyn().getTypeRegistry().getMatching(filter))
+ .toSortedList(RegisteredTypes.RegisteredTypeNameThenBestFirstComparator.INSTANCE);
+ return toTypeSummary(brooklyn(), sortedItems, ui.getBaseUriBuilder());
+ }
+
+ static List<TypeSummary> toTypeSummary(BrooklynRestResourceUtils brooklyn, Iterable<RegisteredType> sortedItems, UriBuilder uriBuilder) {
+ List<TypeSummary> result = MutableList.of();
+ for (RegisteredType t: sortedItems) {
+ result.add(TypeTransformer.summary(brooklyn, t, uriBuilder));
+ }
+ return result;
+ }
+
+ @Override
+ public List<TypeSummary> listVersions(String nameOrAlias) {
+ Predicate<RegisteredType> filter = Predicates.and(RegisteredTypePredicates.entitledToSee(mgmt()),
+ RegisteredTypePredicates.nameOrAlias(nameOrAlias));
+ ImmutableList<RegisteredType> sortedItems =
+ FluentIterable.from(brooklyn().getTypeRegistry().getMatching(filter))
+ .toSortedList(RegisteredTypes.RegisteredTypeNameThenBestFirstComparator.INSTANCE);
+ return toTypeSummary(brooklyn(), sortedItems, ui.getBaseUriBuilder());
+ }
+
+ @Override
+ public TypeDetail detail(String symbolicName, String version) {
+ RegisteredType item = lookup(symbolicName, version);
+ return TypeTransformer.detail(brooklyn(), item, ui.getBaseUriBuilder());
+ }
+
+ protected RegisteredType lookup(String symbolicName, String version) {
+ if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, symbolicName+":"+version)) {
+ // TODO best to default to "not found" - unless maybe they have permission to "see null"
+ throw WebResourceUtils.forbidden("User '%s' not permitted to see info on this type (including whether or not installed)",
+ Entitlements.getEntitlementContext().user());
+ }
+ RegisteredType item;
+ if (LATEST.equalsIgnoreCase(version)) {
+ item = brooklyn().getTypeRegistry().get(symbolicName);
+ } else {
+ item = brooklyn().getTypeRegistry().get(symbolicName, version);
+ }
+ if (item==null) {
+ throw WebResourceUtils.notFound("Entity with id '%s:%s' not found", symbolicName, version);
+ }
+ return item;
+ }
+
+ @Override
+ public Response icon(String symbolicName, String version) {
+ RegisteredType item = lookup(symbolicName, version);
+ return produceIcon(item);
+ }
+
+ private Response produceIcon(RegisteredType result) {
+ String url = result.getIconUrl();
+ if (url==null) {
+ log.debug("No icon available for "+result+"; returning "+Status.NO_CONTENT);
+ return Response.status(Status.NO_CONTENT).build();
+ }
+
+ if (brooklyn().isUrlServerSideAndSafe(url)) {
+ // classpath URL's we will serve IF they end with a recognised image format;
+ // paths (ie non-protocol) and
+ // NB, for security, file URL's are NOT served
+ log.debug("Loading and returning "+url+" as icon for "+result);
+
+ MediaType mime = WebResourceUtils.getImageMediaTypeFromExtension(Files.getFileExtension(url));
+ try {
+ Object content = ResourceUtils.create(CatalogUtils.newClassLoadingContext(mgmt(), result)).getResourceFromUrl(url);
+ return Response.ok(content, mime).build();
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ synchronized (missingIcons) {
+ if (missingIcons.add(url)) {
+ // note: this can be quite common when running from an IDE, as resources may not be copied;
+ // a mvn build should sort it out (the IDE will then find the resources, until you clean or maybe refresh...)
+ log.warn("Missing icon data for "+result.getId()+", expected at: "+url+" (subsequent messages will log debug only)");
+ log.debug("Trace for missing icon data at "+url+": "+e, e);
+ } else {
+ log.debug("Missing icon data for "+result.getId()+", expected at: "+url+" (already logged WARN and error details)");
+ }
+ }
+ throw WebResourceUtils.notFound("Icon unavailable for %s", result.getId());
+ }
+ }
+
+ log.debug("Returning redirect to "+url+" as icon for "+result);
+
+ // for anything else we do a redirect (e.g. http / https; perhaps ftp)
+ return Response.temporaryRedirect(URI.create(url)).build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9b337035/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/EntityTransformer.java
----------------------------------------------------------------------
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 8a15020..6bf3f19 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
@@ -19,6 +19,7 @@
package org.apache.brooklyn.rest.transform;
import static com.google.common.collect.Iterables.transform;
+import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
import java.lang.reflect.Field;
import java.net.URI;
@@ -26,13 +27,21 @@ import java.util.List;
import java.util.Map;
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.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.catalog.internal.CatalogUtils;
import org.apache.brooklyn.core.config.render.RendererHints;
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.AdjunctConfigSummary;
import org.apache.brooklyn.rest.domain.EnricherConfigSummary;
import org.apache.brooklyn.rest.domain.EntityConfigSummary;
import org.apache.brooklyn.rest.domain.EntitySummary;
@@ -43,13 +52,6 @@ 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 javax.ws.rs.core.UriBuilder;
-import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
-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 static org.apache.brooklyn.rest.util.WebResourceUtils.serviceUriBuilder;
/**
* @author Adam Lowe
@@ -123,6 +125,10 @@ public class EntityTransformer {
return new EntityConfigSummary(config, label, priority, pinned, mapOfLinks);
}
+ public static AdjunctConfigSummary adjunctConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
+ return new AdjunctConfigSummary(config, label, priority, links);
+ }
+
public static PolicyConfigSummary policyConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
return new PolicyConfigSummary(config, label, priority, links);
}
@@ -192,6 +198,11 @@ public class EntityTransformer {
return entityConfigSummary(input.getConfigKey(), input.getLabel(), priority, input.isPinned(), null);
}
+ public static AdjunctConfigSummary adjunctConfigSummary(SpecParameter<?> input) {
+ Double priority = input.isPinned() ? Double.valueOf(1d) : null;
+ return policyConfigSummary(input.getConfigKey(), input.getLabel(), priority, null);
+ }
+
public static PolicyConfigSummary policyConfigSummary(SpecParameter<?> input) {
Double priority = input.isPinned() ? Double.valueOf(1d) : null;
return policyConfigSummary(input.getConfigKey(), input.getLabel(), priority, null);
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9b337035/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..fb3fdd3
--- /dev/null
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/TypeTransformer.java
@@ -0,0 +1,194 @@
+/*
+ * 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.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.EntityType;
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+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.Enricher;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.core.entity.EntityDynamicType;
+import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
+import org.apache.brooklyn.core.objs.BrooklynTypes;
+import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
+import org.apache.brooklyn.core.typereg.RegisteredTypes;
+import org.apache.brooklyn.rest.api.TypeApi;
+import org.apache.brooklyn.rest.domain.AdjunctConfigSummary;
+import org.apache.brooklyn.rest.domain.BundleInstallationRestResult;
+import org.apache.brooklyn.rest.domain.BundleSummary;
+import org.apache.brooklyn.rest.domain.EffectorSummary;
+import org.apache.brooklyn.rest.domain.EntityConfigSummary;
+import org.apache.brooklyn.rest.domain.SensorSummary;
+import org.apache.brooklyn.rest.domain.SummaryComparators;
+import org.apache.brooklyn.rest.domain.TypeDetail;
+import org.apache.brooklyn.rest.domain.TypeSummary;
+import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+public class TypeTransformer {
+
+ private static final org.slf4j.Logger log = LoggerFactory.getLogger(TypeTransformer.class);
+
+ public static <T extends Entity> TypeSummary summary(BrooklynRestResourceUtils b, RegisteredType item, UriBuilder ub) {
+ return embellish(new TypeSummary(item), item, false, b, ub);
+ }
+
+ public static TypeDetail detail(BrooklynRestResourceUtils b, RegisteredType item, UriBuilder ub) {
+ return embellish(new TypeDetail(item), item, true, b, ub);
+ }
+
+ private static <T extends TypeSummary> T embellish(T result, RegisteredType item, boolean detail, BrooklynRestResourceUtils b, UriBuilder ub) {
+ result.getExtraFields().put("links", makeLinks(item, ub));
+
+ if (RegisteredTypes.isTemplate(item)) {
+ result.getExtraFields().put("template", true);
+ }
+ if (item.getIconUrl()!=null) {
+ result.setIconUrl(tidyIconLink(b, item, item.getIconUrl(), ub));
+ }
+
+ if (detail) {
+ if (RegisteredTypes.isSubtypeOf(item, Entity.class)) {
+ embellishEntity(result, item, b);
+ } else if (RegisteredTypes.isSubtypeOf(item, EntityAdjunct.class) ||
+ // when implied supertypes are used we won't need the code below
+ RegisteredTypes.isSubtypeOf(item, Policy.class) || RegisteredTypes.isSubtypeOf(item, Enricher.class) || RegisteredTypes.isSubtypeOf(item, Feed.class)
+ ) {
+ try {
+ Set<AdjunctConfigSummary> config = Sets.newLinkedHashSet();
+
+ AbstractBrooklynObjectSpec<?,?> spec = b.getTypeRegistry().createSpec(item, null, null);
+ for (final SpecParameter<?> input : spec.getParameters()){
+ config.add(EntityTransformer.adjunctConfigSummary(input));
+ }
+
+ result.getExtraFields().put("config", config);
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ log.trace("Unable to create spec for "+item+": "+e, e);
+ }
+
+ } else if (RegisteredTypes.isSubtypeOf(item, Location.class)) {
+ // TODO include config on location specs? (wasn't done previously so not needed, but good for completeness)
+ result.getExtraFields().put("config", Collections.emptyMap());
+ }
+ }
+ return result;
+ }
+
+ protected static <T extends TypeSummary> void embellishEntity(T result, RegisteredType item, BrooklynRestResourceUtils b) {
+ try {
+ Set<EntityConfigSummary> config = Sets.newLinkedHashSet();
+ Set<SensorSummary> sensors = Sets.newTreeSet(SummaryComparators.nameComparator());
+ Set<EffectorSummary> effectors = Sets.newTreeSet(SummaryComparators.nameComparator());
+
+ EntitySpec<?> spec = b.getTypeRegistry().createSpec(item, null, EntitySpec.class);
+ EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType());
+ EntityType type = typeMap.getSnapshot();
+
+ AtomicInteger paramPriorityCnt = new AtomicInteger();
+ for (SpecParameter<?> input: spec.getParameters())
+ config.add(EntityTransformer.entityConfigSummary(input, paramPriorityCnt));
+ for (Sensor<?> x: type.getSensors())
+ sensors.add(SensorTransformer.sensorSummaryForCatalog(x));
+ for (Effector<?> x: type.getEffectors())
+ effectors.add(EffectorTransformer.effectorSummaryForCatalog(x));
+
+ result.getExtraFields().put("config", config);
+ result.getExtraFields().put("sensors", sensors);
+ result.getExtraFields().put("effectors", effectors);
+
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+
+ // templates with multiple entities can't have spec created in the manner above; just ignore
+ if (item.getSuperTypes().contains(Entity.class)) {
+ log.warn("Unable to create spec for "+item+": "+e, e);
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("Unable to create spec for "+item+": "+e, e);
+ }
+ }
+ }
+
+ public static BundleSummary bundleSummary(BrooklynRestResourceUtils brooklyn, ManagedBundle b, UriBuilder baseUriBuilder, ManagementContext mgmt) {
+ BundleSummary result = new BundleSummary(b);
+ for (RegisteredType t: mgmt.getTypeRegistry().getMatching(RegisteredTypePredicates.containingBundle(b))) {
+ result.addType(summary(brooklyn, t, baseUriBuilder));
+ }
+ return result;
+ }
+
+ public static BundleSummary bundleDetails(BrooklynRestResourceUtils brooklyn, ManagedBundle b, UriBuilder baseUriBuilder, ManagementContext mgmt) {
+ BundleSummary result = bundleSummary(brooklyn, b, baseUriBuilder, mgmt);
+ result.getExtraFields().put("osgiVersion", b.getOsgiVersionString());
+ result.getExtraFields().put("checksum", b.getChecksum());
+ return result;
+ }
+
+ public static BundleInstallationRestResult bundleInstallationResult(OsgiBundleInstallationResult in, ManagementContext mgmt, BrooklynRestResourceUtils brooklynU, UriInfo ui) {
+ BundleInstallationRestResult result = new BundleInstallationRestResult(
+ in.getMessage(), in.getVersionedName() != null ? in.getVersionedName().toString() : "", in.getCode());
+ for (RegisteredType t: in.getTypesInstalled()) {
+ TypeSummary summary = TypeTransformer.summary(brooklynU, t, ui.getBaseUriBuilder());
+ result.getTypes().put(t.getId(), summary);
+ }
+ return result;
+ }
+
+ protected static Map<String, URI> makeLinks(RegisteredType item, UriBuilder ub) {
+ return MutableMap.<String, URI>of().addIfNotNull("self", getSelfLink(item, ub));
+ }
+
+ private static URI getSelfLink(RegisteredType item, UriBuilder ub) {
+ return serviceUriBuilder(ub, TypeApi.class, "detail").build(item.getSymbolicName(), item.getVersion());
+ }
+ private static String tidyIconLink(BrooklynRestResourceUtils b, RegisteredType item, String iconUrl, UriBuilder ub) {
+ if (b.isUrlServerSideAndSafe(iconUrl)) {
+ return serviceUriBuilder(ub, TypeApi.class, "icon").build(item.getSymbolicName(), item.getVersion()).toString();
+ }
+ return iconUrl;
+ }
+
+}