Пример #1
1
  /** Fetch the classloader for the given ApplicationID. */
  static URLClassLoader getUrlClassLoader(ApplicationID appId, Map input) {
    NCube cpCube = getCube(appId, CLASSPATH_CUBE);
    if (cpCube
        == null) { // No sys.classpath cube exists, just create regular GroovyClassLoader with no
                   // URLs set into it.
      // Scope the GroovyClassLoader per ApplicationID
      return getLocalClassloader(appId);
    }

    final String envLevel = SystemUtilities.getExternalVariable("ENV_LEVEL");
    if (!input.containsKey("env")
        && StringUtilities.hasContent(
            envLevel)) { // Add in the 'ENV_LEVEL" environment variable when looking up sys.* cubes,
      // if there was not already an entry for it.
      input.put("env", envLevel);
    }
    if (!input.containsKey("username")) { // same as ENV_LEVEL, add it in if not already there.
      input.put("username", System.getProperty("user.name"));
    }
    Object urlCpLoader = cpCube.getCell(input);

    if (urlCpLoader instanceof URLClassLoader) {
      return (URLClassLoader) urlCpLoader;
    }

    throw new IllegalStateException(
        "If the sys.classpath cube exists it must return a URLClassLoader.");
  }
Пример #2
0
  /** Associate Advice to all n-cubes that match the passed in regular expression. */
  public static void addAdvice(ApplicationID appId, String wildcard, Advice advice) {
    validateAppId(appId);
    ConcurrentMap<String, Advice> current = advices.get(appId);
    if (current == null) {
      current = new ConcurrentHashMap<>();
      ConcurrentMap<String, Advice> mapRef = advices.putIfAbsent(appId, current);
      if (mapRef != null) {
        current = mapRef;
      }
    }

    current.put(advice.getName() + '/' + wildcard, advice);

    // Apply newly added advice to any fully loaded (hydrated) cubes.
    String regex = StringUtilities.wildcardToRegexString(wildcard);
    Map<String, Object> cubes = getCacheForApp(appId);

    for (Object value : cubes.values()) {
      if (value instanceof NCube) { // apply advice to hydrated cubes
        NCube ncube = (NCube) value;
        Axis axis = ncube.getAxis("method");
        addAdviceToMatchedCube(advice, regex, ncube, axis);
      }
    }
  }
Пример #3
0
  public static List<NCube> getNCubesFromResource(String name) {
    String lastSuccessful = "";
    try {
      Object[] cubes = getJsonObjectFromResource(name);
      List<NCube> cubeList = new ArrayList<>(cubes.length);

      for (Object cube : cubes) {
        JsonObject ncube = (JsonObject) cube;
        String json = JsonWriter.objectToJson(ncube);
        NCube nCube = NCube.fromSimpleJson(json);
        nCube.sha1();
        addCube(nCube.getApplicationID(), nCube);
        lastSuccessful = nCube.getName();
        cubeList.add(nCube);
      }

      return cubeList;
    } catch (Exception e) {
      String s =
          "Failed to load cubes from resource: "
              + name
              + ", last successful cube: "
              + lastSuccessful;
      LOG.warn(s);
      throw new RuntimeException(s, e);
    }
  }
Пример #4
0
  /** Retrieve all cube names that are deeply referenced by ApplicationID + n-cube name. */
  public static void getReferencedCubeNames(ApplicationID appId, String name, Set<String> refs) {
    if (refs == null) {
      throw new IllegalArgumentException(
          "Could not get referenced cube names, null passed in for Set to hold referenced n-cube names, app: "
              + appId
              + ", n-cube: "
              + name);
    }
    validateAppId(appId);
    NCube.validateCubeName(name);
    NCube ncube = getCube(appId, name);
    if (ncube == null) {
      throw new IllegalArgumentException(
          "Could not get referenced cube names, n-cube: "
              + name
              + " does not exist in app: "
              + appId);
    }
    Set<String> subCubeList = ncube.getReferencedCubeNames();

    // TODO: Use explicit stack, NOT recursion

    for (String cubeName : subCubeList) {
      if (!refs.contains(cubeName)) {
        refs.add(cubeName);
        getReferencedCubeNames(appId, cubeName, refs);
      }
    }
  }
