Author: woodroy
Date: Mon Mar 23 17:14:56 2009
New Revision: 757453

URL: http://svn.apache.org/viewvc?rev=757453&view=rev
Log:
Update initCache and clearCache to account for multi-threaded case.
Essentially, one thread could change the static 'resolvedSchema' variable from
null to non-null after another thread found the value to be null. 

Contributor: Jeff Barrett via Roy Wood
                                             

Added:
    
webservices/commons/trunk/modules/XmlSchema/src/test/java/tests/SchemaBuilderCacheTest.java
Modified:
    
webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java

Modified: 
webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java
URL: 
http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java?rev=757453&r1=757452&r2=757453&view=diff
==============================================================================
--- 
webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java
 (original)
+++ 
webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/SchemaBuilder.java
 Mon Mar 23 17:14:56 2009
@@ -24,6 +24,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -66,7 +67,8 @@
      * initialize resolvedSchemas to non-null Clearing of cache is done by 
calling clearCache() which will
      * clear and nullify resolvedSchemas
      */
-    private static Map<String, SoftReference<XmlSchema>> resolvedSchemas;
+       
+    private static Map<String, Map<String, SoftReference<XmlSchema>>> 
resolvedSchemas;
     private static final String[] RESERVED_ATTRIBUTES_LIST =  {"name", 
                                                                "type", 
                                                                "default", 
@@ -109,16 +111,108 @@
         currentSchema = new XmlSchema();
     }
 
+    
+       /**
+     * Setup the cache to be used by the current thread of execution. Multiple
+     * threads can use the cache, and each one must call this method at
+     * some point prior to attempting to resolve the first schema, or the cache
+     * will not be used on that thread.
+     * 
+     * IMPORTANT: The thread MUST call clearCache() when it is done with the
+     * schemas or a large amount of memory may remain in-use.
+     */
+    public static synchronized void initCache() {
+
+       if (resolvedSchemas == null) {
+            resolvedSchemas = 
+               Collections.synchronizedMap(new HashMap<String, Map<String, 
SoftReference<XmlSchema>>>());
+        }
+        
+        String threadID = String.valueOf(Thread.currentThread().getId());
+        
+        Map<String, SoftReference<XmlSchema>> threadResolvedSchemas =          
+               resolvedSchemas.get(threadID);        
+
+        // If there is no entry yet for this thread ID, then create one
+        if (threadResolvedSchemas == null) {
+            threadResolvedSchemas = Collections.synchronizedMap(new 
Hashtable<String, SoftReference<XmlSchema>>());
+            resolvedSchemas.put(threadID, threadResolvedSchemas);
+
+        }
+    }
+
+    /**
+     * Remove any entries from the cache for the current thread. Entries for
+     * other threads are not altered.
+     */
     public static synchronized void clearCache() {
         if (resolvedSchemas != null) {
-            resolvedSchemas.clear(); // necessary?
-            resolvedSchemas = null;
+            String threadID = String.valueOf(Thread.currentThread().getId());
+            // If there are entries for this thread ID, then clear them and
+            // remove the entry
+            Map<String, SoftReference<XmlSchema>> threadResolvedSchemas =      
+               resolvedSchemas.get(threadID);        
+
+            if (threadResolvedSchemas != null) {
+                threadResolvedSchemas.clear();
+                resolvedSchemas.remove(threadID);
+            }
+        }
+    }
+       
+    /**
+     * Return a cached schema if one exists for this thread.  In order for 
schemas to be cached
+     * the thread must have done an initCache() previously.
+     * The parameters are used to construct a key used to lookup the schema
+     * @param targetNamespace
+     * @param schemaLocation
+     * @param baseUri
+     * @return The cached schema if one exists for this thread or null.
+     */
+    private XmlSchema getCachedSchema(String targetNamespace,
+            String schemaLocation, String baseUri) {
+        
+        XmlSchema resolvedSchema = null;
+    
+        if (resolvedSchemas != null) {  // cache is initialized, use it
+            String threadID = String.valueOf(Thread.currentThread().getId());
+            Map<String, SoftReference<XmlSchema>> threadResolvedSchemas =      
+               resolvedSchemas.get(threadID);        
+            if (threadResolvedSchemas != null) {
+                // Not being very smart about this at the moment. One could, 
for example,
+                // see that the schemaLocation or baseUri is the same as 
another, but differs
+                // only by a trailing slash. As it is now, we assume a single 
character difference
+                // means it's a schema that has yet to be resolved.
+                String schemaKey = targetNamespace + schemaLocation + baseUri;
+                SoftReference<XmlSchema> softref = 
threadResolvedSchemas.get(schemaKey);
+                if (softref != null) {
+                    resolvedSchema = softref.get();
+                }
+            }
         }
+        return resolvedSchema;
     }
 
