You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by dk...@apache.org on 2013/04/04 17:55:23 UTC

svn commit: r1464607 - in /cxf/branches/2.6.x-fixes/rt/transports/http/src: main/java/org/apache/cxf/transport/http/ test/java/org/apache/cxf/transport/http/

Author: dkulp
Date: Thu Apr  4 15:55:23 2013
New Revision: 1464607

URL: http://svn.apache.org/r1464607
Log:
Merged revisions 1464600 via  git cherry-pick from
https://svn.apache.org/repos/asf/cxf/branches/2.7.x-fixes

........
  r1464600 | dkulp | 2013-04-04 11:49:54 -0400 (Thu, 04 Apr 2013) | 10 lines

  Merged revisions 1464598 via  git cherry-pick from
  https://svn.apache.org/repos/asf/cxf/trunk

  ........
    r1464598 | dkulp | 2013-04-04 11:40:01 -0400 (Thu, 04 Apr 2013) | 2 lines

    [CXF-4529] Work a bit harder to get the authentcators cleaned out.

  ........

........

Added:
    cxf/branches/2.6.x-fixes/rt/transports/http/src/test/java/org/apache/cxf/transport/http/CXFAuthenticatorCleanupTest.java
Modified:
    cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/CXFAuthenticator.java
    cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ReferencingAuthenticator.java