Пример #5
0
  private static void cacheCubes(ApplicationID appId, List<NCubeInfoDto> cubes) {
    Map<String, Object> appCache = getCacheForApp(appId);

    for (NCubeInfoDto cubeInfo : cubes) {
      String key = cubeInfo.name.toLowerCase();

      if (!cubeInfo.revision.startsWith("-")) {
        Object cachedItem = appCache.get(key);
        if (cachedItem == null
            || cachedItem
                instanceof
                NCubeInfoDto) { // If cube not in cache or already in cache as infoDto, overwrite it
          appCache.put(key, cubeInfo);
        } else if (cachedItem
            instanceof
            NCube) { // If cube is already cached, make sure the SHA1's match - if not, then cache
                     // the new cubeInfo
          NCube ncube = (NCube) cachedItem;
          if (!ncube.sha1().equals(cubeInfo.sha1)) {
            appCache.put(key, cubeInfo);
          }
        }
      }
    }
  }
Пример #6
0
  /**
   * Update the passed in NCube. Only SNAPSHOT cubes can be updated.
   *
   * @param ncube NCube to be updated.
   * @return boolean true on success, false otherwise
   */
  public static boolean updateCube(ApplicationID appId, NCube ncube, String username) {
    validateAppId(appId);
    validateCube(ncube);

    if (appId.isRelease()) {
      throw new IllegalArgumentException(
          ReleaseStatus.RELEASE
              + " cubes cannot be updated, cube: "
              + ncube.getName()
              + ", app: "
              + appId);
    }

    appId.validateBranchIsNotHead();

    final String cubeName = ncube.getName();
    getPersister().updateCube(appId, ncube, username);
    ncube.setApplicationID(appId);

    if (CLASSPATH_CUBE.equalsIgnoreCase(
        cubeName)) { // If the sys.classpath cube is changed, then the entire class loader must be
                     // dropped.  It will be lazily rebuilt.
      clearCache(appId);
    }

    addCube(appId, ncube);
    broadcast(appId);
    return true;
  }
Пример #7
0
 /**
  * Load n-cube, bypassing any caching. This is necessary for n-cube-editor (IDE time usage). If
  * the IDE environment is clustered, cannot be getting stale copies from cache. Any advices in the
  * manager will be applied to the n-cube.
  *
  * @return NCube of the specified name from the specified AppID, or null if not found.
  */
 public static NCube loadCube(ApplicationID appId, String cubeName) {
   NCube ncube = getPersister().loadCube(appId, cubeName);
   if (ncube == null) {
     return null;
   }
   applyAdvices(ncube.getApplicationID(), ncube);
   Map<String, Object> cubes = getCacheForApp(appId);
   cubes.put(cubeName.toLowerCase(), ncube); // Update cache
   return ncube;
 }
Пример #8
0
 private static NCube prepareCube(NCube cube) {
   applyAdvices(cube.getApplicationID(), cube);
   String cubeName = cube.getName().toLowerCase();
   if (!cube.getMetaProperties().containsKey("cache")
       || Boolean.TRUE.equals(
           cube.getMetaProperty(
               "cache"))) { // Allow cubes to not be cached by specified 'cache':false as a cube
                            // meta-property.
     getCacheForApp(cube.getApplicationID()).put(cubeName, cube);
   }
   return cube;
 }
Пример #9
0
  public static ApplicationID getApplicationID(
      String tenant, String app, Map<String, Object> coord) {
    ApplicationID.validateTenant(tenant);
    ApplicationID.validateApp(tenant);

    if (coord == null) {
      coord = new HashMap<>();
    }

    NCube bootCube = getCube(ApplicationID.getBootVersion(tenant, app), SYS_BOOTSTRAP);

    if (bootCube == null) {
      throw new IllegalStateException(
          "Missing " + SYS_BOOTSTRAP + " cube in the 0.0.0 version for the app: " + app);
    }

    ApplicationID bootAppId = (ApplicationID) bootCube.getCell(coord);
    String version = bootAppId.getVersion();
    String status = bootAppId.getStatus();
    String branch = bootAppId.getBranch();

    if (!tenant.equalsIgnoreCase(bootAppId.getTenant())) {
      LOG.warn(
          "sys.bootstrap cube for tenant '"
              + tenant
              + "', app '"
              + app
              + "' is returning a different tenant '"
              + bootAppId.getTenant()
              + "' than requested. Using '"
              + tenant
              + "' instead.");
    }

    if (!app.equalsIgnoreCase(bootAppId.getApp())) {
      LOG.warn(
          "sys.bootstrap cube for tenant '"
              + tenant
              + "', app '"
              + app
              + "' is returning a different app '"
              + bootAppId.getApp()
              + "' than requested. Using '"
              + app
              + "' instead.");
    }

    return new ApplicationID(tenant, app, version, status, branch);
  }
