Java Code Examples for org.apache.brooklyn.util.exceptions.Exceptions#propagateAnnotated()

The following examples show how to use org.apache.brooklyn.util.exceptions.Exceptions#propagateAnnotated() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: CatalogResource.java    From brooklyn-server with Apache License 2.0 6 votes vote down vote up
private Response buildCreateResponse(Iterable<RegisteredType> catalogItems) {
    log.info("REST created catalog items: "+catalogItems);

    Map<String,Object> result = MutableMap.of();

    for (RegisteredType catalogItem: catalogItems) {
        try {
            result.put(
                    catalogItem.getId(),
                    CatalogTransformer.catalogItemSummary(brooklyn(), catalogItem, ui.getBaseUriBuilder()));
        } catch (Throwable t) {
            log.warn("Error loading catalog item '"+catalogItem+"' (rethrowing): "+t);
            // unfortunately items are already added to the catalog and hard to remove,
            // but at least let the user know;
            // happens eg if a class refers to a missing class, like
            // loading nosql items including mongo without the mongo bson class on the classpath
            throw Exceptions.propagateAnnotated("At least one unusable item was added ("+catalogItem.getId()+")", t);
        }
    }
    return Response.status(Status.CREATED).entity(result).build();
}
 
Example 2
Source File: BundleMaker.java    From brooklyn-server with Apache License 2.0 6 votes vote down vote up
/** installs the given JAR file as an OSGi bundle; all manifest info should be already set up.
 * bundle-start semantics are TBD.
 * 
 * @deprecated since 0.12.0, use {@link OsgiManager#installUploadedBundle(org.apache.brooklyn.api.typereg.ManagedBundle, InputStream)}*/
@Deprecated
public Bundle installBundle(File f, boolean start) {
    try {
        Bundle b = Osgis.install( framework, "file://"+f.getAbsolutePath() );
        if (start) {
            // benefits of start:
            // a) we get wiring issues thrown here, and
            // b) catalog.bom in root will be scanned synchronously here
            // however drawbacks:
            // c) other code doesn't always do it (method above)
            // d) heavier-weight earlier
            // e) tests in IDE break (but mvn fine)
            b.start();
        }
        
        return b;
        
    } catch (Exception e) {
        throw Exceptions.propagateAnnotated("Error starting bundle from "+f, e);
    }
}
 
Example 3
Source File: BundleMaker.java    From brooklyn-server with Apache License 2.0 6 votes vote down vote up
/** Creates a temporary file with the given metadata */ 
public File createTempBundle(String nameHint, Manifest mf, Map<ZipEntry, InputStream> files) {
    File f2 = Os.newTempFile(nameHint, "zip");
    ZipOutputStream zout = null;
    ZipFile zf = null;
    try {
        zout = mf!=null ? new JarOutputStream(new FileOutputStream(f2), mf) : new ZipOutputStream(new FileOutputStream(f2));
        writeZipEntries(zout, files);
    } catch (IOException e) {
        throw Exceptions.propagateAnnotated("Unable to read/write for "+nameHint, e);
    } finally {
        Streams.closeQuietly(zf);
        Streams.closeQuietly(zout);
    }
    return f2;
}
 
Example 4
Source File: DslDeferredFunctionCall.java    From brooklyn-server with Apache License 2.0 6 votes vote down vote up
protected Maybe<Object> invoke() {
    findMethod();
    
    if (method.isPresent()) {
        Method m = method.get();
    
        checkCallAllowed(m);
    
        try {
            // Value is most likely another BrooklynDslDeferredSupplier - let the caller handle it,
            return Maybe.of(Reflections.invokeMethodFromArgs(instance, m, instanceArgs));
        } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
            // If the method is there but not executable for whatever reason fail with a fatal error, don't return an absent.
            throw Exceptions.propagateAnnotated("Error invoking '"+toStringF(fnName, instanceArgs)+"' on '"+instance+"'", e);
        }
    } else {
        // could do deferred execution if an argument is a deferred supplier:
        // if we get a present from:
        // new Invoker(obj, fnName, replaceSuppliersWithNull(args)).findMethod()
        // then return a
        // new DslDeferredFunctionCall(...)
        
        return Maybe.absent(new IllegalArgumentException("No such function '"+fnName+"' taking args "+args+" (on "+obj+")"));
    }
}
 
