[
https://issues.apache.org/jira/browse/NIFI-1571?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15194530#comment-15194530
]
ASF GitHub Bot commented on NIFI-1571:
--------------------------------------
Github user trkurc commented on a diff in the pull request:
https://github.com/apache/nifi/pull/271#discussion_r56104123
--- Diff:
nifi-nar-bundles/nifi-spring-bundle/nifi-spring-processors/src/main/java/org/apache/nifi/spring/SpringContextFactory.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.nifi.spring;
+
+import java.io.File;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper class which provides factory method to create and initialize
Spring
+ * Application Context while scoping it within the dedicated Class Loader.
+ */
+final class SpringContextFactory {
+
+ private static final Logger logger =
LoggerFactory.getLogger(SpringContextFactory.class);
+
+ private static final String SC_DELEGATE_NAME =
"org.apache.nifi.spring.bootstrap.SpringContextDelegate";
+
+ /**
+ * Creates and instance of Spring Application Context scoped within a
+ * dedicated Class Loader
+ */
+ static SpringDataExchanger createSpringContextDelegate(String
classpath, String config) {
+ System.out.println(SpringContextFactory.class.getClassLoader());
+ URL[] urls = gatherAdditionalClassPathUrls(classpath);
+ SpringContextClassLoader contextCl = new
SpringContextClassLoader(urls,
+ SpringContextFactory.class.getClassLoader());
+ try {
+ InputStream delegateStream =
contextCl.getResourceAsStream(SC_DELEGATE_NAME.replace('.', '/') + ".class");
+ byte[] delegateBytes = IOUtils.toByteArray(delegateStream);
+ Class<?> clazz = contextCl.doDefineClass(SC_DELEGATE_NAME,
delegateBytes, 0, delegateBytes.length);
+ Constructor<?> ctr =
clazz.getDeclaredConstructor(String.class);
+ ctr.setAccessible(true);
+ SpringDataExchanger springDelegate = (SpringDataExchanger)
ctr.newInstance(config);
+ if (logger.isInfoEnabled()) {
+ logger.info("Successfully instantiated Spring Application
Context from '" + config + "'");
+ }
+ return springDelegate;
+ } catch (Exception e) {
+ try {
+ contextCl.close();
+ } catch (Exception e2) {
+ // ignore
+ }
+ throw new IllegalStateException("Failed to instantiate Spring
Application Context. Config path: '" + config
+ + "'; Classpath: " + Arrays.asList(urls), e);
+ }
+ }
+
+ /**
+ *
+ */
+ private static URL[] gatherAdditionalClassPathUrls(String path) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Adding additional resources from '" + path + "'
to the classpath.");
+ }
+ File libraryDir = new File(path);
+ if (libraryDir.exists() && libraryDir.isDirectory()) {
+ String[] cpResourceNames = libraryDir.list();
+ try {
+ URLClassLoader thisCl = (URLClassLoader)
SpringContextFactory.class.getClassLoader();
+ List<URL> urls = new ArrayList<>();
+ for (int i = 0; i < cpResourceNames.length; i++) {
+ if (!isDuplicate(thisCl.getURLs(),
cpResourceNames[i])) {
+ URL url = new File(libraryDir,
cpResourceNames[i]).toURI().toURL();
+ urls.add(url);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Identifying additional resource
to the classpath: " + url);
+ }
+ }
+ }
+ return urls.toArray(new URL[] {});
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Failed to parse user libraries from '" +
libraryDir.getAbsolutePath() + "'", e);
+ }
+ } else {
+ throw new IllegalArgumentException("Path '" +
libraryDir.getAbsolutePath()
+ + "' is not valid because it doesn't exist or does not
point to a directory.");
+ }
+ }
+
+ /**
+ *
+ */
+ static boolean isDuplicate(URL[] currentURLs, String resourceName) {
+ if (resourceName.startsWith("spring")) {
+ resourceName = resourceName.substring(0,
resourceName.lastIndexOf("-"));
+ }
+ for (URL eURL : currentURLs) {
+ if (eURL.getPath().contains(resourceName)) {
--- End diff --
I tried reasoning about this for a bit, but couldn't you report duplicates
that are not actual duplicates if you have an resourceName that is just an
unfortunate substring of a url? Or is this very unlikely to occur?
> Provide generic processor that would bootstrap itself from Spring's
> Application Context
> ---------------------------------------------------------------------------------------
>
> Key: NIFI-1571
> URL: https://issues.apache.org/jira/browse/NIFI-1571
> Project: Apache NiFi
> Issue Type: New Feature
> Reporter: Oleg Zhurakousky
> Assignee: Oleg Zhurakousky
> Fix For: 0.6.0
>
>
> So, several clients have expressed interests in using WorkFlow orchestration
> frameworks such as Camel, Spring Integration etc. to be able to encapsulate
> yet modularize and externalize the complexity of some of the custom
> processors as well as handle some of the use cases that fall outside of scope
> of Data Flow paradigm (e.g., transactional context and XA between two+
> Processors).
> There is already a ticket to provide Camel support - NIFI-924. However
> realizing that both Camel and naturally Spring Integration is based on Spring
> Application Context it appears that instead of having multiple extensions we
> should have a more generic extension for a Processor that would delegate its
> processing to a bean in provided Spring Application Context (AC). This way AC
> becomes a black box and could contain anything (e.g., Camel, Spring
> Integration or some custom user code).
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)