Пример #10
0
 public static NCube getNCubeFromResource(ApplicationID id, String name) {
   try {
     String json = getResourceAsString(name);
     NCube ncube = NCube.fromSimpleJson(json);
     ncube.setApplicationID(id);
     ncube.sha1();
     addCube(id, ncube);
     return ncube;
   } catch (Exception e) {
     if (e instanceof RuntimeException) {
       throw (RuntimeException) e;
     }
     throw new RuntimeException("Failed to load cube from resource: " + name, e);
   }
 }
Пример #11
0
 private static void addAdviceToMatchedCube(Advice advice, String regex, NCube ncube, Axis axis) {
   if (axis != null) { // Controller methods
     for (Column column : axis.getColumnsWithoutDefault()) {
       String method = column.getValue().toString();
       String classMethod = ncube.getName() + '.' + method + "()";
       if (classMethod.matches(regex)) {
         ncube.addAdvice(advice, method);
       }
     }
   } else { // Expressions
     String classMethod = ncube.getName() + ".run()";
     if (classMethod.matches(regex)) {
       ncube.addAdvice(advice, "run");
     }
   }
 }
Пример #12
0
  /** Restore a previously deleted n-cube. */
  public static void restoreCubes(ApplicationID appId, Object[] cubeNames, String username) {
    validateAppId(appId);
    appId.validateBranchIsNotHead();

    if (appId.isRelease()) {
      throw new IllegalArgumentException(
          ReleaseStatus.RELEASE + " cubes cannot be restored, app: " + appId);
    }

    if (ArrayUtilities.isEmpty(cubeNames)) {
      throw new IllegalArgumentException(
          "Error, empty array of cube names passed in to be restored.");
    }

    // Batch restore
    getPersister().restoreCubes(appId, cubeNames, username);

    // Load cache
    for (Object name : cubeNames) {
      if ((name instanceof String)) {
        String cubeName = (String) name;
        NCube.validateCubeName(cubeName);
        NCube ncube = getPersister().loadCube(appId, cubeName);
        addCube(appId, ncube);
      } else {
        throw new IllegalArgumentException("Non string name given for cube to restore: " + name);
      }
    }
  }
Пример #13
0
 /** Testing API (Cache validation) */
 static boolean isCubeCached(ApplicationID appId, String cubeName) {
   validateAppId(appId);
   NCube.validateCubeName(cubeName);
   Map<String, Object> ncubes = getCacheForApp(appId);
   Object cachedItem = ncubes.get(cubeName.toLowerCase());
   return cachedItem instanceof NCube || cachedItem instanceof NCubeInfoDto;
 }
Пример #14
0
  private static NCube checkForConflicts(
      ApplicationID appId,
      Map<String, Map> errors,
      String message,
      NCubeInfoDto info,
      NCubeInfoDto head,
      boolean reverse) {
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("message", message);
    map.put("sha1", info.sha1);
    map.put("headSha1", head != null ? head.sha1 : null);

    try {
      if (head != null) {
        long branchCubeId = (long) Converter.convert(info.id, long.class);
        long headCubeId = (long) Converter.convert(head.id, long.class);
        NCube branchCube = getPersister().loadCubeById(branchCubeId);
        NCube headCube = getPersister().loadCubeById(headCubeId);

        if (info.headSha1 != null) {
          NCube baseCube = getPersister().loadCubeBySha1(appId, info.name, info.headSha1);

          Map delta1 = baseCube.getDelta(branchCube);
          Map delta2 = baseCube.getDelta(headCube);

          if (NCube.areDeltaSetsCompatible(delta1, delta2)) {
            if (reverse) {
              headCube.mergeCellChangeSet(delta1);
              return headCube;
            } else {
              branchCube.mergeCellChangeSet(delta2);
              return branchCube;
            }
          }
        }

        List<Delta> diff = branchCube.getDeltaDescription(headCube);
        if (diff.size() > 0) {
          map.put("diff", diff);
        } else {
          return branchCube;
        }
      } else {
        map.put("diff", null);
      }
    } catch (Exception e) {
      map.put("diff", e.getMessage());
    }
    errors.put(info.name, map);
    return null;
  }
