Hi Andy,

super happy you drive this since it appears staled for too IMO!

I have few questions:
1. (not linked to the code) why are diff like it - ie the whole content is
+-? EOL?
2. wonder if we could avoid the static timer and just use constructor and
DestroyableResource or something like that to be bound to the container
lifecycle (will avoid surprises in tests)
3. why not having taken what is on master?

Thanks!

Romain Manni-Bucau
@rmannibucau <https://twitter.com/rmannibucau> |  Blog
<http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> |
LinkedIn <https://www.linkedin.com/in/rmannibucau> | Tomitriber
<http://www.tomitribe.com>

---------- Forwarded message ----------
From: <andygumbre...@apache.org>
Date: 2015-07-01 17:07 GMT-07:00
Subject: tomee git commit: Schedule purge of stale identities logout on
close or finalize
To: comm...@tomee.apache.org


Repository: tomee
Updated Branches:
  refs/heads/tomee-1.7.x ef7b52bdb -> 1ca627ccb


Schedule purge of stale identities
logout on close or finalize


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/1ca627cc
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/1ca627cc
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/1ca627cc

Branch: refs/heads/tomee-1.7.x
Commit: 1ca627ccb34315154d7df33b936490f4ef5969e8
Parents: ef7b52b
Author: AndyGee <andy...@gmx.de>
Authored: Thu Jul 2 02:07:21 2015 +0200
Committer: AndyGee <andy...@gmx.de>
Committed: Thu Jul 2 02:07:21 2015 +0200

----------------------------------------------------------------------
 .../core/security/AbstractSecurityService.java  |  49 +++
 .../openejb/client/AuthenticationRequest.java   |  18 +-
 .../apache/openejb/client/ClientSecurity.java   | 408 +++++++++----------
 .../org/apache/openejb/client/JNDIContext.java  |  63 ++-
 .../apache/openejb/client/ProtocolMetaData.java | 224 +++++-----
 5 files changed, 431 insertions(+), 331 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
----------------------------------------------------------------------
diff --git
a/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
b/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
index 8b8a3a6..721f2b0 100644
---
a/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
+++
b/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
@@ -45,11 +45,14 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;

@@ -60,6 +63,7 @@ import java.util.concurrent.ConcurrentHashMap;
  */
 public abstract class AbstractSecurityService implements
