@Override
  protected synchronized void setApplication(Application app) {
    if (app.getId().equals(getId())) {
      application = getProxy() != null ? (Application) getProxy() : app;
    } else {
      application = app;

      // Alex, Mar 2013: added some checks;
      // i *think* these conditions should not happen,
      // and so should throw but don't want to break things (yet)
      if (getParent() == null) {
        log.warn(
            "Setting application of " + this + " to " + app + ", but " + this + " is not parented");
      } else if (getParent().getApplicationId().equals(app.getParent())) {
        log.warn(
            "Setting application of "
                + this
                + " to "
                + app
                + ", but parent "
                + getParent()
                + " has different app "
                + getParent().getApplication());
      }
    }
    super.setApplication(app);
  }
  /** Walks the contents of a ManagementContext, to create a corresponding memento. */
  public static BrooklynMemento newBrooklynMemento(ManagementContext managementContext) {
    BrooklynMementoImpl.Builder builder = BrooklynMementoImpl.builder();

    for (Application app : managementContext.getApplications()) {
      builder.applicationIds.add(app.getId());
    }
    for (Entity entity : managementContext.getEntityManager().getEntities()) {
      builder.entities.put(
          entity.getId(), ((EntityInternal) entity).getRebindSupport().getMemento());

      for (Location location : entity.getLocations()) {
        if (!builder.locations.containsKey(location.getId())) {
          for (Location locationInHierarchy : TreeUtils.findLocationsInHierarchy(location)) {
            if (!builder.locations.containsKey(locationInHierarchy.getId())) {
              builder.locations.put(
                  locationInHierarchy.getId(),
                  ((LocationInternal) locationInHierarchy).getRebindSupport().getMemento());
            }
          }
        }
      }
    }
    for (LocationMemento memento : builder.locations.values()) {
      if (memento.getParent() == null) {
        builder.topLevelLocationIds.add(memento.getId());
      }
    }

    BrooklynMemento result = builder.build();
    MementoValidators.validateMemento(result);
    return result;
  }
  /**
   * finds the entity indicated by the given ID or name
   *
   * <p>prefers ID based lookup in which case appId is optional, and if supplied will be enforced.
   * optionally the name can be supplied, for cases when paths should work across versions, in which
   * case names will be searched recursively (and the application is required).
   *
   * @throws 404 or 412 (unless input is null in which case output is null)
   */
  public EntityLocal getEntity(String application, String entity) {
    if (entity == null) return null;
    Application app = application != null ? getApplication(application) : null;
    EntityLocal e = (EntityLocal) mgmt.getEntityManager().getEntity(entity);

    if (e != null) {
      if (!Entitlements.isEntitled(mgmt.getEntitlementManager(), Entitlements.SEE_ENTITY, e)) {
        throw WebResourceUtils.notFound(
            "Cannot find entity '%s': no known ID and application not supplied for searching",
            entity);
      }

      if (app == null || app.equals(findTopLevelApplication(e))) return e;
      throw WebResourceUtils.preconditionFailed(
          "Application '%s' specified does not match application '%s' to which entity '%s' (%s) is associated",
          application, e.getApplication().getId(), entity, e);
    }
    if (application == null)
      throw WebResourceUtils.notFound(
          "Cannot find entity '%s': no known ID and application not supplied for searching",
          entity);

    assert app != null : "null app should not be returned from getApplication";
    e = searchForEntityNamed(app, entity);
    if (e != null) return e;
    throw WebResourceUtils.notFound(
        "Cannot find entity '%s' in application '%s' (%s)", entity, application, app);
  }
  /**
   * looks for the given application instance, first by ID then by name
   *
   * @throws 404 if not found, or not entitled
   */
  public Application getApplication(String application) {
    Entity e = mgmt.getEntityManager().getEntity(application);
    if (!Entitlements.isEntitled(mgmt.getEntitlementManager(), Entitlements.SEE_ENTITY, e)) {
      throw notFound("Application '%s' not found", application);
    }

    if (e != null && e instanceof Application) return (Application) e;
    for (Application app : mgmt.getApplications()) {
      if (app.getId().equals(application)) return app;
      if (application.equalsIgnoreCase(app.getDisplayName())) return app;
    }

    throw notFound("Application '%s' not found", application);
  }
  private Application findTopLevelApplication(Entity e) {
    // For nested apps, e.getApplication() can return its direct parent-app rather than the root app
    // (particularly if e.getApplication() was called before the parent-app was wired up to its
    // parent,
    // because that call causes the application to be cached).
    // Therefore we continue to walk the hierarchy until we find an "orphaned" application at the
    // top.

    Application app = e.getApplication();
    while (app != null && !app.equals(app.getApplication())) {
      app = app.getApplication();
    }
    return app;
  }
 @Override
 public Application getApplication() {
   if (application != null) {
     if (application.getId().equals(getId())) return (Application) getProxyIfAvailable();
     return application;
   }
   if (getParent() == null) return (Application) getProxyIfAvailable();
   return getParent().getApplication();
 }
 public Task<?> destroy(final Application application) {
   return mgmt.getExecutionManager()
       .submit(
           MutableMap.of(
               "displayName",
               "destroying " + application,
               "description",
               "REST call to destroy application "
                   + application.getDisplayName()
                   + " ("
                   + application
                   + ")"),
           new Runnable() {
             @Override
             public void run() {
               ((EntityInternal) application).destroy();
               mgmt.getEntityManager().unmanage(application);
             }
           });
 }
  @SuppressWarnings("unchecked")
  public Application create(ApplicationSpec spec) {
    log.debug("REST creating application instance for {}", spec);

    if (!Entitlements.isEntitled(
        mgmt.getEntitlementManager(), Entitlements.DEPLOY_APPLICATION, spec)) {
      throw WebResourceUtils.unauthorized(
          "User '%s' is not authorized to deploy application %s",
          Entitlements.getEntitlementContext().user(), spec);
    }

    final String type = spec.getType();
    final String name = spec.getName();
    final Map<String, String> configO = spec.getConfig();
    final Set<EntitySpec> entities =
        (spec.getEntities() == null) ? ImmutableSet.<EntitySpec>of() : spec.getEntities();

    final Application instance;

    // Load the class; first try to use the appropriate catalog item; but then allow anything that
    // is on the classpath
    final Class<? extends Entity> clazz;
    if (Strings.isEmpty(type)) {
      clazz = BasicApplication.class;
    } else {
      Class<? extends Entity> tempclazz;
      try {
        tempclazz = getCatalog().loadClassByType(type, Entity.class);
      } catch (NoSuchElementException e) {
        try {
          tempclazz = (Class<? extends Entity>) getCatalog().getRootClassLoader().loadClass(type);
          log.info(
              "Catalog does not contain item for type {}; loaded class directly instead", type);
        } catch (ClassNotFoundException e2) {
          log.warn(
              "No catalog item for type {}, and could not load class directly; rethrowing", type);
          throw e;
        }
      }
      clazz = tempclazz;
    }
    if (Entitlements.isEntitled(mgmt.getEntitlementManager(), Entitlements.INVOKE_EFFECTOR, null)) {

      try {
        if (ApplicationBuilder.class.isAssignableFrom(clazz)) {
          Constructor<?> constructor = clazz.getConstructor();
          ApplicationBuilder appBuilder = (ApplicationBuilder) constructor.newInstance();
          if (!Strings.isEmpty(name)) appBuilder.appDisplayName(name);
          if (entities.size() > 0)
            log.warn(
                "Cannot supply additional entities when using an ApplicationBuilder; ignoring in spec {}",
                spec);

          log.info("REST placing '{}' under management", spec.getName());
          appBuilder.configure(convertFlagsToKeys(appBuilder.getType(), configO));
          configureRenderingMetadata(spec, appBuilder);
          instance = appBuilder.manage(mgmt);

        } else if (Application.class.isAssignableFrom(clazz)) {
          brooklyn.entity.proxying.EntitySpec<?> coreSpec = toCoreEntitySpec(clazz, name, configO);
          configureRenderingMetadata(spec, coreSpec);
          instance = (Application) mgmt.getEntityManager().createEntity(coreSpec);
          for (EntitySpec entitySpec : entities) {
            log.info("REST creating instance for entity {}", entitySpec.getType());
            instance.addChild(mgmt.getEntityManager().createEntity(toCoreEntitySpec(entitySpec)));
          }

          log.info(
              "REST placing '{}' under management", spec.getName() != null ? spec.getName() : spec);
          Entities.startManagement(instance, mgmt);

        } else if (Entity.class.isAssignableFrom(clazz)) {
          if (entities.size() > 0)
            log.warn(
                "Cannot supply additional entities when using a non-application entity; ignoring in spec {}",
                spec);

          brooklyn.entity.proxying.EntitySpec<?> coreSpec =
              toCoreEntitySpec(BasicApplication.class, name, configO);
          configureRenderingMetadata(spec, coreSpec);

          instance = (Application) mgmt.getEntityManager().createEntity(coreSpec);

          final Class<? extends Entity> eclazz =
              getCatalog().loadClassByType(spec.getType(), Entity.class);
          Entity soleChild =
              mgmt.getEntityManager().createEntity(toCoreEntitySpec(eclazz, name, configO));
          instance.addChild(soleChild);
          instance.addEnricher(Enrichers.builder().propagatingAll().from(soleChild).build());

          log.info("REST placing '{}' under management", spec.getName());
          Entities.startManagement(instance, mgmt);

        } else {
          throw new IllegalArgumentException(
              "Class " + clazz + " must extend one of ApplicationBuilder, Application or Entity");
        }

        return instance;

      } catch (Exception e) {
        log.error("REST failed to create application: " + e, e);
        throw Exceptions.propagate(e);
      }
    }
    throw WebResourceUtils.unauthorized(
        "User '%s' is not authorized to create application from applicationSpec %s",
        Entitlements.getEntitlementContext().user(), spec);
  }