Пример #15
0
  /**
   * Add a cube to the internal cache of available cubes.
   *
   * @param ncube NCube to add to the list.
   */
  public static void addCube(ApplicationID appId, NCube ncube) {
    validateAppId(appId);
    validateCube(ncube);

    String cubeName = ncube.getName().toLowerCase();

    if (!ncube.getMetaProperties().containsKey("cache")
        || Boolean.TRUE.equals(
            ncube.getMetaProperty(
                "cache"))) { // Allow cubes to not be cached by specified 'cache':false as a cube
                             // meta-property.
      getCacheForApp(appId).put(cubeName, ncube);
    }

    // Apply any matching advices to it
    applyAdvices(appId, ncube);
  }
Пример #16
0
  /** Duplicate the given n-cube specified by oldAppId and oldName to new ApplicationID and name, */
  public static void duplicate(
      ApplicationID oldAppId,
      ApplicationID newAppId,
      String oldName,
      String newName,
      String username) {
    validateAppId(oldAppId);
    validateAppId(newAppId);

    newAppId.validateBranchIsNotHead();

    if (newAppId.isRelease()) {
      throw new IllegalArgumentException(
          "Cubes cannot be duplicated into a "
              + ReleaseStatus.RELEASE
              + " version, cube: "
              + newName
              + ", app: "
              + newAppId);
    }

    NCube.validateCubeName(oldName);
    NCube.validateCubeName(newName);

    if (oldName.equalsIgnoreCase(newName) && oldAppId.equals(newAppId)) {
      throw new IllegalArgumentException(
          "Could not duplicate, old name cannot be the same as the new name when oldAppId matches newAppId, name: "
              + oldName
              + ", app: "
              + oldAppId);
    }

    getPersister().duplicateCube(oldAppId, newAppId, oldName, newName, username);

    if (CLASSPATH_CUBE.equalsIgnoreCase(
        newName)) { // If another cube is renamed into sys.classpath,
      // then the entire class loader must be dropped (and then lazily rebuilt).
      clearCache(newAppId);
    } else {
      Map<String, Object> appCache = getCacheForApp(newAppId);
      appCache.remove(newName.toLowerCase());
    }

    broadcast(newAppId);
  }
Пример #17
0
  public static boolean renameCube(
      ApplicationID appId, String oldName, String newName, String username) {
    validateAppId(appId);
    appId.validateBranchIsNotHead();

    if (appId.isRelease()) {
      throw new IllegalArgumentException(
          "Cannot rename a "
              + ReleaseStatus.RELEASE
              + " cube, cube: "
              + oldName
              + ", app: "
              + appId);
    }

    NCube.validateCubeName(oldName);
    NCube.validateCubeName(newName);

    if (oldName.equalsIgnoreCase(newName)) {
      throw new IllegalArgumentException(
          "Could not rename, old name cannot be the same as the new name, name: "
              + oldName
              + ", app: "
              + appId);
    }

    boolean result = getPersister().renameCube(appId, oldName, newName, username);

    if (CLASSPATH_CUBE.equalsIgnoreCase(oldName)
        || CLASSPATH_CUBE.equalsIgnoreCase(
            newName)) { // If the sys.classpath cube is renamed, or another cube is renamed into
                        // sys.classpath,
      // then the entire class loader must be dropped (and then lazily rebuilt).
      clearCache(appId);
    } else {
      Map<String, Object> appCache = getCacheForApp(appId);
      appCache.remove(oldName.toLowerCase());
      appCache.remove(newName.toLowerCase());
    }

    broadcast(appId);
    return result;
  }
Пример #18
0
  /**
   * Fetch all the n-cube names for the given ApplicationID. This API will load all cube records for
   * the ApplicationID (NCubeInfoDtos), and then get the names from them.
   *
   * @return Set<String> n-cube names. If an empty Set is returned, then there are no persisted
   *     n-cubes for the passed in ApplicationID.
   */
  public static Set<String> getCubeNames(ApplicationID appId) {
    Map<String, Object> options = new HashMap<>();
    options.put(SEARCH_ACTIVE_RECORDS_ONLY, true);
    List<NCubeInfoDto> cubeInfos = search(appId, null, null, options);
    Set<String> names = new TreeSet<>();

    for (NCubeInfoDto info : cubeInfos) {
      names.add(info.name);
    }

    if (names.isEmpty()) { // Support tests that load cubes from JSON files...
      // can only be in there as ncubes, not ncubeDtoInfo
      for (Object value : getCacheForApp(appId).values()) {
        if (value instanceof NCube) {
          NCube cube = (NCube) value;
          names.add(cube.getName());
        }
      }
    }
    return new CaseInsensitiveSet<>(names);
  }
