[ 
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)

Reply via email to