| /* |
| * 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.InputStream; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.NoSuchElementException; |
| import java.util.Set; |
| |
| import javax.annotation.Nullable; |
| import javax.ws.rs.Consumes; |
| import javax.ws.rs.core.MediaType; |
| import javax.ws.rs.core.Response; |
| import javax.ws.rs.core.Response.Status; |
| |
| import org.apache.brooklyn.api.catalog.CatalogItem; |
| import org.apache.brooklyn.api.entity.Application; |
| import org.apache.brooklyn.api.entity.Entity; |
| import org.apache.brooklyn.api.entity.EntitySpec; |
| import org.apache.brooklyn.api.location.Location; |
| import org.apache.brooklyn.api.location.LocationSpec; |
| import org.apache.brooklyn.api.policy.Policy; |
| import org.apache.brooklyn.api.policy.PolicySpec; |
| import org.apache.brooklyn.api.typereg.RegisteredType; |
| import org.apache.brooklyn.core.catalog.CatalogPredicates; |
| import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; |
| import org.apache.brooklyn.core.catalog.internal.CatalogDto; |
| import org.apache.brooklyn.core.catalog.internal.CatalogItemComparator; |
| import org.apache.brooklyn.core.catalog.internal.CatalogUtils; |
| import org.apache.brooklyn.core.mgmt.entitlement.Entitlements; |
| import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.StringAndArgument; |
| import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts; |
| 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.CatalogEntitySummary; |
| import org.apache.brooklyn.rest.domain.CatalogItemSummary; |
| 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.WebResourceUtils; |
| import org.apache.brooklyn.util.collections.MutableMap; |
| 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.guava.Maybe; |
| import org.apache.brooklyn.util.stream.Streams; |
| 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.Function; |
| 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.collect.Lists; |
| import com.google.common.io.Files; |
| import com.sun.jersey.core.header.FormDataContentDisposition; |
| |
| @HaHotStateRequired |
| public class CatalogResource extends AbstractBrooklynRestResource implements CatalogApi { |
| |
| private static final Logger log = LoggerFactory.getLogger(CatalogResource.class); |
| |
| @SuppressWarnings("rawtypes") |
| private final Function<CatalogItem, CatalogItemSummary> TO_CATALOG_ITEM_SUMMARY = new Function<CatalogItem, CatalogItemSummary>() { |
| @Override |
| public CatalogItemSummary apply(@Nullable CatalogItem input) { |
| return CatalogTransformer.catalogItemSummary(brooklyn(), input); |
| } |
| }; |
| |
| @Override |
| @Consumes(MediaType.MULTIPART_FORM_DATA) |
| public Response createFromMultipart(InputStream uploadedInputStream, FormDataContentDisposition fileDetail) { |
| return create(Streams.readFullyString(uploadedInputStream)); |
| } |
| |
| static Set<String> missingIcons = MutableSet.of(); |
| |
| @Override |
| public Response create(String yaml) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.ADD_CATALOG_ITEM, yaml)) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to add catalog item", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| Iterable<? extends CatalogItem<?, ?>> items; |
| try { |
| items = brooklyn().getCatalog().addItems(yaml); |
| } catch (IllegalArgumentException e) { |
| return Response.status(Status.BAD_REQUEST) |
| .type(MediaType.APPLICATION_JSON) |
| .entity(ApiError.of(e)) |
| .build(); |
| } |
| |
| log.info("REST created catalog items: "+items); |
| |
| Map<String,Object> result = MutableMap.of(); |
| |
| for (CatalogItem<?,?> item: items) { |
| result.put(item.getId(), CatalogTransformer.catalogItemSummary(brooklyn(), item)); |
| } |
| return Response.status(Status.CREATED).entity(result).build(); |
| } |
| |
| @SuppressWarnings("deprecation") |
| @Override |
| public Response resetXml(String xml, boolean ignoreErrors) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, null) || |
| !Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.ADD_CATALOG_ITEM, null)) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to modify catalog", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| ((BasicBrooklynCatalog)mgmt().getCatalog()).reset(CatalogDto.newDtoFromXmlContents(xml, "REST reset"), !ignoreErrors); |
| return Response.ok().build(); |
| } |
| |
| @Override |
| @Deprecated |
| public void deleteEntity(String entityId) throws Exception { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(entityId, "delete"))) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to modify catalog", |
| Entitlements.getEntitlementContext().user()); |
| } |
| try { |
| Maybe<RegisteredType> item = RegisteredTypes.tryValidate(mgmt().getTypeRegistry().get(entityId), RegisteredTypeLoadingContexts.spec(Entity.class)); |
| if (item.isNull()) { |
| throw WebResourceUtils.notFound("Entity with id '%s' not found", entityId); |
| } |
| if (item.isAbsent()) { |
| throw WebResourceUtils.notFound("Item with id '%s' is not an entity", entityId); |
| } |
| |
| brooklyn().getCatalog().deleteCatalogItem(item.get().getSymbolicName(), item.get().getVersion()); |
| |
| } catch (NoSuchElementException e) { |
| // shouldn't come here |
| throw WebResourceUtils.notFound("Entity with id '%s' could not be deleted", entityId); |
| |
| } |
| } |
| |
| @Override |
| public void deleteApplication(String symbolicName, String version) throws Exception { |
| deleteEntity(symbolicName, version); |
| } |
| |
| @Override |
| 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.unauthorized("User '%s' is not authorized to modify catalog", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| RegisteredType item = mgmt().getTypeRegistry().get(symbolicName, version); |
| if (item == null) { |
| throw WebResourceUtils.notFound("Entity with id '%s:%s' not found", symbolicName, version); |
| } else if (!RegisteredTypePredicates.IS_ENTITY.apply(item) && !RegisteredTypePredicates.IS_APPLICATION.apply(item)) { |
| throw WebResourceUtils.preconditionFailed("Item with id '%s:%s' not an entity", symbolicName, version); |
| } else { |
| brooklyn().getCatalog().deleteCatalogItem(item.getSymbolicName(), item.getVersion()); |
| } |
| } |
| |
| @Override |
| 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.unauthorized("User '%s' is not authorized to modify catalog", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| RegisteredType item = mgmt().getTypeRegistry().get(policyId, version); |
| if (item == null) { |
| throw WebResourceUtils.notFound("Policy with id '%s:%s' not found", policyId, version); |
| } else if (!RegisteredTypePredicates.IS_POLICY.apply(item)) { |
| throw WebResourceUtils.preconditionFailed("Item with id '%s:%s' not a policy", policyId, version); |
| } else { |
| brooklyn().getCatalog().deleteCatalogItem(item.getSymbolicName(), item.getVersion()); |
| } |
| } |
| |
| @Override |
| 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.unauthorized("User '%s' is not authorized to modify catalog", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| RegisteredType item = mgmt().getTypeRegistry().get(locationId, version); |
| if (item == null) { |
| throw WebResourceUtils.notFound("Location with id '%s:%s' not found", locationId, version); |
| } else if (!RegisteredTypePredicates.IS_LOCATION.apply(item)) { |
| throw WebResourceUtils.preconditionFailed("Item with id '%s:%s' not a location", locationId, version); |
| } else { |
| brooklyn().getCatalog().deleteCatalogItem(item.getSymbolicName(), item.getVersion()); |
| } |
| } |
| |
| @Override |
| public List<CatalogEntitySummary> listEntities(String regex, String fragment, boolean allVersions) { |
| Predicate<CatalogItem<Entity, EntitySpec<?>>> filter = |
| Predicates.and( |
| CatalogPredicates.IS_ENTITY, |
| CatalogPredicates.<Entity, EntitySpec<?>>disabled(false)); |
| List<CatalogItemSummary> result = getCatalogItemSummariesMatchingRegexFragment(filter, regex, fragment, allVersions); |
| return castList(result, CatalogEntitySummary.class); |
| } |
| |
| @Override |
| public List<CatalogItemSummary> listApplications(String regex, String fragment, boolean allVersions) { |
| @SuppressWarnings("unchecked") |
| Predicate<CatalogItem<Application, EntitySpec<? extends Application>>> filter = |
| Predicates.and( |
| CatalogPredicates.IS_TEMPLATE, |
| CatalogPredicates.<Application,EntitySpec<? extends Application>>deprecated(false), |
| CatalogPredicates.<Application,EntitySpec<? extends Application>>disabled(false)); |
| return getCatalogItemSummariesMatchingRegexFragment(filter, regex, fragment, allVersions); |
| } |
| |
| @Override |
| @Deprecated |
| public CatalogEntitySummary getEntity(String entityId) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, entityId)) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| CatalogItem<Entity,EntitySpec<?>> result = |
| CatalogUtils.getCatalogItemOptionalVersion(mgmt(), Entity.class, entityId); |
| |
| if (result==null) { |
| throw WebResourceUtils.notFound("Entity with id '%s' not found", entityId); |
| } |
| |
| return CatalogTransformer.catalogEntitySummary(brooklyn(), result); |
| } |
| |
| @Override |
| public CatalogEntitySummary getEntity(String symbolicName, String version) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, symbolicName+(Strings.isBlank(version)?"":":"+version))) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| //TODO These casts are not pretty, we could just provide separate get methods for the different types? |
| //Or we could provide asEntity/asPolicy cast methods on the CataloItem doing a safety check internally |
| @SuppressWarnings("unchecked") |
| CatalogItem<Entity, EntitySpec<?>> result = |
| (CatalogItem<Entity, EntitySpec<?>>) brooklyn().getCatalog().getCatalogItem(symbolicName, version); |
| |
| if (result==null) { |
| throw WebResourceUtils.notFound("Entity with id '%s:%s' not found", symbolicName, version); |
| } |
| |
| return CatalogTransformer.catalogEntitySummary(brooklyn(), result); |
| } |
| |
| @Override |
| @Deprecated |
| public CatalogEntitySummary getApplication(String applicationId) throws Exception { |
| return getEntity(applicationId); |
| } |
| |
| @Override |
| public CatalogEntitySummary getApplication(String symbolicName, String version) { |
| return getEntity(symbolicName, version); |
| } |
| |
| @Override |
| public List<CatalogPolicySummary> listPolicies(String regex, String fragment, boolean allVersions) { |
| Predicate<CatalogItem<Policy, PolicySpec<?>>> filter = |
| Predicates.and( |
| CatalogPredicates.IS_POLICY, |
| CatalogPredicates.<Policy, PolicySpec<?>>disabled(false)); |
| List<CatalogItemSummary> result = getCatalogItemSummariesMatchingRegexFragment(filter, regex, fragment, allVersions); |
| return castList(result, CatalogPolicySummary.class); |
| } |
| |
| @Override |
| @Deprecated |
| public CatalogPolicySummary getPolicy(String policyId) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, policyId)) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| CatalogItem<? extends Policy, PolicySpec<?>> result = |
| CatalogUtils.getCatalogItemOptionalVersion(mgmt(), Policy.class, policyId); |
| |
| if (result==null) { |
| throw WebResourceUtils.notFound("Policy with id '%s' not found", policyId); |
| } |
| |
| return CatalogTransformer.catalogPolicySummary(brooklyn(), result); |
| } |
| |
| @Override |
| 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.unauthorized("User '%s' is not authorized to see catalog entry", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| @SuppressWarnings("unchecked") |
| CatalogItem<? extends Policy, PolicySpec<?>> result = |
| (CatalogItem<? extends Policy, PolicySpec<?>>)brooklyn().getCatalog().getCatalogItem(policyId, version); |
| |
| if (result==null) { |
| throw WebResourceUtils.notFound("Policy with id '%s:%s' not found", policyId, version); |
| } |
| |
| return CatalogTransformer.catalogPolicySummary(brooklyn(), result); |
| } |
| |
| @Override |
| public List<CatalogLocationSummary> listLocations(String regex, String fragment, boolean allVersions) { |
| Predicate<CatalogItem<Location, LocationSpec<?>>> filter = |
| Predicates.and( |
| CatalogPredicates.IS_LOCATION, |
| CatalogPredicates.<Location, LocationSpec<?>>disabled(false)); |
| List<CatalogItemSummary> result = getCatalogItemSummariesMatchingRegexFragment(filter, regex, fragment, allVersions); |
| return castList(result, CatalogLocationSummary.class); |
| } |
| |
| @Override |
| @Deprecated |
| public CatalogLocationSummary getLocation(String locationId) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, locationId)) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| CatalogItem<? extends Location, LocationSpec<?>> result = |
| CatalogUtils.getCatalogItemOptionalVersion(mgmt(), Location.class, locationId); |
| |
| if (result==null) { |
| throw WebResourceUtils.notFound("Location with id '%s' not found", locationId); |
| } |
| |
| return CatalogTransformer.catalogLocationSummary(brooklyn(), result); |
| } |
| |
| @Override |
| 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.unauthorized("User '%s' is not authorized to see catalog entry", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| @SuppressWarnings("unchecked") |
| CatalogItem<? extends Location, LocationSpec<?>> result = |
| (CatalogItem<? extends Location, LocationSpec<?>>)brooklyn().getCatalog().getCatalogItem(locationId, version); |
| |
| if (result==null) { |
| throw WebResourceUtils.notFound("Location with id '%s:%s' not found", locationId, version); |
| } |
| |
| return CatalogTransformer.catalogLocationSummary(brooklyn(), result); |
| } |
| |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| private <T,SpecT> List<CatalogItemSummary> getCatalogItemSummariesMatchingRegexFragment(Predicate<CatalogItem<T,SpecT>> type, String regex, String fragment, boolean allVersions) { |
| List filters = new ArrayList(); |
| filters.add(type); |
| if (Strings.isNonEmpty(regex)) |
| filters.add(CatalogPredicates.xml(StringPredicates.containsRegex(regex))); |
| if (Strings.isNonEmpty(fragment)) |
| filters.add(CatalogPredicates.xml(StringPredicates.containsLiteralIgnoreCase(fragment))); |
| if (!allVersions) |
| filters.add(CatalogPredicates.isBestVersion(mgmt())); |
| |
| filters.add(CatalogPredicates.entitledToSee(mgmt())); |
| |
| ImmutableList<CatalogItem<Object, Object>> sortedItems = |
| FluentIterable.from(brooklyn().getCatalog().getCatalogItems()) |
| .filter(Predicates.and(filters)) |
| .toSortedList(CatalogItemComparator.getInstance()); |
| return Lists.transform(sortedItems, TO_CATALOG_ITEM_SUMMARY); |
| } |
| |
| @Override |
| @Deprecated |
| public Response getIcon(String itemId) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, itemId)) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| return getCatalogItemIcon( mgmt().getTypeRegistry().get(itemId) ); |
| } |
| |
| @Override |
| public Response getIcon(String itemId, String version) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, itemId+(Strings.isBlank(version)?"":":"+version))) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry", |
| Entitlements.getEntitlementContext().user()); |
| } |
| |
| return getCatalogItemIcon(mgmt().getTypeRegistry().get(itemId, version)); |
| } |
| |
| @Override |
| public void setDeprecatedLegacy(String itemId, boolean deprecated) { |
| log.warn("Use of deprecated \"/v1/catalog/entities/{itemId}/deprecated/{deprecated}\" for "+itemId |
| +"; use \"/v1/catalog/entities/{itemId}/deprecated\" with request body"); |
| setDeprecated(itemId, deprecated); |
| } |
| |
| @SuppressWarnings("deprecation") |
| @Override |
| public void setDeprecated(String itemId, boolean deprecated) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(itemId, "deprecated"))) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to modify catalog", |
| Entitlements.getEntitlementContext().user()); |
| } |
| CatalogUtils.setDeprecated(mgmt(), itemId, deprecated); |
| } |
| |
| @SuppressWarnings("deprecation") |
| @Override |
| public void setDisabled(String itemId, boolean disabled) { |
| if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(itemId, "disabled"))) { |
| throw WebResourceUtils.unauthorized("User '%s' is not authorized to modify catalog", |
| Entitlements.getEntitlementContext().user()); |
| } |
| CatalogUtils.setDisabled(mgmt(), itemId, disabled); |
| } |
| |
| private Response getCatalogItemIcon(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(); |
| } |
| |
| // TODO Move to an appropriate utility class? |
| @SuppressWarnings("unchecked") |
| private static <T> List<T> castList(List<? super T> list, Class<T> elementType) { |
| List<T> result = Lists.newArrayList(); |
| Iterator<? super T> li = list.iterator(); |
| while (li.hasNext()) { |
| try { |
| result.add((T) li.next()); |
| } catch (Throwable throwable) { |
| if (throwable instanceof NoClassDefFoundError) { |
| // happens if class cannot be loaded for any reason during transformation - don't treat as fatal |
| } else { |
| Exceptions.propagateIfFatal(throwable); |
| } |
| |
| // item cannot be transformed; we will have logged a warning earlier |
| log.debug("Ignoring invalid catalog item: "+throwable); |
| } |
| } |
| return result; |
| } |
| } |