Пример #19
0
  public static String getNotes(ApplicationID appId, String cubeName) {
    validateAppId(appId);
    NCube.validateCubeName(cubeName);
    Map<String, Object> options = new HashMap<>();
    options.put(SEARCH_INCLUDE_NOTES, true);
    options.put(SEARCH_EXACT_MATCH_NAME, true);

    List<NCubeInfoDto> infos = search(appId, cubeName, null, options);
    if (infos.size() == 0) {
      throw new IllegalArgumentException(
          "Could not fetch notes, no cube: " + cubeName + " in app: " + appId);
    }
    return infos.get(0).notes;
  }
Пример #20
0
  /**
   * Apply existing advices loaded into the NCubeManager, to the passed in n-cube. This allows
   * advices to be added first, and then let them be applied 'on demand' as an n-cube is loaded
   * later.
   *
   * @param appId ApplicationID
   * @param ncube NCube to which all matching advices will be applied.
   */
  private static void applyAdvices(ApplicationID appId, NCube ncube) {
    final Map<String, Advice> appAdvices = advices.get(appId);

    if (MapUtilities.isEmpty(appAdvices)) {
      return;
    }
    for (Map.Entry<String, Advice> entry : appAdvices.entrySet()) {
      final Advice advice = entry.getValue();
      final String wildcard = entry.getKey().replace(advice.getName() + '/', "");
      final String regex = StringUtilities.wildcardToRegexString(wildcard);
      final Axis axis = ncube.getAxis("method");
      addAdviceToMatchedCube(advice, regex, ncube, axis);
    }
  }
Пример #21
0
  /**
   * Fetch an n-cube by name from the given ApplicationID. If no n-cubes are loaded, then a
   * loadCubes() call is performed and then the internal cache is checked again. If the cube is not
   * found, null is returned.
   */
  public static NCube getCube(ApplicationID appId, String name) {
    validateAppId(appId);
    NCube.validateCubeName(name);
    Map<String, Object> cubes = getCacheForApp(appId);
    final String lowerCubeName = name.toLowerCase();

    if (cubes.containsKey(lowerCubeName)) { // pull from cache
      final Object cube = cubes.get(lowerCubeName);
      return Boolean.FALSE == cube ? null : ensureLoaded(cube);
    }

    // now even items with metaProperties(cache = 'false') can be retrieved
    // and normal app processing doesn't do two queries anymore.
    // used to do getCubeInfoRecords() -> dto
    // and then dto -> loadCube(id)
    NCube ncube = getPersister().loadCube(appId, name);
    if (ncube == null) {
      cubes.put(lowerCubeName, Boolean.FALSE);
      return null;
    }
    return prepareCube(ncube);
  }
Пример #22
0
 public static String getTestData(ApplicationID appId, String cubeName) {
   validateAppId(appId);
   NCube.validateCubeName(cubeName);
   return getPersister().getTestData(appId, cubeName);
 }
Пример #23
0
 /** Get a List<NCubeInfoDto> containing all history for the given cube. */
 public static List<NCubeInfoDto> getRevisionHistory(ApplicationID appId, String cubeName) {
   validateAppId(appId);
   NCube.validateCubeName(cubeName);
   List<NCubeInfoDto> revisions = getPersister().getRevisions(appId, cubeName);
   return revisions;
 }
Пример #24
0
 public static boolean updateNotes(ApplicationID appId, String cubeName, String notes) {
   validateAppId(appId);
   NCube.validateCubeName(cubeName);
   return getPersister().updateNotes(appId, cubeName, notes);
 }
Пример #25
0
 static void validateCube(NCube cube) {
   if (cube == null) {
     throw new IllegalArgumentException("NCube cannot be null");
   }
   NCube.validateCubeName(cube.getName());
 }
Пример #26
0
 public static boolean updateTestData(ApplicationID appId, String cubeName, String testData) {
   validateAppId(appId);
   NCube.validateCubeName(cubeName);
   return getPersister().updateTestData(appId, cubeName, testData);
 }