Repository: incubator-nifi Updated Branches: refs/heads/NIFI-632 a2a2815f9 -> 56e40dd7d
NIFI-632 moving NarCloseable and NarThreadContextClassLoader to nifi-nar-utils from nifi-framework-core-api Project: http://git-wip-us.apache.org/repos/asf/incubator-nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-nifi/commit/f4d5070d Tree: http://git-wip-us.apache.org/repos/asf/incubator-nifi/tree/f4d5070d Diff: http://git-wip-us.apache.org/repos/asf/incubator-nifi/diff/f4d5070d Branch: refs/heads/NIFI-632 Commit: f4d5070dfbfaaf8278e0e27cbe7957ba89cd8958 Parents: a2a2815 Author: danbress <dbr...@onyxconsults.com> Authored: Mon Jun 8 21:26:35 2015 -0400 Committer: danbress <dbr...@onyxconsults.com> Committed: Mon Jun 8 21:26:35 2015 -0400 ---------------------------------------------------------------------- .../java/org/apache/nifi/nar/NarCloseable.java | 44 ----- .../nifi/nar/NarThreadContextClassLoader.java | 187 ------------------- .../java/org/apache/nifi/nar/NarCloseable.java | 44 +++++ .../nifi/nar/NarThreadContextClassLoader.java | 187 +++++++++++++++++++ 4 files changed, 231 insertions(+), 231 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/f4d5070d/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/nar/NarCloseable.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/nar/NarCloseable.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/nar/NarCloseable.java deleted file mode 100644 index b25c90b..0000000 --- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/nar/NarCloseable.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.nifi.nar; - -import java.io.Closeable; - -/** - * - */ -public class NarCloseable implements Closeable { - - public static NarCloseable withNarLoader() { - final ClassLoader current = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(NarThreadContextClassLoader.getInstance()); - return new NarCloseable(current); - } - - private final ClassLoader toSet; - - private NarCloseable(final ClassLoader toSet) { - this.toSet = toSet; - } - - @Override - public void close() { - if (toSet != null) { - Thread.currentThread().setContextClassLoader(toSet); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/f4d5070d/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java deleted file mode 100644 index 9471ba6..0000000 --- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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.nifi.nar; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; - -import org.apache.nifi.authorization.AuthorityProvider; -import org.apache.nifi.components.Validator; -import org.apache.nifi.controller.ControllerService; -import org.apache.nifi.controller.repository.ContentRepository; -import org.apache.nifi.controller.repository.FlowFileRepository; -import org.apache.nifi.controller.repository.FlowFileSwapManager; -import org.apache.nifi.controller.status.history.ComponentStatusRepository; -import org.apache.nifi.flowfile.FlowFilePrioritizer; -import org.apache.nifi.processor.Processor; -import org.apache.nifi.processor.io.InputStreamCallback; -import org.apache.nifi.processor.io.OutputStreamCallback; -import org.apache.nifi.processor.io.StreamCallback; -import org.apache.nifi.provenance.ProvenanceEventRepository; -import org.apache.nifi.reporting.ReportingTask; - -/** - * THREAD SAFE - */ -public class NarThreadContextClassLoader extends URLClassLoader { - - static final ContextSecurityManager contextSecurityManager = new ContextSecurityManager(); - private final ClassLoader forward = ClassLoader.getSystemClassLoader(); - private static final List<Class<?>> narSpecificClasses = new ArrayList<>(); - - static { - narSpecificClasses.add(Processor.class); - narSpecificClasses.add(FlowFilePrioritizer.class); - narSpecificClasses.add(ReportingTask.class); - narSpecificClasses.add(Validator.class); - narSpecificClasses.add(InputStreamCallback.class); - narSpecificClasses.add(OutputStreamCallback.class); - narSpecificClasses.add(StreamCallback.class); - narSpecificClasses.add(ControllerService.class); - narSpecificClasses.add(AuthorityProvider.class); - narSpecificClasses.add(ProvenanceEventRepository.class); - narSpecificClasses.add(ComponentStatusRepository.class); - narSpecificClasses.add(FlowFileRepository.class); - narSpecificClasses.add(FlowFileSwapManager.class); - narSpecificClasses.add(ContentRepository.class); - } - - private NarThreadContextClassLoader() { - super(new URL[0]); - } - - @Override - public void clearAssertionStatus() { - lookupClassLoader().clearAssertionStatus(); - } - - @Override - public URL getResource(String name) { - return lookupClassLoader().getResource(name); - } - - @Override - public InputStream getResourceAsStream(String name) { - return lookupClassLoader().getResourceAsStream(name); - } - - @Override - public Enumeration<URL> getResources(String name) throws IOException { - return lookupClassLoader().getResources(name); - } - - @Override - public Class<?> loadClass(String name) throws ClassNotFoundException { - return lookupClassLoader().loadClass(name); - } - - @Override - public void setClassAssertionStatus(String className, boolean enabled) { - lookupClassLoader().setClassAssertionStatus(className, enabled); - } - - @Override - public void setDefaultAssertionStatus(boolean enabled) { - lookupClassLoader().setDefaultAssertionStatus(enabled); - } - - @Override - public void setPackageAssertionStatus(String packageName, boolean enabled) { - lookupClassLoader().setPackageAssertionStatus(packageName, enabled); - } - - private ClassLoader lookupClassLoader() { - final Class<?>[] classStack = contextSecurityManager.getExecutionStack(); - - for (Class<?> currentClass : classStack) { - final Class<?> narClass = findNarClass(currentClass); - if (narClass != null) { - final ClassLoader desiredClassLoader = narClass.getClassLoader(); - - // When new Threads are created, the new Thread inherits the ClassLoaderContext of - // the caller. However, the call stack of that new Thread may not trace back to any NiFi-specific - // code. Therefore, the NarThreadContextClassLoader will be unable to find the appropriate NAR - // ClassLoader. As a result, we want to set the ContextClassLoader to the NAR ClassLoader that - // contains the class or resource that we are looking for. - // This locks the current Thread into the appropriate NAR ClassLoader Context. The framework will change - // the ContextClassLoader back to the NarThreadContextClassLoader as appropriate via the - // {@link FlowEngine.beforeExecute(Thread, Runnable)} and - // {@link FlowEngine.afterExecute(Thread, Runnable)} methods. - if (desiredClassLoader instanceof NarClassLoader) { - Thread.currentThread().setContextClassLoader(desiredClassLoader); - } - return desiredClassLoader; - } - } - return forward; - } - - private Class<?> findNarClass(final Class<?> cls) { - for (final Class<?> narClass : narSpecificClasses) { - if (narClass.isAssignableFrom(cls)) { - return cls; - } else if (cls.getEnclosingClass() != null) { - return findNarClass(cls.getEnclosingClass()); - } - } - - return null; - } - - private static class SingletonHolder { - - public static final NarThreadContextClassLoader instance = new NarThreadContextClassLoader(); - } - - public static NarThreadContextClassLoader getInstance() { - return SingletonHolder.instance; - } - - static class ContextSecurityManager extends SecurityManager { - - Class<?>[] getExecutionStack() { - return getClassContext(); - } - } - - public static <T> T createInstance(final String implementationClassName, final Class<T> typeDefinition) throws InstantiationException, IllegalAccessException, ClassNotFoundException { - final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(NarThreadContextClassLoader.getInstance()); - try { - final ClassLoader detectedClassLoaderForType = ExtensionManager.getClassLoader(implementationClassName); - final Class<?> rawClass; - if (detectedClassLoaderForType == null) { - // try to find from the current class loader - rawClass = Class.forName(implementationClassName); - } else { - // try to find from the registered classloader for that type - rawClass = Class.forName(implementationClassName, true, ExtensionManager.getClassLoader(implementationClassName)); - } - - Thread.currentThread().setContextClassLoader(detectedClassLoaderForType); - final Class<?> desiredClass = rawClass.asSubclass(typeDefinition); - return typeDefinition.cast(desiredClass.newInstance()); - } finally { - Thread.currentThread().setContextClassLoader(originalClassLoader); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/f4d5070d/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarCloseable.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarCloseable.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarCloseable.java new file mode 100644 index 0000000..b25c90b --- /dev/null +++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarCloseable.java @@ -0,0 +1,44 @@ +/* + * 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.nifi.nar; + +import java.io.Closeable; + +/** + * + */ +public class NarCloseable implements Closeable { + + public static NarCloseable withNarLoader() { + final ClassLoader current = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(NarThreadContextClassLoader.getInstance()); + return new NarCloseable(current); + } + + private final ClassLoader toSet; + + private NarCloseable(final ClassLoader toSet) { + this.toSet = toSet; + } + + @Override + public void close() { + if (toSet != null) { + Thread.currentThread().setContextClassLoader(toSet); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/f4d5070d/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java new file mode 100644 index 0000000..9471ba6 --- /dev/null +++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java @@ -0,0 +1,187 @@ +/* + * 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.nifi.nar; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import org.apache.nifi.authorization.AuthorityProvider; +import org.apache.nifi.components.Validator; +import org.apache.nifi.controller.ControllerService; +import org.apache.nifi.controller.repository.ContentRepository; +import org.apache.nifi.controller.repository.FlowFileRepository; +import org.apache.nifi.controller.repository.FlowFileSwapManager; +import org.apache.nifi.controller.status.history.ComponentStatusRepository; +import org.apache.nifi.flowfile.FlowFilePrioritizer; +import org.apache.nifi.processor.Processor; +import org.apache.nifi.processor.io.InputStreamCallback; +import org.apache.nifi.processor.io.OutputStreamCallback; +import org.apache.nifi.processor.io.StreamCallback; +import org.apache.nifi.provenance.ProvenanceEventRepository; +import org.apache.nifi.reporting.ReportingTask; + +/** + * THREAD SAFE + */ +public class NarThreadContextClassLoader extends URLClassLoader { + + static final ContextSecurityManager contextSecurityManager = new ContextSecurityManager(); + private final ClassLoader forward = ClassLoader.getSystemClassLoader(); + private static final List<Class<?>> narSpecificClasses = new ArrayList<>(); + + static { + narSpecificClasses.add(Processor.class); + narSpecificClasses.add(FlowFilePrioritizer.class); + narSpecificClasses.add(ReportingTask.class); + narSpecificClasses.add(Validator.class); + narSpecificClasses.add(InputStreamCallback.class); + narSpecificClasses.add(OutputStreamCallback.class); + narSpecificClasses.add(StreamCallback.class); + narSpecificClasses.add(ControllerService.class); + narSpecificClasses.add(AuthorityProvider.class); + narSpecificClasses.add(ProvenanceEventRepository.class); + narSpecificClasses.add(ComponentStatusRepository.class); + narSpecificClasses.add(FlowFileRepository.class); + narSpecificClasses.add(FlowFileSwapManager.class); + narSpecificClasses.add(ContentRepository.class); + } + + private NarThreadContextClassLoader() { + super(new URL[0]); + } + + @Override + public void clearAssertionStatus() { + lookupClassLoader().clearAssertionStatus(); + } + + @Override + public URL getResource(String name) { + return lookupClassLoader().getResource(name); + } + + @Override + public InputStream getResourceAsStream(String name) { + return lookupClassLoader().getResourceAsStream(name); + } + + @Override + public Enumeration<URL> getResources(String name) throws IOException { + return lookupClassLoader().getResources(name); + } + + @Override + public Class<?> loadClass(String name) throws ClassNotFoundException { + return lookupClassLoader().loadClass(name); + } + + @Override + public void setClassAssertionStatus(String className, boolean enabled) { + lookupClassLoader().setClassAssertionStatus(className, enabled); + } + + @Override + public void setDefaultAssertionStatus(boolean enabled) { + lookupClassLoader().setDefaultAssertionStatus(enabled); + } + + @Override + public void setPackageAssertionStatus(String packageName, boolean enabled) { + lookupClassLoader().setPackageAssertionStatus(packageName, enabled); + } + + private ClassLoader lookupClassLoader() { + final Class<?>[] classStack = contextSecurityManager.getExecutionStack(); + + for (Class<?> currentClass : classStack) { + final Class<?> narClass = findNarClass(currentClass); + if (narClass != null) { + final ClassLoader desiredClassLoader = narClass.getClassLoader(); + + // When new Threads are created, the new Thread inherits the ClassLoaderContext of + // the caller. However, the call stack of that new Thread may not trace back to any NiFi-specific + // code. Therefore, the NarThreadContextClassLoader will be unable to find the appropriate NAR + // ClassLoader. As a result, we want to set the ContextClassLoader to the NAR ClassLoader that + // contains the class or resource that we are looking for. + // This locks the current Thread into the appropriate NAR ClassLoader Context. The framework will change + // the ContextClassLoader back to the NarThreadContextClassLoader as appropriate via the + // {@link FlowEngine.beforeExecute(Thread, Runnable)} and + // {@link FlowEngine.afterExecute(Thread, Runnable)} methods. + if (desiredClassLoader instanceof NarClassLoader) { + Thread.currentThread().setContextClassLoader(desiredClassLoader); + } + return desiredClassLoader; + } + } + return forward; + } + + private Class<?> findNarClass(final Class<?> cls) { + for (final Class<?> narClass : narSpecificClasses) { + if (narClass.isAssignableFrom(cls)) { + return cls; + } else if (cls.getEnclosingClass() != null) { + return findNarClass(cls.getEnclosingClass()); + } + } + + return null; + } + + private static class SingletonHolder { + + public static final NarThreadContextClassLoader instance = new NarThreadContextClassLoader(); + } + + public static NarThreadContextClassLoader getInstance() { + return SingletonHolder.instance; + } + + static class ContextSecurityManager extends SecurityManager { + + Class<?>[] getExecutionStack() { + return getClassContext(); + } + } + + public static <T> T createInstance(final String implementationClassName, final Class<T> typeDefinition) throws InstantiationException, IllegalAccessException, ClassNotFoundException { + final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(NarThreadContextClassLoader.getInstance()); + try { + final ClassLoader detectedClassLoaderForType = ExtensionManager.getClassLoader(implementationClassName); + final Class<?> rawClass; + if (detectedClassLoaderForType == null) { + // try to find from the current class loader + rawClass = Class.forName(implementationClassName); + } else { + // try to find from the registered classloader for that type + rawClass = Class.forName(implementationClassName, true, ExtensionManager.getClassLoader(implementationClassName)); + } + + Thread.currentThread().setContextClassLoader(detectedClassLoaderForType); + final Class<?> desiredClass = rawClass.asSubclass(typeDefinition); + return typeDefinition.cast(desiredClass.newInstance()); + } finally { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } +}