/**
   * Tests that the providersCache object is and remains instanceof ConcurrentHashMap.
   *
   * <p>ProvidersRegistry.MediaTypeMap uses type ConcurrentHashMap on the providersCache object to
   * provide some lock protection on the map when providers are dynamically added. However, lock
   * protection is already built into the ProvidersRegistry methods: getContextResolver(),
   * getMessageBodyReader(), and getMessageBodyWriter().
   *
   * <p>However, the second protection (in the ProvidersRegistry methods) is for the cache itself
   * which could be written to by two different threads even if they both were getting a single
   * MessageBodyReader (i.e. a cache value may be dropped and then two threads come back later and
   * try to write a new cache value). Due to some weird HashMap properties, this can blow up in
   * weird ways.
   *
   * <p>Thus, we need to ensure the providersCache continues to be instantiated with
   * ConcurrentHashMap.
   */
  public void testProtectionModel() throws Exception {

    // I need the instantiated object providersCache in the abstract private nested class
    // MediaTypeMap, so here we go!
    ProvidersRegistry providersRegistry =
        new ProvidersRegistry(new LifecycleManagersRegistry(), new ApplicationValidator());
    Field field = providersRegistry.getClass().getDeclaredField("messageBodyReaders");
    field.setAccessible(true);
    Object messageBodyReaders = field.get(providersRegistry);
    Field field2 = messageBodyReaders.getClass().getSuperclass().getDeclaredField("providersCache");
    field2.setAccessible(true);
    Object providersCache = field2.get(messageBodyReaders);

    assertTrue(providersCache instanceof SoftConcurrentMap);
  }
  /**
   * Application subclass methods .getClasses and .getSingletons may list provider class or instance
   * that is the same as a default Wink provider to override it to establish a new priority order.
   *
   * <p>The order that the Wink runtime loads providers is: Application.getSingletons
   * Application.getClasses system (through wink-providers file) extra jars (through each
   * wink-application file)
   */
  @SuppressWarnings("unchecked")
  public void testOverrideSystemProvider() throws Exception {
    ProvidersRegistry providersRegistry = createProvidersRegistryImpl();
    assertTrue(
        providersRegistry.addProvider(
            StringReader.class, 0.5, false)); // registered as a user provider
    MessageBodyReader<String> reader1 =
        providersRegistry.getMessageBodyReader(
            String.class, null, null, MediaType.TEXT_PLAIN_TYPE, null);

    // registered twice as a custom user provider with higher priority
    // See javadoc for Application.getSingletons to see why we ignore the attempt to add a second
    // StringReader
    assertFalse(providersRegistry.addProvider(StringReader.class, 0.6, false));
    MessageBodyReader<String> reader2 =
        providersRegistry.getMessageBodyReader(
            String.class, null, null, MediaType.TEXT_PLAIN_TYPE, null);
    assertTrue(reader1 == reader2); // object compare to make sure reader2 has been silently ignored

    // registered as a system provider
    assertFalse(providersRegistry.addProvider(StringReader.class, 0.1, false));
    MessageBodyReader<String> reader3 =
        providersRegistry.getMessageBodyReader(
            String.class, null, null, MediaType.TEXT_PLAIN_TYPE, null);
    assertTrue(reader1 == reader3); // object compare to make sure reader3 has been silently ignored
    assertTrue(reader2 == reader3); // object compare to make sure reader3 has been silently ignored

    // to confirm that the ignores are indeed happening, I need to get the private field
    // "messageBodyReaders" object, then it's superclass "data" object and inspect it:
    Field field = providersRegistry.getClass().getDeclaredField("messageBodyReaders");
    field.setAccessible(true);
    Object messageBodyReaders = field.get(providersRegistry);
    Field field2 = messageBodyReaders.getClass().getSuperclass().getDeclaredField("data");
    field2.setAccessible(true);
    HashMap data = (HashMap) field2.get(messageBodyReaders);
    Set readers = (Set) data.get(MediaType.WILDCARD_TYPE);

    // make there is only one provider in the list to conform to JAX-RS 4.1 first sentence
    assertEquals(1, readers.size());
  }