You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by st...@apache.org on 2015/11/23 10:31:27 UTC
deltaspike git commit: DELTASPIKE-1015 support for hierarchic
BeanManager
Repository: deltaspike
Updated Branches:
refs/heads/master ada7480c8 -> bbd5fa8b2
DELTASPIKE-1015 support for hierarchic BeanManager
This is mainly needed in EARs.
Using WeakReferences will prevent mem leaks if a webapp using DS
get's undeployed. Otherwise the JVM will not be able to garbage
collect any WebAppClassLoader
Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/bbd5fa8b
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/bbd5fa8b
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/bbd5fa8b
Branch: refs/heads/master
Commit: bbd5fa8b24a08f0c0cda8e0dca61403872a00594
Parents: ada7480
Author: Mark Struberg <st...@apache.org>
Authored: Mon Nov 23 10:21:30 2015 +0100
Committer: Mark Struberg <st...@apache.org>
Committed: Mon Nov 23 10:31:05 2015 +0100
----------------------------------------------------------------------
.../core/util/ParentExtensionStorage.java | 139 +++++++
.../impl/message/MessageBundleExtension.java | 417 ++++++++++---------
.../impl/extension/SecurityExtension.java | 14 +
3 files changed, 369 insertions(+), 201 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/bbd5fa8b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ParentExtensionStorage.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ParentExtensionStorage.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ParentExtensionStorage.java
new file mode 100644
index 0000000..6e1f044
--- /dev/null
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/util/ParentExtensionStorage.java
@@ -0,0 +1,139 @@
+/*
+ * 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.deltaspike.core.util;
+
+import javax.enterprise.inject.spi.Extension;
+
+import java.lang.ref.WeakReference;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Support for Containers with 'hierarchic BeanManagers'
+ * This is mostly useful for EAR applications.
+ *
+ * Some EE Container scan the common shared EAR lib path and reuse this information
+ * for the webapps in the EAR. This is actually the only approach a container can
+ * do to prevent mem leaks and side effects spreading to different webapps.
+ * Of course this also means that the webapps get their own (different)
+ * instances of an Extension.
+ *
+ * To acknowledge this solution we provide a mechanism to lookup 'parent Extensions'
+ * which is very similar to handling parent ClassLoaders.
+ *
+ * All your Extension has to do is to register itself in
+ * {@link javax.enterprise.inject.spi.BeforeBeanDiscovery}.
+ * Later at boot time the Extension can lookup it's parent Extension instance and
+ * e.g. check which classes got scanned in the parent ClassLoader.
+ *
+ * The ExtensionInfo automatically gets removed if the webapp gets undeployed.
+ */
+public final class ParentExtensionStorage
+{
+
+ private static Set<ExtensionStorageInfo> extensionStorage = new HashSet<ExtensionStorageInfo>();
+
+ private ParentExtensionStorage()
+ {
+ // utility class ct
+ }
+
+ /**
+ * Add info about an Extension to our storage
+ * This method is usually called during boostrap via {@code @Observes BeforeBeanDiscovery}.
+ */
+ public static synchronized void addExtension(Extension extension)
+ {
+ removeAbandonedExtensions();
+
+ ClassLoader classLoader = ClassUtils.getClassLoader(null);
+ extensionStorage.add(new ExtensionStorageInfo(classLoader, extension));
+ }
+
+ /**
+ * When adding a new Extension we also clean up ExtensionInfos
+ * from ClassLoaders which got unloaded.
+ */
+ private static void removeAbandonedExtensions()
+ {
+ Iterator<ExtensionStorageInfo> it = extensionStorage.iterator();
+ while (it.hasNext())
+ {
+ ExtensionStorageInfo info = it.next();
+ if (info.isAbandoned())
+ {
+ it.remove();
+ }
+ }
+ }
+
+ /**
+ * @return the Extension from the same type but registered in a hierarchic 'parent' BeanManager
+ */
+ public static synchronized <T extends Extension> T getParentExtension(Extension extension)
+ {
+ ClassLoader parentClassLoader = ClassUtils.getClassLoader(null).getParent();
+
+ Iterator<ExtensionStorageInfo> extIt = extensionStorage.iterator();
+ while (extIt.hasNext())
+ {
+ ExtensionStorageInfo extensionInfo = extIt.next();
+ if (!extensionInfo.isAbandoned() && // weak reference case
+ extension.getClass().equals(extensionInfo.getExtension().getClass()) &&
+ extensionInfo.getClassLoader().equals(parentClassLoader))
+ {
+ return (T) extensionInfo.getExtension();
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Information about an Extension instance and in which classloader it got used
+ */
+ private static class ExtensionStorageInfo
+ {
+ // we use WeakReferences to allow perfect unloading of any webapp ClassLoader
+ private final WeakReference<ClassLoader> classLoader;
+ private final WeakReference<Extension> extension;
+
+ public ExtensionStorageInfo(ClassLoader classLoader, Extension extension)
+ {
+ this.classLoader = new WeakReference<ClassLoader>(classLoader);
+ this.extension = new WeakReference<Extension>(extension);
+ }
+
+ boolean isAbandoned()
+ {
+ return classLoader.get() == null || extension.get() == null;
+ }
+
+ ClassLoader getClassLoader()
+ {
+ return classLoader.get();
+ }
+
+ Extension getExtension()
+ {
+ return extension.get();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/bbd5fa8b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/message/MessageBundleExtension.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/message/MessageBundleExtension.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/message/MessageBundleExtension.java
index 5636529..1733f5f 100644
--- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/message/MessageBundleExtension.java
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/message/MessageBundleExtension.java
@@ -1,201 +1,216 @@
-/*
- * 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.deltaspike.core.impl.message;
-
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.event.Observes;
-import javax.enterprise.inject.spi.*;
-
-import org.apache.deltaspike.core.api.literal.DefaultLiteral;
-import org.apache.deltaspike.core.api.message.Message;
-import org.apache.deltaspike.core.api.message.MessageBundle;
-import org.apache.deltaspike.core.api.message.MessageTemplate;
-import org.apache.deltaspike.core.api.provider.BeanProvider;
-import org.apache.deltaspike.core.api.provider.DependentProvider;
-import org.apache.deltaspike.core.util.ClassUtils;
-import org.apache.deltaspike.core.util.bean.BeanBuilder;
-import org.apache.deltaspike.core.spi.activation.Deactivatable;
-import org.apache.deltaspike.core.util.ClassDeactivationUtils;
-import org.apache.deltaspike.core.util.metadata.builder.ContextualLifecycle;
-
-/**
- * Extension for handling {@link MessageBundle}s.
- *
- * @see MessageBundle
- * @see MessageTemplate
- */
-public class MessageBundleExtension implements Extension, Deactivatable
-{
- private final Collection<AnnotatedType<?>> messageBundleTypes = new HashSet<AnnotatedType<?>>();
-
- private List<String> deploymentErrors = new ArrayList<String>();
-
- private Boolean isActivated = true;
-
- @SuppressWarnings("UnusedDeclaration")
- protected void init(@Observes BeforeBeanDiscovery beforeBeanDiscovery)
- {
- isActivated = ClassDeactivationUtils.isActivated(getClass());
- }
-
- @SuppressWarnings("UnusedDeclaration")
- protected void detectInterfaces(@Observes ProcessAnnotatedType processAnnotatedType)
- {
- if (!isActivated)
- {
- return;
- }
-
- AnnotatedType<?> type = processAnnotatedType.getAnnotatedType();
-
- if (type.isAnnotationPresent(MessageBundle.class))
- {
- if (validateMessageBundle(type.getJavaClass()))
- {
- messageBundleTypes.add(type);
- }
- }
- }
-
- /**
- * @return <code>true</code> if all is well
- */
- private boolean validateMessageBundle(Class<?> currentClass)
- {
- boolean ok = true;
-
- // sanity check: annotated class must be an Interface
- if (!currentClass.isInterface())
- {
- deploymentErrors.add("@MessageBundle must only be used on Interfaces, but got used on class " +
- currentClass.getName());
- return false;
- }
-
- for (Method currentMethod : currentClass.getDeclaredMethods())
- {
- if (!currentMethod.isAnnotationPresent(MessageTemplate.class))
- {
- continue;
- }
-
- if (String.class.isAssignableFrom(currentMethod.getReturnType()))
- {
- continue;
- }
-
- if (Message.class.isAssignableFrom(currentMethod.getReturnType()))
- {
- continue;
- }
-
- deploymentErrors.add(currentMethod.getReturnType().getName() + " isn't supported. Details: " +
- currentMethod.getDeclaringClass().getName() + "#" + currentMethod.getName() +
- " only " + String.class.getName() + " or " + Message.class.getName());
- ok = false;
- }
-
- return ok;
- }
-
- @SuppressWarnings("UnusedDeclaration")
- protected void installMessageBundleProducerBeans(@Observes AfterBeanDiscovery abd, BeanManager beanManager)
- {
- if (!deploymentErrors.isEmpty())
- {
- abd.addDefinitionError(new IllegalArgumentException("The following MessageBundle problems where found: " +
- Arrays.toString(deploymentErrors.toArray())));
- return;
- }
-
- for (AnnotatedType<?> type : messageBundleTypes)
- {
- abd.addBean(createMessageBundleBean(type, beanManager));
- }
- }
-
- private <T> Bean<T> createMessageBundleBean(AnnotatedType<T> annotatedType,
- BeanManager beanManager)
- {
- BeanBuilder<T> beanBuilder = new BeanBuilder<T>(beanManager).readFromType(annotatedType);
-
- beanBuilder.beanLifecycle(new MessageBundleLifecycle<T>(beanManager));
-
- beanBuilder.types(annotatedType.getJavaClass(), Object.class, Serializable.class);
- beanBuilder.addQualifier(new DefaultLiteral());
-
- beanBuilder.passivationCapable(true);
- beanBuilder.scope(ApplicationScoped.class); // needs to be a normalscope due to a bug in older Weld versions
- beanBuilder.id("MessageBundleBean#" + annotatedType.getJavaClass().getName());
-
- return beanBuilder.create();
- }
-
- @SuppressWarnings("UnusedDeclaration")
- protected void cleanup(@Observes AfterDeploymentValidation afterDeploymentValidation)
- {
- messageBundleTypes.clear();
- }
-
- private static class MessageBundleLifecycle<T> implements ContextualLifecycle<T>
- {
- private final BeanManager beanManager;
-
- private DependentProvider<MessageBundleInvocationHandler> invocationHandlerProvider;
-
- private MessageBundleLifecycle(BeanManager beanManager)
- {
- this.beanManager = beanManager;
- }
-
- @Override
- public T create(Bean<T> bean, CreationalContext<T> creationalContext)
- {
- invocationHandlerProvider = BeanProvider.getDependent(beanManager, MessageBundleInvocationHandler.class);
-
- return createMessageBundleProxy((Class<T>) bean.getBeanClass(), invocationHandlerProvider.get());
- }
-
- @Override
- public void destroy(Bean<T> bean, T instance, CreationalContext<T> creationalContext)
- {
- if (invocationHandlerProvider != null)
- {
- invocationHandlerProvider.destroy();
- }
- }
-
- private <T> T createMessageBundleProxy(Class<T> type, MessageBundleInvocationHandler handler)
- {
- return type.cast(Proxy.newProxyInstance(ClassUtils.getClassLoader(null),
- new Class<?>[]{type, Serializable.class}, handler));
- }
-
- }
-}
+/*
+ * 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.deltaspike.core.impl.message;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.AfterDeploymentValidation;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+
+import org.apache.deltaspike.core.api.literal.DefaultLiteral;
+import org.apache.deltaspike.core.api.message.Message;
+import org.apache.deltaspike.core.api.message.MessageBundle;
+import org.apache.deltaspike.core.api.message.MessageTemplate;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.api.provider.DependentProvider;
+import org.apache.deltaspike.core.util.ClassUtils;
+import org.apache.deltaspike.core.util.ParentExtensionStorage;
+import org.apache.deltaspike.core.util.bean.BeanBuilder;
+import org.apache.deltaspike.core.spi.activation.Deactivatable;
+import org.apache.deltaspike.core.util.ClassDeactivationUtils;
+import org.apache.deltaspike.core.util.metadata.builder.ContextualLifecycle;
+
+/**
+ * Extension for handling {@link MessageBundle}s.
+ *
+ * @see MessageBundle
+ * @see MessageTemplate
+ */
+public class MessageBundleExtension implements Extension, Deactivatable
+{
+ private final Collection<AnnotatedType<?>> messageBundleTypes = new HashSet<AnnotatedType<?>>();
+
+ private List<String> deploymentErrors = new ArrayList<String>();
+
+ private Boolean isActivated = true;
+
+ @SuppressWarnings("UnusedDeclaration")
+ protected void init(@Observes BeforeBeanDiscovery beforeBeanDiscovery)
+ {
+ isActivated = ClassDeactivationUtils.isActivated(getClass());
+ ParentExtensionStorage.addExtension(this);
+ }
+
+ @SuppressWarnings("UnusedDeclaration")
+ protected void detectInterfaces(@Observes ProcessAnnotatedType processAnnotatedType)
+ {
+ if (!isActivated)
+ {
+ return;
+ }
+
+ AnnotatedType<?> type = processAnnotatedType.getAnnotatedType();
+
+ if (type.isAnnotationPresent(MessageBundle.class))
+ {
+ if (validateMessageBundle(type.getJavaClass()))
+ {
+ messageBundleTypes.add(type);
+ }
+ }
+ }
+
+ /**
+ * @return <code>true</code> if all is well
+ */
+ private boolean validateMessageBundle(Class<?> currentClass)
+ {
+ boolean ok = true;
+
+ // sanity check: annotated class must be an Interface
+ if (!currentClass.isInterface())
+ {
+ deploymentErrors.add("@MessageBundle must only be used on Interfaces, but got used on class " +
+ currentClass.getName());
+ return false;
+ }
+
+ for (Method currentMethod : currentClass.getDeclaredMethods())
+ {
+ if (!currentMethod.isAnnotationPresent(MessageTemplate.class))
+ {
+ continue;
+ }
+
+ if (String.class.isAssignableFrom(currentMethod.getReturnType()))
+ {
+ continue;
+ }
+
+ if (Message.class.isAssignableFrom(currentMethod.getReturnType()))
+ {
+ continue;
+ }
+
+ deploymentErrors.add(currentMethod.getReturnType().getName() + " isn't supported. Details: " +
+ currentMethod.getDeclaringClass().getName() + "#" + currentMethod.getName() +
+ " only " + String.class.getName() + " or " + Message.class.getName());
+ ok = false;
+ }
+
+ return ok;
+ }
+
+ @SuppressWarnings("UnusedDeclaration")
+ protected void installMessageBundleProducerBeans(@Observes AfterBeanDiscovery abd, BeanManager beanManager)
+ {
+ if (!deploymentErrors.isEmpty())
+ {
+ abd.addDefinitionError(new IllegalArgumentException("The following MessageBundle problems where found: " +
+ Arrays.toString(deploymentErrors.toArray())));
+ return;
+ }
+
+ MessageBundleExtension parentExtension = ParentExtensionStorage.getParentExtension(this);
+ if (parentExtension != null)
+ {
+ messageBundleTypes.addAll(parentExtension.messageBundleTypes);
+ }
+
+ for (AnnotatedType<?> type : messageBundleTypes)
+ {
+ abd.addBean(createMessageBundleBean(type, beanManager));
+ }
+ }
+
+ private <T> Bean<T> createMessageBundleBean(AnnotatedType<T> annotatedType,
+ BeanManager beanManager)
+ {
+ BeanBuilder<T> beanBuilder = new BeanBuilder<T>(beanManager).readFromType(annotatedType);
+
+ beanBuilder.beanLifecycle(new MessageBundleLifecycle<T>(beanManager));
+
+ beanBuilder.types(annotatedType.getJavaClass(), Object.class, Serializable.class);
+ beanBuilder.addQualifier(new DefaultLiteral());
+
+ beanBuilder.passivationCapable(true);
+ beanBuilder.scope(ApplicationScoped.class); // needs to be a normalscope due to a bug in older Weld versions
+ beanBuilder.id("MessageBundleBean#" + annotatedType.getJavaClass().getName());
+
+ return beanBuilder.create();
+ }
+
+ @SuppressWarnings("UnusedDeclaration")
+ protected void cleanup(@Observes AfterDeploymentValidation afterDeploymentValidation)
+ {
+ messageBundleTypes.clear();
+ }
+
+ private static class MessageBundleLifecycle<T> implements ContextualLifecycle<T>
+ {
+ private final BeanManager beanManager;
+
+ private DependentProvider<MessageBundleInvocationHandler> invocationHandlerProvider;
+
+ private MessageBundleLifecycle(BeanManager beanManager)
+ {
+ this.beanManager = beanManager;
+ }
+
+ @Override
+ public T create(Bean<T> bean, CreationalContext<T> creationalContext)
+ {
+ invocationHandlerProvider = BeanProvider.getDependent(beanManager, MessageBundleInvocationHandler.class);
+
+ return createMessageBundleProxy((Class<T>) bean.getBeanClass(), invocationHandlerProvider.get());
+ }
+
+ @Override
+ public void destroy(Bean<T> bean, T instance, CreationalContext<T> creationalContext)
+ {
+ if (invocationHandlerProvider != null)
+ {
+ invocationHandlerProvider.destroy();
+ }
+ }
+
+ private <T> T createMessageBundleProxy(Class<T> type, MessageBundleInvocationHandler handler)
+ {
+ return type.cast(Proxy.newProxyInstance(ClassUtils.getClassLoader(null),
+ new Class<?>[]{type, Serializable.class}, handler));
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/bbd5fa8b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/SecurityExtension.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/SecurityExtension.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/SecurityExtension.java
index 375def0..95f0fc5 100644
--- a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/SecurityExtension.java
+++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/SecurityExtension.java
@@ -21,6 +21,7 @@ package org.apache.deltaspike.security.impl.extension;
import org.apache.deltaspike.core.spi.activation.Deactivatable;
import org.apache.deltaspike.core.util.ClassDeactivationUtils;
+import org.apache.deltaspike.core.util.ParentExtensionStorage;
import org.apache.deltaspike.core.util.metadata.builder.AnnotatedTypeBuilder;
import org.apache.deltaspike.security.api.authorization.Secures;
import org.apache.deltaspike.security.api.authorization.SecurityDefinitionException;
@@ -56,6 +57,7 @@ public class SecurityExtension implements Extension, Deactivatable
{
isActivated = ClassDeactivationUtils.isActivated(getClass());
securityMetaDataStorage = new SecurityMetaDataStorage();
+ ParentExtensionStorage.addExtension(this);
}
//workaround for OWB
@@ -136,6 +138,18 @@ public class SecurityExtension implements Extension, Deactivatable
}
SecurityMetaDataStorage metaDataStorage = getMetaDataStorage();
+
+ SecurityExtension parentExtension = ParentExtensionStorage.getParentExtension(this);
+ if (parentExtension != null)
+ {
+ // also add the authorizers from the parent extension
+ Set<Authorizer> parentAuthorizers = parentExtension.getMetaDataStorage().getAuthorizers();
+ for (Authorizer parentAuthorizer : parentAuthorizers)
+ {
+ metaDataStorage.addAuthorizer(parentAuthorizer);
+ }
+ }
+
metaDataStorage.registerSecuredMethods();
for (final AnnotatedMethod<?> method : metaDataStorage.getSecuredMethods())