-    public static synchronized void initCache() {
-        if (resolvedSchemas == null) {
-            resolvedSchemas = Collections.synchronizedMap(new HashMap<String, 
SoftReference<XmlSchema>>());
+    /**
+     * Add an XmlSchema to the cache if the current thread has the cache 
enabled. 
+     * The first three parameters are used to construct a key
+     * @param targetNamespace
+     * @param schemaLocation
+     * @param baseUri
+     * This parameter is the value put under the key (if the cache is enabled)
+     * @param readSchema
+     */
+    private void putCachedSchema(String targetNamespace, String schemaLocation,
+            String baseUri, XmlSchema readSchema) {
+        
+        if (resolvedSchemas != null) {
+            String threadID = String.valueOf(Thread.currentThread().getId());
+            Map<String, SoftReference<XmlSchema>> threadResolvedSchemas =      
+               resolvedSchemas.get(threadID);        
+            if (threadResolvedSchemas != null) {
+                String schemaKey = targetNamespace + schemaLocation + baseUri;
+                threadResolvedSchemas.put(schemaKey, new 
SoftReference<XmlSchema>(readSchema));
+            }
         }
     }
 
@@ -917,22 +1011,10 @@
     XmlSchema resolveXmlSchema(String targetNamespace, String schemaLocation, 
String baseUri,
                                TargetNamespaceValidator validator) {
 
-        String schemaKey = null;
-        if (resolvedSchemas != null) { // cache is initialized, use it
-            // Not being very smart about this at the moment. One could, for 
example,
-            // see that the schemaLocation or baseUri is the same as another, 
but differs
-            // only by a trailing slash. As it is now, we assume a single 
character difference
-            // means it's a schema that has yet to be resolved.
-            schemaKey = Thread.currentThread().getId() + targetNamespace + 
schemaLocation + baseUri;
-            SoftReference<XmlSchema> softref = resolvedSchemas.get(schemaKey);
-            if (softref != null) {
-                XmlSchema resolvedSchema = softref.get();
-                if (resolvedSchema != null) {
-                    return resolvedSchema;
-                }
-            }
+        if (getCachedSchema(targetNamespace, schemaLocation, baseUri) != null) 
{
+            return getCachedSchema(targetNamespace, schemaLocation, baseUri);
         }
-
+        
         // use the entity resolver provided if the schema location is present 
null
         if (schemaLocation != null && !"".equals(schemaLocation)) {
             InputSource source = 
collection.getSchemaResolver().resolveEntity(targetNamespace,
@@ -958,9 +1040,7 @@
                 collection.push(key);
                 try {
                     XmlSchema readSchema = collection.read(source, null, 
validator);
-                    if (resolvedSchemas != null) {
-                        resolvedSchemas.put(schemaKey, new 
SoftReference<XmlSchema>(readSchema));
-                    }
+                    putCachedSchema(targetNamespace, schemaLocation, baseUri, 
readSchema);
                     return readSchema;
                 } catch (Exception e) {
                     throw new RuntimeException(e);

Added: 
webservices/commons/trunk/modules/XmlSchema/src/test/java/tests/SchemaBuilderCacheTest.java
URL: 
http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/test/java/tests/SchemaBuilderCacheTest.java?rev=757453&view=auto
==============================================================================
--- 
webservices/commons/trunk/modules/XmlSchema/src/test/java/tests/SchemaBuilderCacheTest.java
 (added)
+++ 
webservices/commons/trunk/modules/XmlSchema/src/test/java/tests/SchemaBuilderCacheTest.java
 Mon Mar 23 17:14:56 2009
@@ -0,0 +1,424 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *      
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package tests;
+
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Field;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.ws.commons.schema.SchemaBuilder;
+import org.apache.ws.commons.schema.XmlSchema;
+import org.apache.ws.commons.schema.XmlSchemaCollection;
+import org.w3c.dom.Document;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.Ignore;
+
+/**
+ * Test the resolved Schema cache.   
+ */
+public class SchemaBuilderCacheTest extends Assert {
+
+       /**
+     * Test that if the cache is not initialized, then it should not be used 
when a schema is read.
+     * @throws Exception
+     */
+       @Test
+    public void testResolveCacheUninitialized() throws Exception {
+        Document doc = setupDocument();
+        XmlSchemaCollection schemaCol = setupXmlSchemaCollection();
+        XmlSchema schema = schemaCol.read(doc,null);
+        assertNotNull(schema);
+        
+        // If the cache is not in use, then it should be null
+        assertNull(getResolvedSchemasHashtable());
+    }
+    
+    /**
+     * Test if the cache is initialized it will be populated when a schema is 
read and it will
+     * be cleared when the clearCache method is called.
+     * @throws Exception
+     */
+       @Test
+    public void testResolveCacheInitialized() throws Exception {
+        try {
+            SchemaBuilder.initCache();
+            Document doc = setupDocument();
+            XmlSchemaCollection schemaCol = setupXmlSchemaCollection();
+            XmlSchema schema = schemaCol.read(doc, null);
+            assertNotNull(schema);
+
+            // If the cache is in use, it should not be null and there should
+            // be an entry for this thread ID
+            assertNotNull(getResolvedSchemasHashtable());
+            Map<String, SoftReference<XmlSchema>> threadHT = 
getThreadResolvedSchemaHashtable();
+            assertNotNull(threadHT);
+            assertFalse(threadHT.isEmpty());
+            assertEquals(1, threadHT.size());
+            
+            // After clearing the cache, there should be no entry for this 
thread ID, and 
+            // the hashtable should not be null
+            SchemaBuilder.clearCache();
+            assertNotNull(getResolvedSchemasHashtable());
+            assertNull(getThreadResolvedSchemaHashtable());
+            System.out.println("Line 13");
+        } finally {
+            resetResolvedSchemasHashtable();
+        }
+        
+        // If the cache is enabled, then it should be non-null
+    }
+    
+    /**
+     * Test that threads can not affect the cache for other threads.
+     */
+       @Test
+    public void testMultithreadCache() {
+        try {
+            MultithreadUpdateLockMonitor testMonitor = new 
MultithreadUpdateLockMonitor();
+            startupTestThreads(testMonitor);
+
+            if (testMonitor.t1Exception != null) {
+                fail("Thread T1 encountred an error: "
+                        + testMonitor.t1Exception.toString());
+            }
+            if (testMonitor.t2Exception != null) {
+                fail("Thread T2 encountred an error: "
+                        + testMonitor.t2Exception.toString());
+            }
+            if (testMonitor.t3Exception != null) {
+                fail("Thread T3 encountred an error: "
+                        + testMonitor.t3Exception.toString());
+            }
+        } finally {
+            resetResolvedSchemasHashtable();
+        }
+    }
+    
+    
//==============================================================================================
+    // Utility Methods
+    
//==============================================================================================
+    
+    static Document setupDocument() {
+        DocumentBuilderFactory documentBuilderFactory = 
DocumentBuilderFactory.newInstance();
+        documentBuilderFactory.setNamespaceAware(true);
+        Document doc;
+        try {
+            doc = documentBuilderFactory.newDocumentBuilder().
+                    parse(Resources.asURI("importBase.xsd"));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return doc;
+    }
+    
+    static XmlSchemaCollection setupXmlSchemaCollection() {
+        XmlSchemaCollection schemaCol = new XmlSchemaCollection();
+        schemaCol.setBaseUri(Resources.TEST_RESOURCES);
+        return schemaCol;
+    }
+    
+    /**
+     * Override the protection on the resolvedSchemas attribute in the 
SchemaBuilder class
+     * and return its current value.
+     * @return value of Hashtable resolvedSchemas, which may be null
+     * @throws Exception If there are problems with Java reflection (should 
not happen)
+     */
+    static Map<String, Map<String, SoftReference<XmlSchema>>> 
getResolvedSchemasHashtable(){
+       Map<String, Map<String, SoftReference<XmlSchema>>> ht = null;
+        try {
+            Field field = 
SchemaBuilder.class.getDeclaredField("resolvedSchemas");
+            field.setAccessible(true);
+            ht = (Map<String, Map<String, 
SoftReference<XmlSchema>>>)field.get(null);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return ht;
+    }
+    
+    /**
+     * Return the Hashtable for the current thread or null if there is not one.
+     * @return
+     */
+    static Map<String, SoftReference<XmlSchema>> 
getThreadResolvedSchemaHashtable() {
+       Map<String, SoftReference<XmlSchema>> threadHashtable = null;
+        Map<String, Map<String, SoftReference<XmlSchema>>> ht = 
getResolvedSchemasHashtable();
+        if (ht != null) {
+            String threadID = String.valueOf(Thread.currentThread().getId());
+            threadHashtable = (Map<String, SoftReference<XmlSchema>>) 
ht.get(threadID);
+        }
+        return threadHashtable;
+    }
+    
+    /**
+     * Set the resolvedSchemas collection to null.  This should be done in a 
finally block
+     * of any tests that cause an SchemaBuilder.initCache to be done to 
cleanup for the next 
+     * test.
+     */
+    static void resetResolvedSchemasHashtable() {
+        try {
+            Field field = 
SchemaBuilder.class.getDeclaredField("resolvedSchemas");
+            field.setAccessible(true);
+            Map<String, Map<String, SoftReference<XmlSchema>>> ht = 
(Map<String, Map<String, SoftReference<XmlSchema>>>) field.get(null);
+            if (ht != null) {
+                ht.clear();
+                field.set(null, null);
+            } 
+        }catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // Amount of time the testcase should wait on the test threads before 
timing out
+    private static int THREAD_TIMEOUT = 90000;
+    
+    /**
+     * Configure and start the test threads for the multi-threaded testing.  
The threads will
+     * perform various tests between themselves such as clearing cache in one 
thread and making 
+     * sure the cache used by a different thread is not affected.  A monitor 
is used to control
+     * the synchonization between the threads and for communicating faliures 
back to the test
+     * method.  
+     * 
+     * See thed Runnable classes for details on the tests performed.
+     * 
+     * @param testMonitor Used to synchronize the tests between the threads
+     */
+    private void startupTestThreads(MultithreadUpdateLockMonitor testMonitor) {
+        TestingRunnable1 testRunnable1 = new TestingRunnable1();
+        testRunnable1.testMonitor = testMonitor;
+        
+        TestingRunnable2 testRunnable2 = new TestingRunnable2();
+        testRunnable2.testMonitor = testMonitor;
+        
+        TestingRunnable3 testRunnable3 = new TestingRunnable3();
+        testRunnable3.testMonitor = testMonitor;
+
+        Thread thread1 = new Thread(testRunnable1);
+        Thread thread2 = new Thread(testRunnable2);
+        Thread thread3 = new Thread(testRunnable3);
+
+        thread1.start();
+        thread2.start();
+        thread3.start();
+        
+        // Join the threads to wait for their completion, specifying a timeout 
to prevent 
+        // a testcase hang if something goes wrong with the threads.
+        try {
+            thread1.join(THREAD_TIMEOUT);
+            thread2.join(THREAD_TIMEOUT);
+            thread3.join(THREAD_TIMEOUT);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            fail("Unable to join to testing threads");
+        }
+    }
+}
+
+/**
+ * Monitor used to control synchronization between the testing threads and 
communicate failures
+ * back to the test method. 
+ */
+class MultithreadUpdateLockMonitor {
+    boolean t1SetupComplete = false;
+    boolean t2SetupComplete = false;
+    Exception t1Exception = null;
+    Exception t2Exception = null;
+    Exception t3Exception = null;
+}
+//=================================================================================================
+// Test execution threads
+//=================================================================================================
+/**
+ * Thread 1 will do the following
+ * - Initialize the cache and verify it was used during a read
+ * - Unblock Thread 2
+ * - Wait until Thread 2 unblocks it
+ * - Verify that the clearCache done by Thread 2 did not affect this Thread's 
cache.
+ */
+...@ignore
+class TestingRunnable1 implements Runnable {
+    
+    MultithreadUpdateLockMonitor testMonitor = null;
+
+    public void run() {
+        SchemaBuilder.initCache();
+        Document doc = SchemaBuilderCacheTest.setupDocument();
+        XmlSchemaCollection schemaCol = 
SchemaBuilderCacheTest.setupXmlSchemaCollection();
+        XmlSchema schema = schemaCol.read(doc, null);
+        if (schema == null) {
+            testMonitor.t1Exception = new Exception("Schema was null");
+        }
+
+        // If the cache is in use, it should not be null and there should be 
an entry for this
+        // Thread
+        if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) {
+            testMonitor.t1Exception = new Exception("resolvedSchemas was 
null");
+        }
+        Map<String, SoftReference<XmlSchema>> threadHT = 
SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable();
+        if (threadHT == null ) {
+            testMonitor.t1Exception = new Exception("Thread resolvedSchemas 
was null");
+        }
+        
+        if (threadHT.isEmpty()) {
+            testMonitor.t1Exception = new Exception("Thread resolvedSchemas 
was empty");
+        }
+
+        synchronized(testMonitor) {
+            testMonitor.t1SetupComplete = true;
+            testMonitor.notifyAll();
+            while (!testMonitor.t2SetupComplete) {
+                try {
+                    testMonitor.wait();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                    testMonitor.t1Exception = new RuntimeException(e);
+                    throw (RuntimeException) testMonitor.t1Exception;
+                }
+            }
+        }
+       
+        // After the other thread does a reset, the cache for this thread 
should NOT be null
+        if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) {
+            testMonitor.t1Exception = new Exception("resolvedSchemas was null 
after reset");
+        }
+        threadHT = SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable();
+        if (threadHT == null ) {
+            testMonitor.t1Exception = new Exception("Thread resolvedSchemas 
was null after clear");
+        }
+        
+        if (threadHT.isEmpty()) {
+            testMonitor.t1Exception = new Exception("Thread resolvedSchemas 
was empty after clear");
+        }
+        
+        // Issue our a clear on this TID, and now there should be no entires 
for it
+        SchemaBuilder.clearCache();
+        if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) {
+            testMonitor.t1Exception = new Exception("resolvedSchemas was null 
after clear on TID");
+        }
+
+        threadHT = SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable();
+        if (threadHT != null ) {
+            testMonitor.t1Exception = new Exception("Thread resolvedSchemas 
was not null after clear");
+        }
+    }
+}
+
+/**
+ * Thread 2 will:
+ * - Block until released by Thread 1
+ * - Initialize the cache then make sure it was used for a resolve on this 
thread
+ * - clear the cache and make sure the entries for this Thread a removed 
+ * - Unblock Thread 1 to make sure the clear did not affect it
+ */
+...@ignore
+class TestingRunnable2 implements Runnable {
+    
+    MultithreadUpdateLockMonitor testMonitor = null;
+
+    public void run() {
+        synchronized (testMonitor) {
+            while (!testMonitor.t1SetupComplete) {
+                try {
+                    testMonitor.wait();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                    testMonitor.t2Exception = new RuntimeException(e);
+                    throw (RuntimeException) testMonitor.t2Exception;
+                }
+            }
+        }
+        SchemaBuilder.initCache();
+        Document doc = SchemaBuilderCacheTest.setupDocument();
+        XmlSchemaCollection schemaCol = 
SchemaBuilderCacheTest.setupXmlSchemaCollection();
+        XmlSchema schema = schemaCol.read(doc, null);
+        if (schema == null) {
+            testMonitor.t2Exception = new Exception("Schema was null");
+        }
+
+        // If the cache is in use, it should not be null.
+        if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) {
+            testMonitor.t2Exception = new Exception("resolvedSchemas was 
null");
+        }
+        Map<String, SoftReference<XmlSchema>> threadHT = 
SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable();
+        if (threadHT == null ) {
+            testMonitor.t2Exception = new Exception("Thread resolvedSchemas 
was null");
+        }
+        if (threadHT.isEmpty()) {
+            testMonitor.t2Exception = new Exception("Thread resolvedSchemas 
was empty");
+        }
+
+        // Issue our a clear on this TID, and now there should be no entires 
for it
+        SchemaBuilder.clearCache();
+        if (SchemaBuilderCacheTest.getResolvedSchemasHashtable() == null) {
+            testMonitor.t2Exception = new Exception("resolvedSchemas was null 
after clear on TID");
+        }
+
+        threadHT = SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable();
+        if (threadHT != null ) {
+            testMonitor.t2Exception = new Exception("Thread resolvedSchemas 
was not null after clear");
+        }
+        
+        synchronized (testMonitor) {
+            testMonitor.t2SetupComplete = true;
+            testMonitor.notifyAll();
+        }
+    }
+}
+
+/**
+ * Test that the init done by Thread 1 does NOT cause the cache to be used by 
this thread 
+ * which did not do an init.
+ */
+...@ignore
+class TestingRunnable3 implements Runnable {
+    MultithreadUpdateLockMonitor testMonitor = null;
+
+    public void run() {
+        synchronized (testMonitor) {
+            while (!testMonitor.t1SetupComplete) {
+                try {
+                    testMonitor.wait();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                    testMonitor.t3Exception = new RuntimeException(e);
+                    throw (RuntimeException) testMonitor.t2Exception;
+                }
+            }
+        }
+        Document doc = SchemaBuilderCacheTest.setupDocument();
+        XmlSchemaCollection schemaCol = 
SchemaBuilderCacheTest.setupXmlSchemaCollection();
+        XmlSchema schema = schemaCol.read(doc, null);
+        if (schema == null) {
+            testMonitor.t3Exception = new Exception("Schema was null");
+        }
+        Map<String, SoftReference<XmlSchema>> threadHT = 
SchemaBuilderCacheTest.getThreadResolvedSchemaHashtable();
+        if (threadHT != null ) {
+            testMonitor.t3Exception = new Exception("Thread resolvedSchemas 
was not null");
+        }
+
+        
+    }
+    
+}


Reply via email to