/**
   * Convenience method to retrieve field values from an L2 cached object if they are loaded in that
   * object. If the object is not in the L2 cache then just returns, and similarly if the required
   * fields aren't available.
   *
   * @param fieldNumbers Numbers of fields to load from the L2 cache
   * @return The fields that couldn't be loaded
   */
  protected int[] loadFieldsFromLevel2Cache(int[] fieldNumbers) {
    // Only continue if there are fields, and not being deleted/flushed etc
    if (fieldNumbers == null
        || fieldNumbers.length == 0
        || myEC.isFlushing()
        || myLC.isDeleted()
        || isDeleting()
        || getExecutionContext().getTransaction().isCommitting()) {
      return fieldNumbers;
    }
    // TODO Drop this check when we're confident that this doesn't affect some use-cases
    if (!myEC.getNucleusContext()
        .getConfiguration()
        .getBooleanProperty(PropertyNames.PROPERTY_CACHE_L2_LOADFIELDS, true)) {
      return fieldNumbers;
    }

    Level2Cache l2cache = myEC.getNucleusContext().getLevel2Cache();
    if (l2cache != null && myEC.getNucleusContext().isClassCacheable(cmd)) {
      CachedPC<T> cachedPC = l2cache.get(myID);
      if (cachedPC != null) {
        int[] cacheFieldsToLoad =
            ClassUtils.getFlagsSetTo(cachedPC.getLoadedFields(), fieldNumbers, true);
        if (cacheFieldsToLoad != null && cacheFieldsToLoad.length > 0) {
          if (NucleusLogger.CACHE.isDebugEnabled()) {
            NucleusLogger.CACHE.debug(
                Localiser.msg(
                    "026034",
                    StringUtils.toJVMIDString(getObject()),
                    myID,
                    StringUtils.intArrayToString(cacheFieldsToLoad)));
          }

          L2CacheRetrieveFieldManager l2RetFM = new L2CacheRetrieveFieldManager(this, cachedPC);
          this.replaceFields(cacheFieldsToLoad, l2RetFM);
          int[] fieldsNotLoaded = l2RetFM.getFieldsNotLoaded();
          if (fieldsNotLoaded != null) {
            for (int i = 0; i < fieldsNotLoaded.length; i++) {
              loadedFields[fieldsNotLoaded[i]] = false;
            }
          }
        }
      }
    }

    return ClassUtils.getFlagsSetTo(loadedFields, fieldNumbers, false);
  }
  /**
   * Convenience method to update a Level2 cached version of this object if cacheable and has not
   * been modified during this transaction.
   *
   * @param fieldNumbers Numbers of fields to update in L2 cached object
   */
  protected void updateLevel2CacheForFields(int[] fieldNumbers) {
    String updateMode = (String) myEC.getProperty(PropertyNames.PROPERTY_CACHE_L2_UPDATE_MODE);
    if (updateMode != null && updateMode.equalsIgnoreCase("commit-only")) {
      return;
    }
    if (fieldNumbers == null || fieldNumbers.length == 0) {
      return;
    }

    Level2Cache l2cache = myEC.getNucleusContext().getLevel2Cache();
    if (l2cache != null
        && myEC.getNucleusContext().isClassCacheable(cmd)
        && !myEC.isObjectModifiedInTransaction(myID)) {
      CachedPC<T> cachedPC = l2cache.get(myID);
      if (cachedPC != null) {
        // This originally just updated the L2 cache for fields where the L2 cache didn't have a
        // value for that field, like this
        /*
        int[] cacheFieldsToLoad = ClassUtils.getFlagsSetTo(cachedPC.getLoadedFields(), fieldNumbers, false);
        if (cacheFieldsToLoad == null || cacheFieldsToLoad.length == 0)
        {
            return;
        }
        */
        int[] cacheFieldsToLoad = fieldNumbers;
        CachedPC copyCachedPC = cachedPC.getCopy();
        if (NucleusLogger.CACHE.isDebugEnabled()) {
          NucleusLogger.CACHE.debug(
              Localiser.msg(
                  "026033",
                  StringUtils.toJVMIDString(getObject()),
                  myID,
                  StringUtils.intArrayToString(cacheFieldsToLoad)));
        }

        provideFields(cacheFieldsToLoad, new L2CachePopulateFieldManager(this, copyCachedPC));

        // Replace the current L2 cached object with this one
        myEC.getNucleusContext().getLevel2Cache().put(getInternalObjectId(), copyCachedPC);
      }
    }
  }