Example 5
Source File: CatalogDo.java    From brooklyn-server with Apache License 2.0 6 votes vote down vote up
private void loadCatalogItems(boolean failOnLoadError) {
    Iterable<CatalogItemDtoAbstract<?, ?>> entries = dto.getUniqueEntries();
    if (entries!=null) {
        for (CatalogItemDtoAbstract<?,?> entry : entries) {
            try {
                CatalogUtils.installLibraries(mgmt, entry.getLibraries());
            } catch (Exception e) {
                Exceptions.propagateIfFatal(e);
                if (failOnLoadError) {
                    Exceptions.propagateAnnotated("Loading bundles for catalog item " + entry.getCatalogItemId() + " failed", e);
                } else {
                    log.error("Loading bundles for catalog item " + entry + " failed: " + e.getMessage(), e);
                }
            }
        }
    }
}
 
Example 6
Source File: BasicBrooklynCatalog.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
private void addCatalogLegacyItemsOnRebind(Iterable<? extends CatalogItem<?,?>> items, boolean failOnLoadError) {
    specCache.invalidate();
    
    log.debug("Adding manual catalog items to "+mgmt+": "+items);
    checkNotNull(items, "item");
    for (CatalogItem<?,?> item : items) {
        CatalogItemDtoAbstract<?,?> cdto;
        if (item instanceof CatalogItemDtoAbstract) {
            cdto = (CatalogItemDtoAbstract<?,?>) item;
        } else if (item instanceof CatalogItemDo && ((CatalogItemDo<?,?>)item).getDto() instanceof CatalogItemDtoAbstract) {
            cdto = (CatalogItemDtoAbstract<?,?>) ((CatalogItemDo<?,?>)item).getDto();
        } else {
            throw new IllegalArgumentException("Expected items of type "+CatalogItemDtoAbstract.class.getSimpleName());
        }
        cdto.setManagementContext((ManagementContextInternal) mgmt);
        
        try {
            CatalogUtils.installLibraries(mgmt, item.getLibraries());
        } catch (Exception e) {
            Exceptions.propagateIfFatal(e);
            if (failOnLoadError) {
                Exceptions.propagateAnnotated("Loading bundles for catalog item " + item.getCatalogItemId() + " failed", e);
            } else {
                log.error("Loading bundles for catalog item " + item + " failed: " + e.getMessage(), e);
            }
        }
        catalog.addEntry((CatalogItemDtoAbstract<?,?>)item);
    }
    catalog.load(mgmt, null, failOnLoadError);
}
 
Example 7
Source File: BundleUpgradeParser.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
private static VersionRangedName parseVersionRangedName(String name, String range, boolean singleVersionIsOsgiRange) {
    try {
        return new VersionRangedName(name, range, singleVersionIsOsgiRange);
    } catch (Exception e) {
        if (Strings.containsAny(range, "(", ")", "[", "]") &&
                !Strings.containsAny(range, "'", "\"")) {
            throw Exceptions.propagateAnnotated("Entry cannot be parsed. If defining a range on an entry you must quote the entry.", e);
        }
        throw Exceptions.propagate(e);
    }
}
 
Example 8
Source File: BundleUpgradeParser.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
private static VersionRangedName parseVersionRangedName(String val, boolean singleVersionIsOsgiRange) {
    try {
        return VersionRangedName.fromString(val, singleVersionIsOsgiRange);
    } catch (Exception e) {
        if (Strings.containsAny(val, "(", ")", "[", "]") &&
                !Strings.containsAny(val, "'", "\"")) {
            throw Exceptions.propagateAnnotated("Entry cannot be parsed. If defining a range on an entry you must quote the entry.", e);
        }
        throw Exceptions.propagate(e);
    }
}
 
Example 9
Source File: FileBasedStoreObjectAccessor.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
@Override
public void append(String val) {
    try {
        if (val==null) val = "";
        FileUtil.setFilePermissionsTo600(file);
        Files.append(val, file, Charsets.UTF_8);
        
    } catch (IOException e) {
        throw Exceptions.propagateAnnotated("Problem appending to file "+file, e);
    }
}
 
Example 10
Source File: FileBasedStoreObjectAccessor.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
@Override
public byte[] getBytes() {
    try {
        if (!exists()) return null;
        return Files.asByteSource(file).read();
    } catch (IOException e) {
        throw Exceptions.propagateAnnotated("Problem reading bytes of file "+file, e);
    }
}
 