SecurityService<UUID>, ThreadContextListener,
BasicPolicyConfiguration.RoleResolver {

+    private static final Timer timer = new
Timer("AbstractSecurityService.Timer", true);
     private static final Map<UUID, Identity> identities = new
ConcurrentHashMap<UUID, Identity>();
     protected static final ThreadLocal<Identity> clientIdentity = new
ThreadLocal<Identity>();
     protected String defaultUser = "guest";
@@ -67,6 +71,42 @@ public abstract class AbstractSecurityService implements
SecurityService<UUID>,
     protected Subject defaultSubject;
     protected SecurityContext defaultContext;

+    static {
+        final long period =
Long.parseLong(SystemInstance.get().getProperty("tomee.security.identity.schedule",
"60000"));
+
+        //TODO - Get the default session timeout rather than this
+        final long defaultTimeout =
Long.parseLong(SystemInstance.get().getProperty("tomee.security.identity.timeout",
"1800000"));
+
+        timer.scheduleAtFixedRate(new TimerTask() {
+
+            /**
+             * Check for identities that have not been accessed within
timeout
+             */
+            @Override
+            public void run() {
+
+                Map.Entry<UUID, Identity> next;
+                final Iterator<Map.Entry<UUID, Identity>> iterator =
identities.entrySet().iterator();
+                while (iterator.hasNext()) {
+                    next = iterator.next();
+                    final Identity value = next.getValue();
+                    long timeout = value.getTimeout();
+
+                    if (0 == timeout) {
+                        timeout = defaultTimeout;
+                    }
+
+                    if (timeout > 0) {
+                        if (System.currentTimeMillis() -
value.getLastAccess() > timeout) {
+                            iterator.remove();
+                        }
+                    }
+                }
+
+            }
+        }, period, period);
+    }
+
     public AbstractSecurityService() {
         this(BasicJaccProvider.class.getName());
     }
@@ -395,6 +435,7 @@ public abstract class AbstractSecurityService
implements SecurityService<UUID>,
     protected static class Identity implements Serializable {

         private long lastAccess;
+        private long timeout = 0;
         private final Subject subject;
         private final UUID token;

@@ -426,6 +467,14 @@ public abstract class AbstractSecurityService
implements SecurityService<UUID>,
         public long getLastAccess() {
             return lastAccess;
         }
+
+        public void setTimeout(final long timeout) {
+            this.timeout = timeout;
+        }
+
+        public long getTimeout() {
+            return timeout;
+        }
     }

     public static class Group implements java.security.acl.Group {

http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
----------------------------------------------------------------------
diff --git
a/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
b/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
index ea49446..f2defdd 100644
---
a/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
+++
b/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
@@ -22,7 +22,11 @@ import java.io.ObjectOutput;

 public class AuthenticationRequest implements Request {

-    private static final long serialVersionUID = 7009531340098948330L;
+    /**
+     * Never change this, use #metaData for version
+     */
+    private static final long serialVersionUID = 7009531340198948330L;
+
     private transient String realm;
     private transient String username;
     private transient String credentials;
@@ -41,6 +45,10 @@ public class AuthenticationRequest implements Request {
         this(null, principal, credentials, timeout);
     }

+    public AuthenticationRequest(final String securityRealm, final String
username, final String password) {
+        this(securityRealm, username, password, 0);
+    }
+
     public AuthenticationRequest(final String realm, final String
principal, final String credentials, final long timeout) {
         this.realm = realm;
         this.username = principal;
@@ -87,13 +95,13 @@ public class AuthenticationRequest implements Request {
      */
     @Override
     public void readExternal(final ObjectInput in) throws IOException,
ClassNotFoundException {
-        final byte version = in.readByte(); // future use
+        in.readByte(); // Not used @see #metaData

         realm = (String) in.readObject();
         username = (String) in.readObject();
         credentials = (String) in.readObject();

-        if (version > 1) {
+        if (null == metaData || metaData.isAtLeast(4, 7)) {
             timeout = in.readLong();
             logout = in.readBoolean();
         }
@@ -104,8 +112,8 @@ public class AuthenticationRequest implements Request {
      */
     @Override
     public void writeExternal(final ObjectOutput out) throws IOException {
-        // write out the version of the serialized data for future use
-        out.writeByte(2);
+        // Not used, but must be written @see #metaData
+        out.writeByte(1);

         out.writeObject(realm);
         out.writeObject(username);

http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java
----------------------------------------------------------------------
diff --git
a/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java
b/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java
index 99cacd1..1990958 100644
---
a/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java
+++
b/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java
@@ -1,204 +1,204 @@
-/**
- *
- * 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.openejb.client;
-
-import javax.security.auth.login.FailedLoginException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.rmi.RemoteException;
-
-public class ClientSecurity {
-
-    public static final String IDENTITY_RESOLVER_STRATEGY =
"openejb.client.identityResolver";
-
-    private static ServerMetaData server;
-    private static IdentityResolver identityResolver;
-    private static Object staticClientIdentity;
-    private static final InheritableThreadLocal<Object>
threadClientIdentity = new InheritableThreadLocal<Object>();
-
-    static {
-        // determine the server uri
-        final String serverUri = System.getProperty("openejb.server.uri");
-
-        if (serverUri != null) {
-            // determine the server location
-            try {
-                final URI location = new URI(serverUri);
-                server = new ServerMetaData(location);
-            } catch (final Exception e) {
-                if (!serverUri.contains("://")) {
-                    try {
-                        final URI location = new URI("oejb://" +
serverUri);
-                        server = new ServerMetaData(location);
-                    } catch (final URISyntaxException ignored) {
-                    }
-                }
-            }
-        }
-    }
-
-    public static ServerMetaData getServer() {
-        return server;
-    }
-
-    public static void setServer(final ServerMetaData server) {
-        ClientSecurity.server = server;
-    }
-
-    /**
-     * Login the spedified user using the specified password.  This is a
global login for the
-     * entire Java Virtural Machine.  If you would like to have a thread
scoped login, use
-     * ClientSecurity.login(username, password, true);
-     * </p>
-     * This is the equivalent of ClientSecurity.login(username, password,
false);
-     *
-     * @param username the user to login
-     * @param password the password for the user
-     * @throws FailedLoginException if the username and password
combination are not valid or
-     *                              if there is a problem communiating
with the server
-     */
-    public static void login(final String username, final String password)
throws FailedLoginException {
-        login(username, password, false);
-    }
-
-    /**
-     * Login the spedified user using the specified password either
globally for the
-     * entire Java Virtural Machine or scoped to the thread.
-     * </p>
-     * When using thread scoped login, you should logout in a finally
block.  This particularly
-     * when using thread pools.  If a thread is returned to the pool with
a login attached to the
-     * thread the next user of that thread will inherit the thread scoped
login.
-     *
-     * @param username     the user to login
-     * @param password     the password for the user
-     * @param threadScoped if true the login is scoped to the thread;
otherwise the login is global
-     *                     for the entire Java Virtural Machine
-     * @throws FailedLoginException if the username and password
combination are not valid or
-     *                              if there is a problem communiating
with the server
-     */
-    public static void login(final String username, final String password,
final boolean threadScoped) throws FailedLoginException {
-        final Object clientIdentity = directAuthentication(username,
password, server);
-        if (threadScoped) {
-            threadClientIdentity.set(clientIdentity);
-        } else {
-            staticClientIdentity = clientIdentity;
-        }
-        identityResolver = new SimpleIdentityResolver();
-    }
-
-    /**
-     * Clears the thread and global login data.
-     */
-    public static void logout() {
-        threadClientIdentity.set(null);
-        staticClientIdentity = null;
-    }
-
-    /**
-     * This is a helper method for login modules. Directly authenticates
with the server using the specified
-     * username and password returning the identity token for the client.
This methods does not store the
-     * identity token and the caller must arrange for the to be available
to the OpenEJB proxies via an
-     * IdentityResolver.
-     *
-     * @param username the username for authentication
-     * @param password the password for authentication
-     * @param server   ServerMetaData
-     * @return the client identity token
-     * @throws FailedLoginException if the username password combination
is not valid
-     */
-    public static Object directAuthentication(final String username, final
String password, final ServerMetaData server) throws FailedLoginException {
-        return directAuthentication(null, username, password, server);
-    }
-
-    public static Object directAuthentication(final String securityRealm,
final String username, final String password, final ServerMetaData server)
throws FailedLoginException {
-        // authenticate
-        final AuthenticationRequest authReq = new
AuthenticationRequest(securityRealm, username, password);
-        final AuthenticationResponse authRes;
-        try {
-            authRes = (AuthenticationResponse) Client.request(authReq, new
AuthenticationResponse(), server);
-        } catch (final RemoteException e) {
-            throw (FailedLoginException) new FailedLoginException("Unable
to authenticate with server " + server).initCause(e);
-        }
-
-        // check the response
-        if (authRes.getResponseCode() != ResponseCodes.AUTH_GRANTED) {
-            throw (FailedLoginException) new FailedLoginException("This
principal is not authenticated.").initCause(authRes.getDeniedCause());
-        }
-
-        // return the response object
-        return authRes.getIdentity().getClientIdentity();
-    }
-
-    public static Object getIdentity() {
-        return getIdentityResolver().getIdentity();
-    }
-
-    public static IdentityResolver getIdentityResolver() {
-        if (identityResolver == null) {
-            final String strategy =
System.getProperty(IDENTITY_RESOLVER_STRATEGY);
-            if (strategy == null) {
-                identityResolver = new JaasIdentityResolver();
-            } else {
-                // find the strategy class
-                final ResourceFinder finder = new
ResourceFinder("META-INF/");
-                final Class identityResolverClass;
-                try {
-                    identityResolverClass =
finder.findClass(IdentityResolver.class.getName() + "/" + strategy);
-                } catch (final Exception e) {
-                    throw new IllegalArgumentException("Could not find
client identity strategy '" + strategy + "'");
-                }
-
-                // verify the interface
-                if
(!IdentityResolver.class.isAssignableFrom(identityResolverClass)) {
-                    throw new IllegalArgumentException("Client identity
strategy '" + strategy + "' " +
-                        "class '" + identityResolverClass.getName() + "'
does not implement the " +
-                        "interface '" +
IdentityResolver.class.getSimpleName() + "'");
-                }
-
-                // create the class
-                try {
-                    identityResolver = (IdentityResolver)
identityResolverClass.newInstance();
-                } catch (final Exception e) {
-                    throw new IllegalArgumentException("Unable to create
client identity strategy '" + strategy + "' " +
-                        "class '" + identityResolverClass.getName() + "'",
e);
-                }
-            }
-
-        }
-        return identityResolver;
-    }
-
-    public static void setIdentityResolver(final IdentityResolver
identityResolver) {
-        ClientSecurity.identityResolver = identityResolver;
-    }
-
-    private ClientSecurity() {
-    }
-
-    public static class SimpleIdentityResolver implements IdentityResolver
{
-
-        @Override
-        public Object getIdentity() {
-            Object clientIdentity = threadClientIdentity.get();
-            if (clientIdentity == null) {
-                clientIdentity = staticClientIdentity;
-            }
-            return clientIdentity;
-        }
-    }
-}
+/**
+ *
+ * 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.openejb.client;
+
+import javax.security.auth.login.FailedLoginException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.rmi.RemoteException;
+
+public class ClientSecurity {
+
+    public static final String IDENTITY_RESOLVER_STRATEGY =
"openejb.client.identityResolver";
+
+    private static ServerMetaData server;
+    private static IdentityResolver identityResolver;
+    private static Object staticClientIdentity;
+    private static final InheritableThreadLocal<Object>
threadClientIdentity = new InheritableThreadLocal<Object>();
+
+    static {
+        // determine the server uri
+        final String serverUri = System.getProperty("openejb.server.uri");
+
+        if (serverUri != null) {
+            // determine the server location
+            try {
+                final URI location = new URI(serverUri);
+                server = new ServerMetaData(location);
+            } catch (final Exception e) {
+                if (!serverUri.contains("://")) {
+                    try {
+                        final URI location = new URI("oejb://" +
serverUri);
+                        server = new ServerMetaData(location);
+                    } catch (final URISyntaxException ignored) {
+                    }
+                }
+            }
+        }
+    }
+
+    public static ServerMetaData getServer() {
+        return server;
+    }
+
+    public static void setServer(final ServerMetaData server) {
+        ClientSecurity.server = server;
+    }
+
+    /**
+     * Login the spedified user using the specified password.  This is a
global login for the
+     * entire Java Virtural Machine.  If you would like to have a thread
scoped login, use
+     * ClientSecurity.login(username, password, true);
+     * </p>
+     * This is the equivalent of ClientSecurity.login(username, password,
false);
+     *
+     * @param username the user to login
+     * @param password the password for the user
+     * @throws FailedLoginException if the username and password
combination are not valid or
+     *                              if there is a problem communiating
with the server
+     */
+    public static void login(final String username, final String password)
throws FailedLoginException {
+        login(username, password, false);
+    }
+
+    /**
+     * Login the spedified user using the specified password either
globally for the
+     * entire Java Virtural Machine or scoped to the thread.
+     * </p>
+     * When using thread scoped login, you should logout in a finally
block.  This particularly
+     * when using thread pools.  If a thread is returned to the pool with
a login attached to the
+     * thread the next user of that thread will inherit the thread scoped
login.
+     *
+     * @param username     the user to login
+     * @param password     the password for the user
+     * @param threadScoped if true the login is scoped to the thread;
otherwise the login is global
+     *                     for the entire Java Virtural Machine
+     * @throws FailedLoginException if the username and password
combination are not valid or
+     *                              if there is a problem communiating
with the server
+     */
+    public static void login(final String username, final String password,
final boolean threadScoped) throws FailedLoginException {
+        final Object clientIdentity = directAuthentication(username,
password, server);
+        if (threadScoped) {
+            threadClientIdentity.set(clientIdentity);
+        } else {
+            staticClientIdentity = clientIdentity;
+        }
+        identityResolver = new SimpleIdentityResolver();
+    }
+
+    /**
+     * Clears the thread and global login data.
+     */
+    public static void logout() {
+        threadClientIdentity.set(null);
+        staticClientIdentity = null;
+    }
+
+    /**
+     * This is a helper method for login modules. Directly authenticates
with the server using the specified
+     * username and password returning the identity token for the client.
This methods does not store the
+     * identity token and the caller must arrange for the to be available
to the OpenEJB proxies via an
+     * IdentityResolver.
+     *
+     * @param username the username for authentication
+     * @param password the password for authentication
+     * @param server   ServerMetaData
+     * @return the client identity token
+     * @throws FailedLoginException if the username password combination
is not valid
+     */
+    public static Object directAuthentication(final String username, final
String password, final ServerMetaData server) throws FailedLoginException {
+        return directAuthentication(null, username, password, server);
+    }
+
+    public static Object directAuthentication(final String securityRealm,
final String username, final String password, final ServerMetaData server)
throws FailedLoginException {
+        // authenticate
+        final AuthenticationRequest authReq = new
AuthenticationRequest(securityRealm, username, password);
+        final AuthenticationResponse authRes;
+        try {
+            authRes = (AuthenticationResponse) Client.request(authReq, new
AuthenticationResponse(), server);
+        } catch (final RemoteException e) {
+            throw (FailedLoginException) new FailedLoginException("Unable
to authenticate with server " + server).initCause(e);
+        }
+
+        // check the response
+        if (authRes.getResponseCode() != ResponseCodes.AUTH_GRANTED) {
+            throw (FailedLoginException) new FailedLoginException("This
principal is not authenticated.").initCause(authRes.getDeniedCause());
+        }
+
+        // return the response object
+        return authRes.getIdentity().getClientIdentity();
+    }
+
+    public static Object getIdentity() {
+        return getIdentityResolver().getIdentity();
+    }
+
+    public static IdentityResolver getIdentityResolver() {
+        if (identityResolver == null) {
+            final String strategy =
System.getProperty(IDENTITY_RESOLVER_STRATEGY);
+            if (strategy == null) {
+                identityResolver = new JaasIdentityResolver();
+            } else {
+                // find the strategy class
+                final ResourceFinder finder = new
ResourceFinder("META-INF/");
+                final Class identityResolverClass;
+                try {
+                    identityResolverClass =
finder.findClass(IdentityResolver.class.getName() + "/" + strategy);
+                } catch (final Exception e) {
+                    throw new IllegalArgumentException("Could not find
client identity strategy '" + strategy + "'");
+                }
+
+                // verify the interface
+                if
(!IdentityResolver.class.isAssignableFrom(identityResolverClass)) {
+                    throw new IllegalArgumentException("Client identity
strategy '" + strategy + "' " +
+                        "class '" + identityResolverClass.getName() + "'
does not implement the " +
+                        "interface '" +
IdentityResolver.class.getSimpleName() + "'");
+                }
+
+                // create the class
+                try {
+                    identityResolver = (IdentityResolver)
identityResolverClass.newInstance();
+                } catch (final Exception e) {
+                    throw new IllegalArgumentException("Unable to create
client identity strategy '" + strategy + "' " +
+                        "class '" + identityResolverClass.getName() + "'",
e);
+                }
+            }
+
+        }
+        return identityResolver;
+    }
+
+    public static void setIdentityResolver(final IdentityResolver
identityResolver) {
+        ClientSecurity.identityResolver = identityResolver;
+    }
+
+    private ClientSecurity() {
+    }
+
+    public static class SimpleIdentityResolver implements IdentityResolver
{
+
+        @Override
+        public Object getIdentity() {
+            Object clientIdentity = threadClientIdentity.get();
+            if (clientIdentity == null) {
+                clientIdentity = staticClientIdentity;
+            }
+            return clientIdentity;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
----------------------------------------------------------------------
diff --git
a/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
b/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
index 9b3b3b1..08e7537 100644
---
a/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
+++
b/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
@@ -56,6 +56,7 @@ import java.util.concurrent.RejectedExecutionHandler;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -65,6 +66,7 @@ import java.util.logging.Logger;
  */
 public class JNDIContext implements InitialContextFactory, Context {
     private static final Logger LOGGER =
Logger.getLogger("OpenEJB.client");
+    private static final AtomicBoolean isShutdown = new
AtomicBoolean(false);

     @SuppressWarnings("UnusedDeclaration")
     public static final String DEFAULT_PROVIDER_URL =
"ejbd://localhost:4201";
@@ -82,7 +84,6 @@ public class JNDIContext implements
InitialContextFactory, Context {
     private Hashtable env;
     private String moduleId;
     private ClientInstance clientIdentity;
-    private boolean authWithRequest = false;

     private static final ThreadPoolExecutor GLOBAL_CLIENT_POOL =
newExecutor(10, null);

@@ -99,7 +100,7 @@ public class JNDIContext implements
InitialContextFactory, Context {
             Runtime.getRuntime().addShutdownHook(new Thread() {
                 @Override
                 public void run() {
-                    waitEndOfTasks(GLOBAL_CLIENT_POOL);
+                    waitForShutdown(GLOBAL_CLIENT_POOL);
                 }
             });
         }
@@ -234,7 +235,8 @@ public class JNDIContext implements
InitialContextFactory, Context {
         final String userID = (String) env.get(Context.SECURITY_PRINCIPAL);
         final String psswrd = (String)
env.get(Context.SECURITY_CREDENTIALS);
         String providerUrl = (String) env.get(Context.PROVIDER_URL);
-        authWithRequest =
"true".equalsIgnoreCase(String.class.cast(env.get(AUTHENTICATE_WITH_THE_REQUEST)));
+
+        final boolean authWithRequest =
"true".equalsIgnoreCase(String.class.cast(env.get(AUTHENTICATE_WITH_THE_REQUEST)));
         moduleId = (String) env.get("openejb.client.moduleId");

         final URI location;
@@ -294,10 +296,14 @@ public class JNDIContext implements
InitialContextFactory, Context {
     private long getTimeout(final Hashtable env) {
         final Object o = env.get(IDENTITY_TIMEOUT);
         if (null != o) {
-
+            final Long l = Long.class.cast(o);
+            //noinspection ConstantConditions
+            if(null != l){
+                return l;
+            }
         }

-        return 0;
+        return 0L;
     }

     private static String getProperty(final Hashtable env, final String
key, final String defaultValue) {
@@ -388,6 +394,8 @@ public class JNDIContext implements
InitialContextFactory, Context {
     @Override
     public Object lookup(String name) throws NamingException {

+        checkState();
+
         if (name == null) {
             throw new InvalidNameException("The name cannot be null");
         } else if (name.equals("")) {
@@ -565,6 +573,9 @@ public class JNDIContext implements
InitialContextFactory, Context {
     @SuppressWarnings("unchecked")
     @Override
     public NamingEnumeration<NameClassPair> list(String name) throws
NamingException {
+
+        checkState();
+
         if (name == null) {
             throw new InvalidNameException("The name cannot be null");
         } else if (name.startsWith("java:")) {
@@ -724,17 +735,36 @@ public class JNDIContext implements
InitialContextFactory, Context {
         return "";
     }

+    private void checkState() throws NamingException {
+        if (isShutdown.get()) {
+            throw new NamingException("Context has been closed. Please
create a new instance.");
+        }
+    }
+
     @Override
     public void close() throws NamingException {
-        waitEndOfTasks(executorService);
+
+        if (isShutdown.getAndSet(true)) {
+            return;
+        }
+
+        waitForShutdown(executorService);

         final String userID = (String) env.get(Context.SECURITY_PRINCIPAL);
-        final String psswrd = (String)
env.get(Context.SECURITY_CREDENTIALS);
-        this.authenticate(userID, psswrd, true);
+
+        if (userID != null) {
+            final String psswrd = (String)
env.get(Context.SECURITY_CREDENTIALS);
+            final boolean logout = true;
+            try {
+                this.authenticate(userID, psswrd, logout);
+            } catch (final Exception ignore) {
+                //no-op
+            }
+        }
     }

-    private static void waitEndOfTasks(final ExecutorService executor) {
-        if (executor == null) {
+    private static void waitForShutdown(final ExecutorService executor) {
+        if (executor == null || executor.isShutdown()) {
             return;
         }

@@ -808,6 +838,15 @@ public class JNDIContext implements
InitialContextFactory, Context {
         return createSubcontext(name.toString());
     }

+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
     private static final class SimpleNameParser implements NameParser {

         private static final Properties PARSER_PROPERTIES = new
Properties();
@@ -834,6 +873,10 @@ public class JNDIContext implements
InitialContextFactory, Context {
         private final char[] password;
         private final long timeout;

+        public AuthenticationInfo(final String realm, final String user,
final char[] chars) {
+            this(realm, user, chars, 0);
+        }
+
         public AuthenticationInfo(final String realm, final String user,
final char[] password, final long timeout) {
             this.realm = realm;
             this.user = user;

http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java
----------------------------------------------------------------------
diff --git
a/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java
b/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java
index ccef38d..b19252b 100644
---
a/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java
+++
b/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java
@@ -1,112 +1,112 @@
-/**
- * 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.openejb.client;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-
-/**
- * OpenEJB Enterprise Javabean Protocol (OEJP)
- * <p/>
- * OEJP uses a "<major>.<minor>" numbering scheme to indicate versions of
the protocol.
- * <p/>
- * Protocol-Version   = "OEJP" "/" 1*DIGIT "." 1*DIGIT
- * <p/>
- * Some compatability is guaranteed with the major part of the version
number.
- *
- * @version $Revision$ $Date$
- */
-@SuppressWarnings("UnusedDeclaration")
-public class ProtocolMetaData {
-
-    public static final String VERSION = "4.6";
-
-    private static final String OEJB = "OEJP";
-    private transient String id;
-    private transient int major;
-    private transient int minor;
-
-    public ProtocolMetaData() {
-        init(OEJB + "/" + VERSION);
-    }
-
-    public ProtocolMetaData(final String version) {
-        init(OEJB + "/" + version);
-    }
-
-    private void init(final String spec) {
-
-        if (!spec.matches("^OEJP/[0-9]\\.[0-9]$")) {
-            throw new RuntimeException("Protocol version spec must follow
format [ \"OEJB\" \"/\" 1*DIGIT \".\" 1*DIGIT ] - " + spec);
-        }
-
-        final char[] chars = new char[8];
-        spec.getChars(0, chars.length, chars, 0);
-
-        this.id = new String(chars, 0, 4);
-        this.major = Integer.parseInt(new String(chars, 5, 1));
-        this.minor = Integer.parseInt(new String(chars, 7, 1));
-    }
-
-    public boolean isAtLeast(final int major, final int minor) {
-        return this.major >= major && (this.major != major || this.minor
>= minor);
-    }
-
-    public String getId() {
-        return id;
-    }
-
-    public int getMajor() {
-        return major;
-    }
-
-    public int getMinor() {
-        return minor;
-    }
-
-    public String getVersion() {
-        return major + "." + minor;
-    }
-
-    public String getSpec() {
-        return id + "/" + major + "." + minor;
-    }
-
-    public void writeExternal(final OutputStream out) throws IOException {
-        out.write(getSpec().getBytes("UTF-8"));
-        out.flush();
-    }
-
-    public void readExternal(final InputStream in) throws IOException {
-        final byte[] spec = new byte[8];
-        for (int i = 0; i < spec.length; i++) {
-            spec[i] = (byte) in.read();
-            if (spec[i] == -1) {
-                throw new EOFException("Unable to read protocol version.
Reached the end of the stream.");
-            }
-        }
-        try {
-            init(new String(spec, "UTF-8"));
-        } catch (final Throwable e) {
-            throw new IOException("Failed to read spec: " +
Arrays.toString(spec), e);
-        }
-    }
-}
+/**
+ * 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.openejb.client;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * OpenEJB Enterprise Javabean Protocol (OEJP)
+ * <p/>
+ * OEJP uses a "<major>.<minor>" numbering scheme to indicate versions of
the protocol.
+ * <p/>
+ * Protocol-Version   = "OEJP" "/" 1*DIGIT "." 1*DIGIT
+ * <p/>
+ * Some compatability is guaranteed with the major part of the version
number.
+ *
+ * @version $Revision$ $Date$
+ */
+@SuppressWarnings("UnusedDeclaration")
+public class ProtocolMetaData {
+
+    public static final String VERSION = "4.7";
+
+    private static final String OEJB = "OEJP";
+    private transient String id;
+    private transient int major;
+    private transient int minor;
+
+    public ProtocolMetaData() {
+        init(OEJB + "/" + VERSION);
+    }
+
+    public ProtocolMetaData(final String version) {
+        init(OEJB + "/" + version);
+    }
+
+    private void init(final String spec) {
+
+        if (!spec.matches("^OEJP/[0-9]\\.[0-9]$")) {
+            throw new RuntimeException("Protocol version spec must follow
format [ \"OEJB\" \"/\" 1*DIGIT \".\" 1*DIGIT ] - " + spec);
+        }
+
+        final char[] chars = new char[8];
+        spec.getChars(0, chars.length, chars, 0);
+
+        this.id = new String(chars, 0, 4);
+        this.major = Integer.parseInt(new String(chars, 5, 1));
+        this.minor = Integer.parseInt(new String(chars, 7, 1));
+    }
+
+    public boolean isAtLeast(final int major, final int minor) {
+        return this.major >= major && (this.major != major || this.minor
>= minor);
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public int getMajor() {
+        return major;
+    }
+
+    public int getMinor() {
+        return minor;
+    }
+
+    public String getVersion() {
+        return major + "." + minor;
+    }
+
+    public String getSpec() {
+        return id + "/" + major + "." + minor;
+    }
+
+    public void writeExternal(final OutputStream out) throws IOException {
+        out.write(getSpec().getBytes("UTF-8"));
+        out.flush();
+    }
+
+    public void readExternal(final InputStream in) throws IOException {
+        final byte[] spec = new byte[8];
+        for (int i = 0; i < spec.length; i++) {
+            spec[i] = (byte) in.read();
+            if (spec[i] == -1) {
+                throw new EOFException("Unable to read protocol version.
Reached the end of the stream.");
+            }
+        }
+        try {
+            init(new String(spec, "UTF-8"));
+        } catch (final Throwable e) {
+            throw new IOException("Failed to read spec: " +
Arrays.toString(spec), e);
+        }
+    }
+}

Reply via email to