ONOS-3521: SM-ONOS performance improvement

Change-Id: I8643187f2ceb35f8e0701d9e7ddb10098f05b244
diff --git a/core/api/src/main/java/org/onosproject/security/AppGuard.java b/core/api/src/main/java/org/onosproject/security/AppGuard.java
index 4b80dfc..788fbcd 100644
--- a/core/api/src/main/java/org/onosproject/security/AppGuard.java
+++ b/core/api/src/main/java/org/onosproject/security/AppGuard.java
@@ -16,26 +16,102 @@
 
 package org.onosproject.security;
 
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
 
 import com.google.common.annotations.Beta;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Aids SM-ONOS to perform API-level permission checking.
  */
 @Beta
 public final class AppGuard {
-
     private AppGuard() {
     }
 
     /**
      * Checks if the caller has the required permission only when security-mode is enabled.
+     *
      * @param permission permission to be checked
      */
     public static void checkPermission(AppPermission.Type permission) {
+
         SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            System.getSecurityManager().checkPermission(new AppPermission(permission));
+        if (sm == null) {
+            return;
+        }
+
+        Object result = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
+            int contextHash = 0;
+            AccessControlContext context = AccessController.getContext();
+            Field f = null;
+            try {
+                f = context.getClass().getDeclaredField("context");
+
+                f.setAccessible(true);
+                ProtectionDomain[] domain = (ProtectionDomain[]) f.get(context);
+                for (ProtectionDomain pd : domain) {
+                    if (pd.getCodeSource() != null) {
+                        contextHash = contextHash ^ pd.getCodeSource().getLocation().hashCode();
+                    } else {
+                        return null;
+                    }
+                }
+                return contextHash;
+            } catch (NoSuchFieldException e) {
+                return null;
+            } catch (IllegalAccessException e) {
+                return null;
+            }
+        });
+
+        if (result == null) {
+            sm.checkPermission(new AppPermission(permission));
+        } else {
+            AppPermission perm = new AppPermission(permission);
+            int hash = ((int) result) ^ perm.hashCode();
+            PermissionCheckCache.getInstance().checkCache(hash, perm);
         }
     }
+
+
+    private static final class PermissionCheckCache {
+
+        private static final Cache<Integer, Boolean> CACHE = CacheBuilder.newBuilder()
+                .maximumSize(1000)
+                .expireAfterAccess(10, TimeUnit.MINUTES)
+                .build();
+
+        private PermissionCheckCache() {
+        }
+
+        private static class SingletonHelper {
+            private static final PermissionCheckCache INSTANCE = new PermissionCheckCache();
+        }
+
+        public static PermissionCheckCache getInstance() {
+            return SingletonHelper.INSTANCE;
+        }
+
+        public static void checkCache(int key, AppPermission perm) {
+            try {
+                CACHE.get(key, () -> {
+                    System.getSecurityManager().checkPermission(perm);
+                    return true;
+                });
+            } catch (ExecutionException e) {
+                System.getSecurityManager().checkPermission(perm);
+            }
+        }
+    }
+
 }
+
diff --git a/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java b/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java
index 30d143c..fee1ae9 100644
--- a/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java
+++ b/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java
@@ -74,6 +74,4 @@
      * @return Map of list of permissions sorted by permission type
      */
     Map<Integer, List<Permission>> getPrintableRequestedPermissions(ApplicationId appId);
-
-
 }
diff --git a/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java b/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java
index b043765..1fbb7c8 100644
--- a/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java
+++ b/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java
@@ -54,11 +54,12 @@
 import org.onosproject.security.SecurityAdminService;
 import org.onosproject.store.service.StorageAdminService;
 import org.onosproject.store.service.StorageService;
-import org.osgi.framework.BundlePermission;
-import org.osgi.framework.CapabilityPermission;
 import org.osgi.framework.ServicePermission;
-import org.osgi.framework.PackagePermission;
+import org.osgi.framework.AdminPermission;
 import org.osgi.framework.AdaptPermission;
+import org.osgi.framework.CapabilityPermission;
+import org.osgi.framework.BundlePermission;
+import org.osgi.framework.PackagePermission;
 import org.osgi.service.cm.ConfigurationPermission;
 
 import javax.net.ssl.SSLPermission;
@@ -68,6 +69,7 @@
 import javax.sound.sampled.AudioPermission;
 import java.io.FilePermission;
 import java.io.SerializablePermission;