Example 11
Source File: FileBasedStoreObjectAccessor.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
@Override
public String get() {
    try {
        if (!exists()) return null;
        return Files.asCharSource(file, Charsets.UTF_8).read();
    } catch (IOException e) {
        throw Exceptions.propagateAnnotated("Problem reading String contents of file "+file, e);
    }
}
 
Example 12
Source File: CatalogBundleLoader.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
private String readBom(URL bom) {
    try (final InputStream ins = bom.openStream()) {
        return Streams.readFullyString(ins);
    } catch (IOException e) {
        throw Exceptions.propagateAnnotated("Error loading Catalog BOM from " + bom, e);
    }
}
 
Example 13
Source File: BasicBrooklynCatalog.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
/**
 * @deprecated since 1.0.0; Catalog annotation is deprecated.
 */
@Deprecated
@SuppressWarnings("unused")  // keep during 0.12.0 until we are decided we won't support this; search for this method name
// (note that this now could work after rebind since we have the OSGi cache)
private Collection<CatalogItemDtoAbstract<?, ?>> scanAnnotationsInBundle(ManagementContext mgmt, ManagedBundle containingBundle) {
    CatalogDto dto = CatalogDto.newNamedInstance("Bundle "+containingBundle.getVersionedName().toOsgiString()+" Scanned Catalog", "All annotated Brooklyn entities detected in bundles", "scanning-bundle-"+containingBundle.getVersionedName().toOsgiString());
    CatalogDo subCatalog = new CatalogDo(dto);
    // need access to a JAR to scan this
    String url = null;
    File f = ((ManagementContextInternal)mgmt).getOsgiManager().get().getBundleFile(containingBundle);
    if (f!=null) {
        url = "file//:"+f.getAbsolutePath();
    }
    if (url==null) {
        url = containingBundle.getUrl();
    }
    if (url==null) {
        // should now always be available 
        throw new IllegalArgumentException("Error preparing to scan "+containingBundle.getVersionedName()+": no URL available");
    }
    // org.reflections requires the URL to be "file:" containg ".jar"
    File fJar = Os.newTempFile(containingBundle.getVersionedName().toOsgiString(), ".jar");
    try {
        Streams.copy(ResourceUtils.create().getResourceFromUrl(url), new FileOutputStream(fJar));
        subCatalog.addToClasspath(new String[] { "file:"+fJar.getAbsolutePath() });
        Collection<CatalogItemDtoAbstract<?, ?>> result = scanAnnotationsInternal(mgmt, subCatalog, MutableMap.of("version", containingBundle.getSuppliedVersionString()), containingBundle);
        return result;
    } catch (FileNotFoundException e) {
        throw Exceptions.propagateAnnotated("Error extracting "+url+" to scan "+containingBundle.getVersionedName(), e);
    } finally {
        fJar.delete();
    }
}
 
Example 14
Source File: BasicBrooklynCatalog.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
/** See comments on {@link #collectCatalogItemsFromItemMetadataBlock(String, ManagedBundle, Map, List, boolean, Map, int, boolean)};
 * this is a shell around that that parses the `brooklyn.catalog` header on the BOM YAML file */