Modified: cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/CXFAuthenticator.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/CXFAuthenticator.java?rev=1464607&r1=1464606&r2=1464607&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/CXFAuthenticator.java (original)
+++ cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/CXFAuthenticator.java Thu Apr  4 15:55:23 2013
@@ -38,21 +38,28 @@ import org.apache.cxf.transport.Conduit;
  * 
  */
 public class CXFAuthenticator extends Authenticator {
-    static boolean setup;
-    private static final CXFAuthenticator INSTANCE = new CXFAuthenticator();
+    static CXFAuthenticator instance;
     
     
     public CXFAuthenticator() {
     }
-
+    
     public static synchronized void addAuthenticator() { 
-        if (!setup) {
+        if (instance == null) {
+            instance = new CXFAuthenticator();
             Authenticator wrapped = null;
             for (final Field f : Authenticator.class.getDeclaredFields()) {
                 if (f.getType().equals(Authenticator.class)) {
                     ReflectionUtil.setAccessible(f);
                     try {
                         wrapped = (Authenticator)f.get(null);
+                        if (wrapped != null 
+                            && wrapped.getClass().getName().equals(ReferencingAuthenticator.class.getName())) {
+                            Method m = wrapped.getClass().getMethod("check");
+                            m.setAccessible(true);
+                            m.invoke(wrapped);
+                        }
+                        wrapped = (Authenticator)f.get(null);
                     } catch (Exception e) {
                         //ignore
                     }
@@ -60,23 +67,25 @@ public class CXFAuthenticator extends Au
             }
             
             try {
-                InputStream ins = ReferencingAuthenticator.class.getResourceAsStream("ReferencingAuthenticator.class");
-                final byte b[] = IOUtils.readBytesFromStream(ins);
                 ClassLoader loader = new URLClassLoader(new URL[0], ClassLoader.getSystemClassLoader());
                 Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, 
                                                                byte[].class, Integer.TYPE, Integer.TYPE);
+                
+                InputStream ins = ReferencingAuthenticator.class
+                        .getResourceAsStream("ReferencingAuthenticator.class");
+                byte b[] = IOUtils.readBytesFromStream(ins);
+                
                 ReflectionUtil.setAccessible(m).invoke(loader, ReferencingAuthenticator.class.getName(),
                                                        b, 0, b.length);
                 Class<?> cls = loader.loadClass(ReferencingAuthenticator.class.getName());
                 Authenticator auth = (Authenticator)cls.getConstructor(Authenticator.class, Authenticator.class)
-                    .newInstance(INSTANCE, wrapped);
+                    .newInstance(instance, wrapped);
                 
                 Authenticator.setDefault(auth);
             } catch (Throwable t) {
                 //ignore
                 t.printStackTrace();
             }
-            setup = true;
         }
     }
     

Modified: cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ReferencingAuthenticator.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ReferencingAuthenticator.java?rev=1464607&r1=1464606&r2=1464607&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ReferencingAuthenticator.java (original)
+++ cxf/branches/2.6.x-fixes/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ReferencingAuthenticator.java Thu Apr  4 15:55:23 2013
@@ -18,7 +18,8 @@
  */
 package org.apache.cxf.transport.http;
 
-import java.lang.ref.SoftReference;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -26,14 +27,19 @@ import java.net.Authenticator;
 import java.net.PasswordAuthentication;
 
 public class ReferencingAuthenticator extends Authenticator {
-    SoftReference<Authenticator> auth;
-    Authenticator wrapped;
+    final Reference<Authenticator> auth;
+    final Authenticator wrapped;
     public ReferencingAuthenticator(Authenticator cxfauth, Authenticator wrapped) {
-        this.auth = new SoftReference<Authenticator>(cxfauth);
+        this.auth = new WeakReference<Authenticator>(cxfauth);
         this.wrapped = wrapped;
     }
+
     @Override
     protected PasswordAuthentication getPasswordAuthentication() {
+        Authenticator cxfauth = auth.get();
+        if (cxfauth == null) {
+            remove();
+        }
         PasswordAuthentication pauth = null;
         if (wrapped != null) {
             try {
@@ -45,22 +51,71 @@ public class ReferencingAuthenticator ex
                 pauth = null;
             }
         }
+        if (cxfauth != null) {
+            try {
+                pauth = tryWith(cxfauth);
+            } catch (Exception e1) {
+                pauth = null;
+            }
+        }
+        return pauth;
+    }
+    
+    public final void check() {
         Authenticator cxfauth = auth.get();
         if (cxfauth == null) {
+            remove();
+        }
+        if (wrapped != null && wrapped.getClass().getName().equals(ReferencingAuthenticator.class.getName())) {
             try {
-                Authenticator.setDefault(wrapped);
+                Method m = wrapped.getClass().getMethod("check");
+                m.setAccessible(true);
+                m.invoke(wrapped);
             } catch (Throwable t) {
                 //ignore
             }
-        } else {
-            try {
-                pauth = tryWith(cxfauth);
-            } catch (Exception e1) {
-                pauth = null;
+        }
+    }
+    private void remove() {
+        try {
+            for (final Field f : Authenticator.class.getDeclaredFields()) {
+                if (f.getType().equals(Authenticator.class)) {
+                    try {
+                        f.setAccessible(true);
+                        Authenticator o = (Authenticator)f.get(null);
+                        if (o == this) {
+                            //this is at the root of any chain of authenticators
+                            Authenticator.setDefault(wrapped);
+                        } else {
+                            removeFromChain(o);
+                        }
+                    } catch (Exception e) {
+                        //ignore
+                    }
+                }
             }
+        } catch (Throwable t) {
+            //ignore
         }
-        return pauth;
-    }  
+    }
+    private void removeFromChain(Authenticator a) {
+        try {
+            if (a.getClass().getName().equals(ReferencingAuthenticator.class.getName())) {
+                //multiple referencing authenticators, we can remove ourself
+                Field f2 = a.getClass().getDeclaredField("wrapped");
+                f2.setAccessible(true);
+                Authenticator a2 = (Authenticator)f2.get(a);
+                if (a2 == this) {
+                    f2.set(a, wrapped);
+                } else {
+                    removeFromChain(a2);
+                }
+            }
+        } catch (Throwable t) {
+            //ignore
+        }
+    }
+    
     PasswordAuthentication tryWith(Authenticator a) throws Exception {
         if (a == null) {
             return null;

Added: cxf/branches/2.6.x-fixes/rt/transports/http/src/test/java/org/apache/cxf/transport/http/CXFAuthenticatorCleanupTest.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/transports/http/src/test/java/org/apache/cxf/transport/http/CXFAuthenticatorCleanupTest.java?rev=1464607&view=auto
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/transports/http/src/test/java/org/apache/cxf/transport/http/CXFAuthenticatorCleanupTest.java (added)
+++ cxf/branches/2.6.x-fixes/rt/transports/http/src/test/java/org/apache/cxf/transport/http/CXFAuthenticatorCleanupTest.java Thu Apr  4 15:55:23 2013
@@ -0,0 +1,146 @@
+/**
+ * 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 org.apache.cxf.transport.http;
+
+import java.net.Authenticator;
+import java.net.InetAddress;
+import java.net.PasswordAuthentication;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * 
+ */
+public class CXFAuthenticatorCleanupTest {
+
+    /**
+     * 
+     */
+    public CXFAuthenticatorCleanupTest() {
+    }
+
+    
+    @Test
+    public void runCleanupTestStrongRef() throws Exception {
+        final List<Integer> traceLengths = new ArrayList<Integer>();
+        
+        //create a chain of CXFAuthenticators, strongly referenced to prevent cleanups
+        Authenticator.setDefault(new Authenticator() {
+            protected PasswordAuthentication getPasswordAuthentication() {
+                traceLengths.add(Thread.currentThread().getStackTrace().length);
+                return super.getPasswordAuthentication();
+            }
+        });
+        
+        
+        InetAddress add = InetAddress.getLocalHost();
+        Authenticator.requestPasswordAuthentication("localhost", add,
+                                                    8080, "http", "hello", "http");
+        
+        List<CXFAuthenticator> list = new ArrayList<CXFAuthenticator>();
+        for (int x = 0; x < 20; x++) {
+            CXFAuthenticator.addAuthenticator();
+            list.add(CXFAuthenticator.instance);
+            CXFAuthenticator.instance = null;
+        }
+
+        Authenticator.requestPasswordAuthentication("localhost", add,
+                                                    8080, "http", "hello", "http");
+        for (int x = 9; x > 0; x -= 2) {
+            list.remove(x);
+        }
+        for (int x = 0; x < 10; x++) {
+            System.gc();
+            Authenticator.requestPasswordAuthentication("localhost", add,
+                                                        8080, "http", "hello", "http");
+        }
+        list.clear();
+        for (int x = 0; x < 10; x++) {
+            System.gc();
+            Authenticator.requestPasswordAuthentication("localhost", add,
+                                                        8080, "http", "hello", "http");
+        }
+        Assert.assertEquals(22, traceLengths.size());
+        //first trace would be just the raw authenticator above
+        int raw = traceLengths.get(0);
+        //second would be the trace with ALL the auths 
+        int all = traceLengths.get(1);
+        //after remove of 5 and some gc's
+        int some = traceLengths.get(11);
+        //after clear and gc's
+        int none = traceLengths.get(traceLengths.size() - 1);
+        
+        //System.out.println(traceLengths);
+        Assert.assertTrue(all > (raw + 20 * 3)); //all should be A LOT above raw
+        Assert.assertTrue(all > raw);
+        Assert.assertTrue(all > some);
+        Assert.assertTrue(some > none);
+        Assert.assertEquals(raw, none);
+    }
+    @Test
+    public void runCleanupTestWeakRef() throws Exception {
+        InetAddress add = InetAddress.getLocalHost();
+        final List<Integer> traceLengths = new ArrayList<Integer>();
+        //create a chain of CXFAuthenticators, strongly referenced to prevent cleanups
+        Authenticator.setDefault(new Authenticator() {
+            protected PasswordAuthentication getPasswordAuthentication() {
+                traceLengths.add(Thread.currentThread().getStackTrace().length);
+                return super.getPasswordAuthentication();
+            }
+        });
+        Authenticator.requestPasswordAuthentication("localhost", add,
+                                                    8080, "http", "hello", "http");
+        
+        
+        for (int x = 0; x < 20; x++) {
+            CXFAuthenticator.addAuthenticator();
+            CXFAuthenticator.instance = null;
+            System.gc();
+        }
+        CXFAuthenticator.addAuthenticator();
+        System.gc();       
+
+        Authenticator.requestPasswordAuthentication("localhost", add,
+                                                    8080, "http", "hello", "http");
+        CXFAuthenticator.instance = null;
+        for (int x = 0; x < 10; x++) {
+            System.gc();
+            Authenticator.requestPasswordAuthentication("localhost", add,
+                                                        8080, "http", "hello", "http");
+        }
+        Assert.assertEquals(12, traceLengths.size());
+        
+        //first trace would be just the raw authenticator above
+        int raw = traceLengths.get(0);
+        //second trace should still have an Authenticator added
+        int one = traceLengths.get(1);
+        //after clear and gc's
+        int none = traceLengths.get(traceLengths.size() - 1);
+        
+        //System.out.println(traceLengths);
+        Assert.assertTrue(one < (raw + (20 * 2))); //one should only be slightly above raw 
+        Assert.assertTrue(one > raw);
+        Assert.assertTrue(one > none);
+        Assert.assertEquals(raw, none);
+    }
+}