+import java.lang.reflect.ReflectPermission;
 import java.net.NetPermission;
 import java.net.SocketPermission;
 import java.security.Permissions;
@@ -159,6 +161,7 @@
         permSet.add(new PackagePermission("*", PackagePermission.IMPORT));
         permSet.add(new AdaptPermission("*", AdaptPermission.ADAPT));
         permSet.add(new ConfigurationPermission("*", ConfigurationPermission.CONFIGURE));
+        permSet.add(new AdminPermission("*", AdminPermission.METADATA));
         return permSet;
     }
 
@@ -359,6 +362,12 @@
         } else if (permission instanceof ServicePermission) {
             return new org.onosproject.security.Permission(
                     ServicePermission.class.getName(), permission.getName(), permission.getActions());
+        } else if (permission instanceof AdminPermission) {
+            return new org.onosproject.security.Permission(
+                    AdminPermission.class.getName(), permission.getName(), permission.getActions());
+        } else if (permission instanceof ConfigurationPermission) {
+            return new org.onosproject.security.Permission(
+                    ConfigurationPermission.class.getName(), permission.getName(), permission.getActions());
         }
         return null;
     }
@@ -416,10 +425,16 @@
             return new PackagePermission(name, actions);
         } else if (ServicePermission.class.getName().equals(classname)) {
             return new ServicePermission(name, actions);
+        } else if (AdminPermission.class.getName().equals(classname)) {
+            return new AdminPermission(name, actions);
+        } else if (ConfigurationPermission.class.getName().equals(classname)) {
+            return new ConfigurationPermission(name, actions);
+        } else if (ReflectPermission.class.getName().equals(classname)) {
+            return new ReflectPermission(name, actions);
         }
 
         //AllPermission, SecurityPermission, UnresolvedPermission
-        //AWTPermission, AdminPermission(osgi), ReflectPermission not allowed
+        //AWTPermission,  ReflectPermission not allowed
         return null;
 
     }
@@ -444,5 +459,4 @@
         }
         return permissions;
     }
-}
-
+}
\ No newline at end of file
diff --git a/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java b/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java
index 325f49b..f928dd6 100644
--- a/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java
+++ b/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java
@@ -92,16 +92,12 @@
 
     private PermissionAdmin permissionAdmin = getPermissionAdmin();
 
-
     @Activate
     public void activate() {
 
         eventDispatcher.addSink(SecurityModeEvent.class, listenerRegistry);
-        // add Listeners
         logReaderService.addLogListener(securityLogListener);
 
-        store.setDelegate(delegate);
-
         if (System.getSecurityManager() == null) {
             log.warn("J2EE security manager is disabled.");
             deactivate();
@@ -112,6 +108,7 @@
             deactivate();
             return;
         }
+        store.setDelegate(delegate);
 
         log.info("Security-Mode Started");
     }
@@ -302,4 +299,6 @@
         return FrameworkUtil.getBundle(this.getClass()).getBundleContext();
 
     }
+
+
 }
\ No newline at end of file
diff --git a/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java b/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java
index 925298c..b880ffd 100644
--- a/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java
+++ b/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java
@@ -303,14 +303,4 @@
         }
         return locations;
     }
-
-    @Override
-    public void setDelegate(SecurityModeStoreDelegate delegate) {
-        super.setDelegate(delegate);
-    }
-
-    @Override
-    public void unsetDelegate(SecurityModeStoreDelegate delegate) {
-        super.setDelegate(delegate);
-    }
 }
diff --git a/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java b/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java
index 7e6b653..e69971c 100644
--- a/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java
+++ b/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java
@@ -101,4 +101,5 @@
      * @param permissionSet array of PermissionInfo
      */
     void acceptPolicy(ApplicationId appId, Set<Permission> permissionSet);
+
 }
\ No newline at end of file
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index 67b2a85..69c6484 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -186,6 +186,7 @@
 import org.onosproject.net.resource.link.MplsLabel;
 import org.onosproject.net.resource.link.MplsLabelResourceAllocation;
 import org.onosproject.net.resource.link.MplsLabelResourceRequest;
+import org.onosproject.security.Permission;
 import org.onosproject.store.Timestamp;
 import org.onosproject.store.service.MapEvent;
 import org.onosproject.store.service.SetEvent;
@@ -286,6 +287,7 @@
                     ApplicationState.class,
                     ApplicationRole.class,
                     DefaultApplication.class,
+                    Permission.class,
                     Device.Type.class,
                     Port.Type.class,
                     ChassisId.class,