private void collectCatalogItemsFromCatalogBomRoot(String contextForError, String yaml, ManagedBundle containingBundle, 
        List<CatalogItemDtoAbstract<?, ?>> resultLegacyFormat, Map<RegisteredType, RegisteredType> resultNewFormat, 
        boolean requireValidation, Map<?, ?> parentMeta, int depth, boolean force) {
    Map<?,?> itemDef;
    try {
        itemDef = Yamls.getAs(Yamls.parseAll(yaml), Map.class);
    } catch (Exception e) {
        throw Exceptions.propagateAnnotated("Error parsing YAML in "+contextForError, e);
    }
    Map<?,?> catalogMetadata = getFirstAsMap(itemDef, "brooklyn.catalog").orNull();
    if (catalogMetadata==null)
        log.warn("No `brooklyn.catalog` supplied in catalog request; using legacy mode for "+itemDef);
    catalogMetadata = MutableMap.copyOf(catalogMetadata);

    collectCatalogItemsFromItemMetadataBlock(Yamls.getTextOfYamlAtPath(yaml, "brooklyn.catalog").getMatchedYamlTextOrWarn(), 
        containingBundle, catalogMetadata, resultLegacyFormat, resultNewFormat, requireValidation, parentMeta, 0, force);
    
    itemDef.remove("brooklyn.catalog");
    catalogMetadata.remove("item");
    catalogMetadata.remove("items");
    if (!itemDef.isEmpty()) {
        // AH - i forgot we even supported this. probably no point anymore,
        // now that catalog defs can reference an item yaml and things can be bundled together?
        log.warn("Deprecated read of catalog item from sibling keys of `brooklyn.catalog` section, "
            + "instead of the more common appraoch of putting inside an `item` within it. "
            + "Rewrite to use nested/reference syntax instead or contact the community for assistance or feedback.");
        Map<String,?> rootItem = MutableMap.of("item", itemDef);
        String rootItemYaml = yaml;
        YamlExtract yamlExtract = Yamls.getTextOfYamlAtPath(rootItemYaml, "brooklyn.catalog");
        String match = yamlExtract.withOriginalIndentation(true).withKeyIncluded(true).getMatchedYamlTextOrWarn();
        if (match!=null) {
            if (rootItemYaml.startsWith(match)) rootItemYaml = Strings.removeFromStart(rootItemYaml, match);
            else rootItemYaml = Strings.replaceAllNonRegex(rootItemYaml, "\n"+match, "");
        }
        collectCatalogItemsFromItemMetadataBlock("item:\n"+makeAsIndentedObject(rootItemYaml), containingBundle, rootItem, resultLegacyFormat, resultNewFormat, requireValidation, catalogMetadata, 1, force);
    }
}
 
Example 15
Source File: InternalFactory.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
private <T> T constructWithSpecial(Class<? extends SpecialBrooklynObjectConstructor> special, Class<? extends T> clazz, AbstractBrooklynObjectSpec<?, ?> spec) {
    try {
        return special.newInstance().create(managementContext, clazz, spec);
    } catch (Exception e) {
        Exceptions.propagateIfFatal(e);
        throw Exceptions.propagateAnnotated("Unable to create "+clazz+" "+spec+" using special "+special, e);
    }
}
 
Example 16
Source File: CampTypePlanTransformer.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
@Override
protected AbstractBrooklynObjectSpec<?, ?> createSpec(RegisteredType type, RegisteredTypeLoadingContext context) throws Exception {
    try {
        return new CampResolver(mgmt, type, context).createSpec();
    } catch (Exception e) {
        Exceptions.propagateIfFatal(e);
        String message = null;
        // check a few common errors, annotate if so
        if (type==null || type.getPlan()==null || type.getPlan().getPlanData()==null) {
            // shouldn't happen
            message = "Type/plan/data is null when resolving CAMP blueprint";
        } else {
            Object planData = type.getPlan().getPlanData();
            if (RegisteredTypes.getAsYamlMap(planData).isAbsent()) {
                message = "Type or plan is invalid YAML when resolving CAMP blueprint";
            } else if (planData.toString().contains("brooklyn.catalog")) {
                message = "CAMP blueprint for type definition looks like a catalog file";
            } else {
                // leave null, don't annotate
            }
        }
        if (message!=null) {
            throw Exceptions.propagateAnnotated(message, e);
        } else {
            throw e;
        }
    }
}
 
Example 17
Source File: CatalogUtils.java    From brooklyn-server with Apache License 2.0 4 votes vote down vote up
/** As {@link #installLibraries(ManagementContext, Collection)} but letting caller suppress the deferred start/install
 * (for use in tests where bundles' BOMs aren't resolvable). */
