public void storeMeemDefinition(MeemPath meemPath, MeemDefinition meemDefinition) {
    if (DEBUG) {
      logger.info("storing meem def: " + meemPath);
    }

    // only store meemstore paths
    if (meemPath.getSpace().equals(Space.MEEMSTORE)) {
      int meemVersion = meemDefinition.getMeemAttribute().getVersion();
      if (meemVersion > definitionStore.getVersion(meemPath)) {
        definitionStore.store(meemPath, meemDefinition);

        synchronized (meemPaths) {
          if (!meemPaths.containsKey(meemPath.getLocation())) {
            meemPaths.put(meemPath.getLocation(), meemPath);
            meemStoreClient.meemStored(meemPath);
          }
          meemDefinitionClient.meemDefinitionChanged(meemPath, meemDefinition);
          meemContentClient.meemContentChanged(meemPath, null);
        }
      } else {
        // definition version number is same or smaller than the persisted one
        // LogTools.warn(logger, "Request to persist MeemDefinition with lower version number than
        // most recent version");
      }
    }
  }
  public void storeMeemContent(MeemPath meemPath, MeemContent meemContent) {
    if (DEBUG) {
      logger.info("storing meem content: " + meemPath);
    }

    // only store meemstore paths
    if (meemPath.getSpace().equals(Space.MEEMSTORE)) {
      contentStore.store(meemPath, meemContent);

      String location = meemPath.getLocation();
      boolean stored = false;

      synchronized (meemPaths) {
        if (!meemPaths.containsKey(location)) {
          meemPaths.put(location, meemPath);
          stored = true;
        }

        if (stored) {
          meemStoreClient.meemStored(meemPath);
        }

        // TODO[peter] Should this be called if the meem was just stored?
        meemContentClient.meemContentChanged(meemPath, meemContent);
      }
    }
  }
  /**
   * @see org.openmaji.meem.filter.FilterChecker#invokeMethodCheck(org.openmaji.meem.filter.Filter,
   *     java.lang.String, java.lang.Object[])
   */
  public boolean invokeMethodCheck(Filter filter, String methodName, Object[] args)
      throws IllegalFilterException {
    if (!(filter instanceof ExactMatchFilter)) {
      throw new IllegalFilterException("Can't check filter: " + filter);
    }

    if (methodName.equals("meemDefinitionChanged")
        || methodName.equals("meemContentChanged")
        || methodName.equals("meemDestroyed")) {

      MeemPath meemPath = (MeemPath) args[0];
      if (meemPath != null) {
        ExactMatchFilter exactMatchFilter = (ExactMatchFilter) filter;
        return meemPath.equals(exactMatchFilter.getTemplate());
      }
    }

    return false;
  }
  public void commence() {
    Properties properties = System.getProperties();

    // TODO put this in a commence() method, and close stores on conclude().
    startStores(properties);

    // grab the content and definition paths
    // it is possible to have a content stored without a definition and vice versa

    // -mg- not sure this is really necessary. should just hand off to store to try and
    // load and fail silently if path cannot be found
    HashSet<MeemPath> paths = new HashSet<MeemPath>();
    paths.addAll(contentStore.getAllPaths());
    paths.addAll(definitionStore.getAllPaths());

    for (MeemPath meemPath : paths) {
      meemPaths.put(meemPath.getLocation(), meemPath);
    }
  }
  public void destroyMeem(MeemPath meemPath) {

    String location = meemPath.getLocation();
    MeemPath removePath;

    synchronized (meemPaths) {
      removePath = (MeemPath) meemPaths.remove(location);

      if (removePath != null) {

        contentStore.remove(meemPath);
        definitionStore.remove(meemPath);

        meemStoreClient.meemDestroyed(meemPath);
        meemDefinitionClient.meemDefinitionChanged(meemPath, null);
        meemContentClient.meemContentChanged(meemPath, null);
      }
    }
  }