/**
   * These are the expensive operations (initStandardObjects and compileReader/exec). We do them
   * once here, and define this provider as a singleton, so it's only done at provider creation or
   * whenever rules are refreshed.
   *
   * @param rulesCurator
   */
  private void compileRules(RulesCurator rulesCurator) {
    scriptLock.writeLock().lock();
    try {
      // XXX: we need a principal to access the rules,
      // but pushing and popping system principal could be a bad idea
      Principal systemPrincipal = new SystemPrincipal();
      ResteasyProviderFactory.pushContext(Principal.class, systemPrincipal);
      // Check to see if we need to recompile. we do this inside the write lock
      // just to avoid race conditions where we might double compile
      Date newUpdated = rulesCurator.getUpdated();
      if (newUpdated.equals(this.updated)) {
        return;
      }

      log.debug("Recompiling rules with timestamp: " + newUpdated);

      Context context = Context.enter();
      context.setOptimizationLevel(9);
      scope = context.initStandardObjects(null, true);
      try {
        script = context.compileString(rulesCurator.getRules().getRules(), "rules", 1, null);
        script.exec(context, scope);
        ((ScriptableObject) scope).sealObject();
        this.updated = newUpdated;
      } finally {
        Context.exit();
      }
    } finally {
      ResteasyProviderFactory.popContextData(Principal.class);
      scriptLock.writeLock().unlock();
    }
  }
 public void exit() {
   ResteasyProviderFactory.popContextData(CandlepinSingletonScopeData.class);
 }
  // this is synchronized in conjunction with finalize to protect against premature finalize called
  // by the GC
  protected synchronized <T2> Object readFrom(
      Class<T2> type, Type genericType, MediaType media, Annotation[] annotations) {
    Type useGeneric = genericType == null ? type : genericType;
    Class<?> useType = type;
    boolean isMarshalledEntity = false;
    if (type.equals(MarshalledEntity.class)) {
      isMarshalledEntity = true;
      ParameterizedType param = (ParameterizedType) useGeneric;
      useGeneric = param.getActualTypeArguments()[0];
      useType = Types.getRawType(useGeneric);
    }

    Providers current = ResteasyProviderFactory.getContextData(Providers.class);
    ResteasyProviderFactory.pushContext(Providers.class, providerFactory);
    Object obj = null;
    try {
      InputStream is = streamFactory.getInputStream();
      if (is == null) {
        throw new ClientResponseFailure(Messages.MESSAGES.inputStreamEmpty(), this);
      }
      if (isMarshalledEntity) {
        is = new InputStreamToByteArray(is);
      }

      final Object finalObj =
          new ClientReaderInterceptorContext(
                  readerInterceptors,
                  providerFactory,
                  useType,
                  useGeneric,
                  annotations,
                  media,
                  getResponseHeaders(),
                  new InputStreamWrapper(is),
                  attributes)
              .proceed();
      obj = finalObj;
      if (isMarshalledEntity) {
        InputStreamToByteArray isba = (InputStreamToByteArray) is;
        final byte[] bytes = isba.toByteArray();
        return new MarshalledEntity() {
          @Override
          public byte[] getMarshalledBytes() {
            return bytes;
          }

          @Override
          public Object getEntity() {
            return finalObj;
          }
        };
      } else {
        return (T2) finalObj;
      }

    } catch (Exception e) {
      if (e instanceof ReaderException) {
        throw (ReaderException) e;
      } else {
        throw new ReaderException(e);
      }
    } finally {
      ResteasyProviderFactory.popContextData(Providers.class);
      if (current != null) ResteasyProviderFactory.pushContext(Providers.class, current);
      if (obj instanceof ProvidersContextRetainer) {
        ((ProvidersContextRetainer) obj).setProviders(providerFactory);
      }
    }
  }