public static void installLibraries(ManagementContext managementContext, @Nullable Collection<CatalogBundle> libraries, boolean startBundlesAndInstallToBrooklyn) {
    if (libraries == null) return;

    ManagementContextInternal mgmt = (ManagementContextInternal) managementContext;
    if (!libraries.isEmpty()) {
        Maybe<OsgiManager> osgi = mgmt.getOsgiManager();
        if (osgi.isAbsent()) {
            throw new IllegalStateException("Unable to load bundles "+libraries+" because OSGi is not running.");
        }
        if (log.isDebugEnabled()) 
            logDebugOrTraceIfRebinding(log, 
                "Loading bundles in {}: {}", 
                new Object[] {managementContext, Joiner.on(", ").join(libraries)});
        Stopwatch timer = Stopwatch.createStarted();
        List<OsgiBundleInstallationResult> results = MutableList.of();
        for (CatalogBundle bundle : libraries) {
            OsgiBundleInstallationResult result = osgi.get().installDeferredStart(BasicManagedBundle.of(bundle), null, true).get();
            if (log.isDebugEnabled()) {
                logDebugOrTraceIfRebinding(log, "Installation of library "+bundle+": "+result);
            }
            results.add(result);
        }
        Map<String, Throwable> errors = MutableMap.of();
        if (startBundlesAndInstallToBrooklyn) {
            for (OsgiBundleInstallationResult r: results) {
                if (r.getDeferredStart()!=null) {
                    try {
                        r.getDeferredStart().run();
                    } catch (Throwable t) {
                        Exceptions.propagateIfFatal(t);
                        // above will done rollback for the failed item, but we need consistent behaviour for all libraries;
                        // for simplicity we simply have each bundle either fully installed or fully rolled back
                        // (alternative would be to roll back everything)
                        errors.put(r.getVersionedName().toString(), t);
                    }
                }
            }
        }
        if (!errors.isEmpty()) {
            logDebugOrTraceIfRebinding(log, "Tried registering {} libraries, {} succeeded, but failed {} (throwing)", 
                new Object[] { libraries.size(), libraries.size() - errors.size(), errors.keySet() });
            if (errors.size()==1) {
                throw Exceptions.propagateAnnotated("Error starting referenced library in Brooklyn bundle "+Iterables.getOnlyElement(errors.keySet()), 
                    Iterables.getOnlyElement(errors.values()));
            } else {
                throw Exceptions.create("Error starting referenced libraries in Brooklyn bundles "+errors.keySet(), errors.values());                    
            }
        }
        if (log.isDebugEnabled()) { 
            logDebugOrTraceIfRebinding(log, 
                "Registered {} bundle{} in {}",
                new Object[]{libraries.size(), Strings.s(libraries.size()), Time.makeTimeStringRounded(timer)});
        }
    }
}
 
Example 18
Source File: BasicBrooklynTypeRegistry.java    From brooklyn-server with Apache License 2.0 4 votes vote down vote up
@SuppressWarnings({ "deprecation", "unchecked", "rawtypes" })
private <SpecT extends AbstractBrooklynObjectSpec<?,?>> SpecT createSpec(
        RegisteredType type,
        TypeImplementationPlan plan,
        @Nullable String symbolicName, @Nullable String version, Set<Object> superTypes,
        @Nullable RegisteredTypeLoadingContext constraint, @Nullable Class<SpecT> specSuperType) {
    // TODO type is only used to call to "transform"; we should perhaps change transform so it doesn't need the type?
    if (constraint!=null) {
        if (constraint.getExpectedKind()!=null && constraint.getExpectedKind()!=RegisteredTypeKind.SPEC) {
            throw new IllegalStateException("Cannot create spec with constraint "+constraint);
        }
        if (symbolicName != null && constraint.getAlreadyEncounteredTypes().contains(symbolicName)) {
            // avoid recursive cycle
            // TODO implement using java if permitted
        }
    }
    constraint = RegisteredTypeLoadingContexts.withSpecSuperType(constraint, specSuperType);

    Maybe<Object> result = TypePlanTransformers.transform(mgmt, type, constraint);
    if (result.isPresent()) return (SpecT) result.get();
    
    // fallback: look up in (legacy) catalog
    // TODO remove once all transformers are available in the new style
    CatalogItem item = symbolicName!=null ? (CatalogItem) mgmt.getCatalog().getCatalogItemLegacy(symbolicName, version) : null;
    if (item==null) {
        // if not in catalog (because loading a new item?) then look up item based on type
        // (only really used in tests; possibly also for any recursive legacy transformers we might have to create a CI; cross that bridge when we come to it)
        CatalogItemType ciType = CatalogItemType.ofTargetClass( (Class)constraint.getExpectedJavaSuperType() );
        if (ciType==null) {
            // throw -- not supported for non-spec types
            result.get();
        }
        item = CatalogItemBuilder.newItem(ciType, 
                symbolicName!=null ? symbolicName : Identifiers.makeRandomId(8), 
                version!=null ? version : BasicBrooklynCatalog.DEFAULT_VERSION)
            .plan((String)plan.getPlanData())
            .build();
    }
    try {
        SpecT resultLegacy = (SpecT) BasicBrooklynCatalog.internalCreateSpecLegacy(mgmt, item, constraint.getAlreadyEncounteredTypes(), false);
        log.warn("Item '"+item+"' was only parseable using legacy transformers; may not be supported in future versions: "+resultLegacy);
        return resultLegacy;
    } catch (Exception exceptionFromLegacy) {
        Exceptions.propagateIfFatal(exceptionFromLegacy);
        // for now, combine this failure with the original
        try {
            result.get();
            // above will throw -- so won't come here
            throw new IllegalStateException("should have failed getting type resolution for "+symbolicName);
        } catch (Exception exceptionFromPrimary) {
            // ignore the legacy error. means much nicer errors in the happy case.
            
            if (log.isTraceEnabled()) {
                log.trace("Unable to instantiate "+(symbolicName==null ? "item" : symbolicName)+", primary error", 
                    exceptionFromPrimary);
                log.trace("Unable to instantiate "+(symbolicName==null ? "item" : symbolicName)+", legacy error", 
                    exceptionFromLegacy);
            }

            Throwable exception = Exceptions.collapse(exceptionFromPrimary);
            throw symbolicName==null ? Exceptions.propagate(exception) : Exceptions.propagateAnnotated("Unable to instantiate "+symbolicName, exception);
        }
    }
}
 
