3

I'm facing a conundrum here.

One of the applications that I've developed is loading an incorrect implementation of the DocumentBuilderFactory class of JAXP. This behavior was later deduced to be resulting from another class in different application built by a different team/company. The said class had changed the preferred DocumentBuilderFactory class upon loading, by inclusion of a static block similar to the one below:

  static
  {
    System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "a new factory");
  }

If one goes by the Javadocs of the DocumentBuilderFactory.newInstance method, it would be quite obvious that the above code was responsible for changing the parser implementation returned to all applications, when the newInstance method is invoked.

A patch was applied, which corrected this problem, but it leads me to ask this question - how does one determine which class is performing the System.setProperty call at runtime?

We had produced a custom build of OpenJDK with a modified System class that was responsible for nailing the culprit, for the very simple reason that we did not have access to all the sources for all the applications deployed on the server. But this was possible only due to the fact that the production environment was replicated in its entiriety. The question therefore, could also be interpreted as - how does one determine which class is performing the System.setProperty call at runtime, in a production environment?

Vineet Reynolds
  • 76,006
  • 17
  • 150
  • 174

5 Answers5

6

System.setProperty is checked by a SecurityManager, if installed.

You can create your own MySecurityManager and deploy at runtime. Your own SecurityManager can log some information like the current stacktrace, when the method checkPropertyAccess is called:

public class MySecurityManager extends SecurityManager
{

    public MySecurityManager()
    {
        super();
    }

    @Override
    public void checkPropertyAccess(String key)
    {
        if ("javax.xml.parsers.DocumentBuilderFactory".equals(key))
        {
            System.err.println("checkPropertyAccess(String :" + key + "): ");
            Thread.currentThread().dumpStack(); // or anything useful for
                                                // logging the context.
            new Throwable().printStackTrace(); // whatever, or use it with
            // PrintStream/PrintWriter, or some logging framework if configured.
        }
        super.checkPropertyAccess(key);
    }

    @Override
    public void checkPermission(Permission perm)
    {
        if (perm instanceof PropertyPermission)
        {
            PropertyPermission propPerm = (PropertyPermission) perm;
            System.err.println("checkPropertyAccess(String:" + propPerm.getName() + "):");
            Thread.currentThread().dumpStack(); // or anything useful for
                                                // logging the context.
            new Throwable().printStackTrace(); // whatever, or use it with
            // PrintStream/PrintWriter, or some logging framework if configured.
        }
        super.checkPermission(perm);
    }
}
Vineet Reynolds
  • 76,006
  • 17
  • 150
  • 174
Michael Konietzka
  • 5,419
  • 2
  • 28
  • 29
2

String literals are UTF8-encoded in the class file format and since there is no reason to assume that the offending invoker is using code to concatenate the property name, I would simply have unpacked all JARs from the classpath into one directory and tried a recursive grep for "javax.xml.parsers.DocumentBuilderFactory" through the class files. You would have at least found all class files containing this String as a literal and hopefully not to many false positives.

If the class name of the incorrect implementation is easier to identify, it would perhaps been more clever to search for that instead.

jarnbjo
  • 33,923
  • 7
  • 70
  • 94
  • Well, this isnt a bad idea at all. Thanks for the tip. The only thing that prevents me doing this if the issue recurs, is the fact that there are several MBs of JARs loaded by the application server across several applications and libraries. – Vineet Reynolds Nov 17 '10 at 18:17
  • Well, in fact, In such a case, i would personnally have written it like `System.setProperty(DocumentBuilderFactory.class.getName(), "a new factory");` in order to ensure I use the correct class (that should be in Classpath, as a consequence). but that's only a detail. – Riduidel Nov 18 '10 at 09:00
1

Just start you application in debug mode, connect to it with eclipse, set breakpoint and look what class do it in call hierarchy http://www.eclipsezone.com/eclipse/forums/t53459.html

zaletniy
  • 549
  • 4
  • 12
  • Thanks for the answer. The problem is that remote debugging of applications was not possible in production for very obvious reasons. By the time we had replicated the environment, the home-built JDK was available so eventually it didnt prove to be a bothersome exercise. – Vineet Reynolds Nov 17 '10 at 16:26
1

I know 2 solutions

  1. use aspect framework (aspectJ or so)
  2. Modify System class (add logging to setProperty() method) new Throwable().printStacktrace(); will report you where the method was called from.

Now run your application with option -Xbootclasspath/p and put your version System class there.

-Xbootclasspath/p:<directories and zip/jar files separated by ;> prepend in front of bootstrap class path

I prefer the second solution because it is very simple.

Riduidel
  • 22,052
  • 14
  • 85
  • 185
AlexR
  • 114,158
  • 16
  • 130
  • 208
0

Seems like some use case for aspect frameworks, no ?

Riduidel
  • 22,052
  • 14
  • 85
  • 185