UUderzo
UUderzo

Reputation: 1

Using different DocumentBuilder implementations on the same Java VM

I know that this question has been already asked, but in a different flavour so i ask again from my POV.

In our application server several EJB reside (so, AFAIK, several threads, one for each EJB call). Some EJB, for proper functioning, need that the DocumentBuilder factory to produce xerces instances, some EJB need crimson instances.

Currently, a choice was made to force xerces as the default, so the xerces class was injected in the proper System.property, which is global.

As far as i can see, the DocumentBuilder class looks first for the System.property, then for a property file into the JRE folder, then again for property files into JAR/Services.

To isolate the library that needs crimson to work i wrote a custom classloader, so their jars are not in classpath and i can be sure that other parts of the "suite" are sound and safe from interferences.

But even if i isolate those jars, they leverage on DocumentBuilder, that looks for the implementation as previously said. If i change the System.property for the strict time needed to call the library, i risk that other EJBs to crash because they don't get the correct implementation.

I tried also to write a fake DocumentBuilder class to switch the newInstance result based on the calling thread, but this didn't work (too bad the called library masks the exceptions by catching original exceptions and throwing new exceptions by getting only the original message, which is insufficient to get the point)

I'm looking for a way to isolate the property change at thread level, but cannot figure it out.

Any thoughts? Thank you!

Upvotes: 0

Views: 812

Answers (1)

UUderzo
UUderzo

Reputation: 1

Ok, i figured out how to workaround this issue.

I actually wrote a fake DocumentBuilder, that takes in a static field the Thread that needs to get the crimson implementation. So, only this thread will get crimson, all other threads will get xerces. Then, i just set this class in the javax.xml.parsers.DocumentBuilderFactory System property and reset to the original value when finished. This solution can be generalized to a permanent class that handles requests from vaiour threads, i guess.

Here the source of the fake DocumentBuilder:

public class   DocumentBuilderFactoryTweak
       extends DocumentBuilderFactory
{
  private static Thread tweakingTH = null;    

  private DocumentBuilderFactory impl = null;

  public DocumentBuilderFactoryTweak() {
    super();
    try {
      this.impl =
          Thread.currentThread() == tweakingTH
        ? (DocumentBuilderFactory)tweakingTH.getContextClassLoader().loadClass( "org.apache.crimson.jaxp.DocumentBuilderFactoryImpl" ).newInstance()
        : (DocumentBuilderFactory)Class.forName( "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"  ).newInstance();
    }
    catch( Throwable exc ) { exc.printStackTrace(); }
  }

  public synchronized static void setTweakingThread( Thread th ) { tweakingTH = th; }

  public boolean isCoalescing                                ()                                     { return this.impl.isCoalescing                      ();       }
  public boolean isExpandEntityReferences                    ()                                     { return this.impl.isExpandEntityReferences          ();       }
  public boolean isIgnoringComments                          ()                                     { return this.impl.isIgnoringComments                ();       }
  public boolean isIgnoringElementContentWhitespace          ()                                     { return this.impl.isIgnoringElementContentWhitespace();       }
  public boolean isNamespaceAware                            ()                                     { return this.impl.isNamespaceAware                  ();       }
  public boolean isValidating                                ()                                     { return this.impl.isValidating                      ();       }
  public void    setCoalescing                               ( boolean v )                          { this.impl.setCoalescing                            ( v );    }
  public void    setExpandEntityReferences                   ( boolean v )                          { this.impl.setExpandEntityReferences                ( v );    }
  public void    setIgnoringComments                         ( boolean v )                          { this.impl.setIgnoringComments                      ( v );    }
  public void    setIgnoringElementContentWhitespace         ( boolean v )                          { this.impl.setIgnoringElementContentWhitespace      ( v );    }
  public void    setNamespaceAware                           ( boolean v )                          { this.impl.setNamespaceAware                        ( v );    }
  public void    setValidating                               ( boolean v )                          { this.impl.setValidating                            ( v );    }
  public javax.xml.parsers.DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { return this.impl.newDocumentBuilder                ();       }
  public Object  getAttribute                                ( String k )                           { return this.impl.getAttribute                      ( k );    }
  public void    setAttribute                                ( String k, Object v )                 { this.impl.setAttribute                             ( k, v ); }    
}

Upvotes: 0

Related Questions