Example 19
Source File: BrooklynComponentTemplateResolver.java    From brooklyn-server with Apache License 2.0 4 votes vote down vote up
@Override public EntitySpec<?> get() {
    // TODO: This should called from BrooklynAssemblyTemplateInstantiator.configureEntityConfig
    // And have transformSpecialFlags(Object flag, ManagementContext mgmt) drill into the Object flag if it's a map or iterable?
    @SuppressWarnings("unchecked")
    Map<String, Object> resolvedConfig = (Map<String, Object>)transformSpecialFlags(flag.getSpecConfiguration());
    EntitySpec<?> entitySpec;
    try {
        // first parse as a CAMP entity
        entitySpec = Factory.newInstance(getLoader(), resolvedConfig).resolveSpec(encounteredRegisteredTypeIds);
    } catch (Exception e1) {
        Exceptions.propagateIfFatal(e1);
        
        // if that doesn't work, try full multi-format plan parsing 
        String yamlPlan = null;
        try {
            yamlPlan = new Yaml().dump(resolvedConfig);
            entitySpec = mgmt.getTypeRegistry().createSpecFromPlan(null, yamlPlan, 
                RegisteredTypeLoadingContexts.alreadyEncountered(encounteredRegisteredTypeIds), EntitySpec.class);
        } catch (Exception e2) {
            String errorMessage = "entitySpec plan parse error";
            if (Thread.currentThread().isInterrupted()) {
                // plans which read/write to a file might not work in interrupted state
                if (cached!=null) {
                    log.debug("EntitySpecSupplier returning cached spec "+cached+" because being invoked in a context which must return immediately");
                    return cached;
                } else {
                    errorMessage += " (note, it is being invoked in a context which must return immediately and there is no cache)";
                }
            }
            Exceptions.propagateIfFatal(e2);
            
            Exception exceptionToInclude;
            // heuristic
            if (resolvedConfig.containsKey("type")) {
                // if it has a key 'type' then it is likely a CAMP entity, abbreviated syntax (giving a type), so just give e1
                exceptionToInclude = e1;
            } else if (resolvedConfig.containsKey("brooklyn.services")) {
                // seems like a CAMP app, just give e2
                exceptionToInclude = e2;
            } else {
                // can't tell if it was short form eg `entitySpec: { type: x, ... }`
                // or long form (camp or something else), eg `entitySpec: { brooklyn.services: [ ... ] }`.
                // the error from the latter is a bit nicer so return it, but log the former.
                errorMessage += "; consult log for more information";
                log.debug("Suppressed error in entity spec where unclear whether abbreviated or full syntax, is (from abbreviated form parse, where error parsing full form will be reported subsequently): "+e1);
                exceptionToInclude = e2;
                // don't use the list as that causes unhelpful "2 errors including"...
            }
            // first exception might include the plan, so we don't need to here
            boolean yamlPlanAlreadyIncluded = exceptionToInclude.toString().contains(yamlPlan);
            if (!yamlPlanAlreadyIncluded) {
                errorMessage += ":\n"+yamlPlan;
            }
            throw Exceptions.propagateAnnotated(errorMessage, exceptionToInclude);
        }
    }
    cached = EntityManagementUtils.unwrapEntity(entitySpec);
    return cached;
}