You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by bu...@apache.org on 2003/03/04 08:34:15 UTC

DO NOT REPLY [Bug 17630] New: - Java extension method cache keys are not unique

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17630>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17630

Java extension method cache keys are not unique

           Summary: Java extension method cache keys are not unique
           Product: XalanJ2
           Version: CurrentCVS
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: Critical
          Priority: Other
         Component: org.apache.xpath
        AssignedTo: xalan-dev@xml.apache.org
        ReportedBy: karena@documentum.com


When using extensions, the method key that's generated for caching purposes is 
not unique. The current key is based on - current position in the m_opMap array 
+ hash code + current time in milliseconds. However, the below debug statements 
show that they are not unique and as a result the invocation of methods are 
incorrect and the behavior is very non-deterministic.

Steps to reproduce: 
------------------
This is extremely hard to reproduce since the method key is dependent on the 
hash code and the current time. In order to reproduce these have to match up.

Debug statements:
-----------------
1. Output of the method key from Compiler:compileExtension(). The key 
624301046301758359 is duplicate. The value within parenthesis show the 
different components of the key i.e. current position in the m_opMap array,  
hash code and current time in milliseconds, each separated by a '-'. 

compileExtension-> methodKey=828971046301758312(8-2897-1046301758312) 
funcName=nodeset
compileExtension-> methodKey=827741046301758328(8-2774-1046301758328) 
funcName=nodeset
compileExtension-> methodKey=825811046301758343(8-2581-1046301758343) 
funcName=nodeset
compileExtension-> methodKey=624881046301758359(6-2488-1046301758359) 
funcName=com.documentum.xml.xdql.DfXmlQuery.new
compileExtension-> methodKey=624481046301758359(6-2448-1046301758359) 
funcName=init
compileExtension-> methodKey=624301046301758359(6-2430-1046301758359) 
funcName=setDql
compileExtension-> methodKey=626081046301758359(6-2608-1046301758359) 
funcName=includeContent
compileExtension-> methodKey=625081046301758359(6-2508-1046301758359) 
funcName=includeContent
compileExtension-> methodKey=624771046301758359(6-2477-1046301758359) 
funcName=setErrorTag
compileExtension-> methodKey=624321046301758359(6-2432-1046301758359) 
funcName=setMaxRows
compileExtension-> methodKey=624081046301758359(6-2408-1046301758359) 
funcName=setMetaDataAsAttributes
compileExtension-> methodKey=623771046301758359(6-2377-1046301758359) 
funcName=setMetaDataAsAttributes
compileExtension-> methodKey=623441046301758359(6-2344-1046301758359) 
funcName=setRowsetTag
compileExtension-> methodKey=623321046301758359(6-2332-1046301758359) 
funcName=setContentEncoding
compileExtension-> methodKey=623131046301758359(6-2313-1046301758359) 
funcName=setRepeatingAsNested
compileExtension-> methodKey=625291046301758359(6-2529-1046301758359) 
funcName=setRepeatingAsNested
compileExtension-> methodKey=624811046301758359(6-2481-1046301758359) 
funcName=execute
compileExtension-> methodKey=624301046301758359(6-2430-1046301758359) 
funcName=getXMLDOM

2. The below debug statements show entry (>>) and exit (<<) calls. If the entry 
calls have any parameters they are shown within the parenthesis and if the exit 
calls have any return values they are shown using '-->'. It's clearly visible 
that because of the key duplication, the value in the cache is being replaced. 
Also, it's evident that an ArrayIndexOutOfBoundsException is thrown. However, 
this exception is swallowed in ExtensionHandlerJavaPackage and as a result the 
problem is lot harder to track.

           >> org.apache.xalan.extensions.ExtensionsTable:extFunction 
('http://xml.apache.org/xslt/java', 'setDql', 'Vector@55d', '624301046301758359'
, 'XPathContext$XPathExpressionContext@8ef')
             >> 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:callFunction 
('setDql', 'Vector@55d', '624301046301758359', 'XPathContext$XPathExpressionCont
ext@8ef')
               >> 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:getFromCache 
('624301046301758359', 'DfXmlQuery@837', 'Object;@4ff')
               << 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:getFromCache --> null
               >> org.apache.xalan.extensions.MethodResolver:getMethod 
('Class@394', 'setDql', 'Object;@4ff', 'Object;@3a5', 'XPathContext$XPathExpress
ionContext@8ef', '2')
                 >> org.apache.xalan.extensions.MethodResolver:scoreMatch 
('Class;@33b', '0', 'Object;@4ff', '1000')
                 << org.apache.xalan.extensions.MethodResolver:scoreMatch --
> "1000"
                 >> org.apache.xalan.extensions.MethodResolver:convertParams 
('Object;@4ff', 'Object;@3a5', 'Class;@33b', 'XPathContext$XPathExpressionContex
t@8ef')
                   >> org.apache.xalan.extensions.MethodResolver:convert 
('XStringForFSB@84e35927', 'Class@3e2')
                   << org.apache.xalan.extensions.MethodResolver:convert --
> "select r_object_id, object_name, award_date, award_name, i_folder_id from 
bea_award where object_name = 'dave_award_test' or object_name = 'awd00002.xml' 
and folder('/BEAPublish/news_events', DESCEND)"
               << org.apache.xalan.extensions.MethodResolver:getMethod --
> "public void com.documentum.xml.xdql.DfXmlQuery.setDql(java.lang.String)"
               >> 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:putToCache 
('624301046301758359', 'DfXmlQuery@837', 'Object;@4ff', 'Method@ec79280f')
               << 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:putToCache --> null
               >> com.documentum.xml.xdql.DfXmlQuery:setDql ('select 
r_object_id, object_name, award_date, award_name, i_folder_id from bea_award 
where object_name = 'dave_award_test' or object_name = 'awd00002.xml' and folder
('/BEAPublish/news_events', DESCEND)')
             << 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:callFunction --> null
           << org.apache.xalan.extensions.ExtensionsTable:extFunction --> null

           >> org.apache.xalan.extensions.ExtensionsTable:extFunction 
('http://xml.apache.org/xslt/java', 'getXMLDOM', 'Vector@bc4', '6243010463017583
59', 'XPathContext$XPathExpressionContext@8ef')
             >> 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:callFunction 
('getXMLDOM', 'Vector@bc4', '624301046301758359', 'XPathContext$XPathExpressionC
ontext@8ef')
               >> 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:getFromCache 
('624301046301758359', 'DfXmlQuery@837', 'Object;@bb2')
               << 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:getFromCache --
> "public void com.documentum.xml.xdql.DfXmlQuery.setDql(java.lang.String)"
               >> org.apache.xalan.extensions.MethodResolver:convertParams 
('Object;@bb2', 'Object;@ba1', 'Class;@b9f', 'XPathContext$XPathExpressionContex
t@8ef')
               << org.apache.xalan.extensions.MethodResolver:convertParams --> 
with Exception:
java.lang.ArrayIndexOutOfBoundsException
	at org/apache/xalan/extensions/MethodResolver.convertParams
	at org/apache/xalan/extensions/ExtensionHandlerJavaPackage.callFunction
	at org/apache/xalan/extensions/ExtensionsTable.extFunction
	at org/apache/xpath/functions/FuncExtFunction.execute
	at org/apache/xpath/XPath.execute
	at org/apache/xalan/templates/ElemVariable.getValue
	at org/apache/xalan/templates/ElemVariable.execute
	at org/apache/xalan/transformer/TransformerImpl.executeChildTemplates
	at org/apache/xalan/templates/ElemTemplate.execute
	at org/apache/xalan/templates/ElemCallTemplate.execute
	at org/apache/xalan/transformer/TransformerImpl.executeChildTemplates
	at org/apache/xalan/transformer/TransformerImpl.transformToRTF
	at org/apache/xalan/templates/ElemVariable.getValue
	at org/apache/xalan/templates/ElemVariable.execute
	at org/apache/xalan/transformer/TransformerImpl.executeChildTemplates
	at org/apache/xalan/transformer/TransformerImpl.applyTemplateToNode
	at org/apache/xalan/transformer/TransformerImpl.transformNode
	at org/apache/xalan/transformer/TransformerImpl.transform
	at org/apache/xalan/transformer/TransformerImpl.transform
	at org/apache/xalan/transformer/TransformerImpl.transform
	at com/documentum/operations/DfApplyTransformation.applyStyleSheet
	at com/documentum/operations/DfApplyTransformation.applyStyleSheet
	at com/documentum/operations/DfApplyTransformation.applyTransformation
	at com/documentum/operations/DfApplyTransformation.execute
	at com/documentum/operations/DfOperationStep.execute
	at com/documentum/operations/DfOperation.execute
	at com/documentum/wcm/WcmUtil.createTransToFile
	at com/documentum/webclient/xmledit/server/PreviewMgr.setPreviewContent
	at com/documentum/webclient/xmledit/server/DocbaseServer.request
               >> org.apache.xalan.extensions.MethodResolver:getMethod 
('Class@394', 'getXMLDOM', 'Object;@bb2', 'Object;@ba1', 'XPathContext$XPathExpr
essionContext@8ef', '2')
                 >> org.apache.xalan.extensions.MethodResolver:scoreMatch 
('Class;@389', '0', 'Object;@bb2', '1000')
                 << org.apache.xalan.extensions.MethodResolver:scoreMatch --
> "1000"
                 >> org.apache.xalan.extensions.MethodResolver:convertParams 
('Object;@bb2', 'Object;@ba1', 'Class;@389', 'XPathContext$XPathExpressionContex
t@8ef')
               << org.apache.xalan.extensions.MethodResolver:getMethod --
> "public org.w3c.dom.Document com.documentum.xml.xdql.DfXmlQuery.getXMLDOM()"
               >> 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:putToCache 
('624301046301758359', 'DfXmlQuery@837', 'Object;@bb2', 'Method@e894992b')
#### WARNING: methodKey 624301046301758359 already exists and is being replaced
               << 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:putToCache --> "public 
void com.documentum.xml.xdql.DfXmlQuery.setDql(java.lang.String)"
               >> com.documentum.xml.xdql.DfXmlQuery:getXMLDOM
               << com.documentum.xml.xdql.DfXmlQuery:getXMLDOM --> "[#document: 
null]"
             << 
org.apache.xalan.extensions.ExtensionHandlerJavaPackage:callFunction --
> "[#document: null]"
           << org.apache.xalan.extensions.ExtensionsTable:extFunction --
> "[#document: null]"


Proposed Solution:
-----------------

1. Generate a method key that's guaranteed to be unique. A solution is to use 
the hash code along with a sequential long value. Below is what the code would 
look like: 

  private Expression compileExtension(int opPos)
          throws TransformerException
  {

    ....
    
    // We create a method key to uniquely identify this function so that we
    // can cache the object needed to invoke it.  This way, we only pay the
    // reflection overhead on the first call.

    Function extension = new FuncExtFunction(ns, funcName, 
       + String.valueOf(hashCode())
       + String.valueOf(getNextMethodId()));

    ....
   }

  synchronized private long getNextMethodId()
  {
    if (s_nextMethodId == Long.MAX_VALUE)
      s_nextMethodId = Long.MIN_VALUE;
    
    return s_nextMethodId++;
  }

  private static long s_nextMethodId = Long.MIN_VALUE;   

2. The code that calls into MethodResolver:convertParams() should not swallow 
exceptions blindly.  Rather they should swallow only known exceptions such as 
InvocationTargetException. This pattern of code is evident in 
ExtensionHandlerJavaClass:callFunction() and 
ExtensionHandlerJavaPackage:callFunction().