You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2017/03/24 15:10:56 UTC
[09/17] nifi git commit: NIFI-3380 Bumping NAR plugin to
1.2.0-SNAPSHOT development to leverage changes from master,
adding buildnumber-maven-plugin to nifi-nar-bundles to properly set build info
in MANIFEST of NARs - Refactoring NarDetails to include al
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java
new file mode 100644
index 0000000..546e67c
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java
@@ -0,0 +1,57 @@
+/*
+ * 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.init;
+
+import org.apache.nifi.annotation.lifecycle.OnShutdown;
+import org.apache.nifi.components.ConfigurableComponent;
+import org.apache.nifi.mock.MockComponentLogger;
+import org.apache.nifi.mock.MockConfigurationContext;
+import org.apache.nifi.mock.MockReportingInitializationContext;
+import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.NarCloseable;
+import org.apache.nifi.reporting.InitializationException;
+import org.apache.nifi.reporting.ReportingInitializationContext;
+import org.apache.nifi.reporting.ReportingTask;
+
+/**
+ * Initializes a ReportingTask using a MockReportingInitializationContext;
+ *
+ *
+ */
+public class ReportingTaskingInitializer implements ConfigurableComponentInitializer {
+
+ @Override
+ public void initialize(ConfigurableComponent component) throws InitializationException {
+ ReportingTask reportingTask = (ReportingTask) component;
+ ReportingInitializationContext context = new MockReportingInitializationContext();
+ try (NarCloseable narCloseable = NarCloseable.withComponentNarLoader(component.getClass(), context.getIdentifier())) {
+ reportingTask.initialize(context);
+ }
+ }
+
+ @Override
+ public void teardown(ConfigurableComponent component) {
+ ReportingTask reportingTask = (ReportingTask) component;
+ try (NarCloseable narCloseable = NarCloseable.withComponentNarLoader(component.getClass(), component.getIdentifier())) {
+
+ final MockConfigurationContext context = new MockConfigurationContext();
+ ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnShutdown.class, reportingTask, new MockComponentLogger(), context);
+ } finally {
+ ExtensionManager.removeInstanceClassLoaderIfExists(component.getIdentifier());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockComponentLogger.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockComponentLogger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockComponentLogger.java
new file mode 100644
index 0000000..920d7eb
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockComponentLogger.java
@@ -0,0 +1,258 @@
+/*
+ * 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.mock;
+
+import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.logging.LogLevel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Stubs out the functionality of a ComponentLog so that it can
+ * be used during initialization of a component.
+ *
+ */
+public class MockComponentLogger implements ComponentLog {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(MockComponentLogger.class);
+
+ @Override
+ public void warn(String msg, Throwable t) {
+ logger.warn(msg, t);
+ }
+
+ @Override
+ public void warn(String msg, Object[] os) {
+ logger.warn(msg, os);
+ }
+
+ @Override
+ public void warn(String msg, Object[] os, Throwable t) {
+ logger.warn(msg, os);
+ logger.warn("", t);
+ }
+
+ @Override
+ public void warn(String msg) {
+ logger.warn(msg);
+ }
+
+ @Override
+ public void trace(String msg, Throwable t) {
+ logger.trace(msg, t);
+ }
+
+ @Override
+ public void trace(String msg, Object[] os) {
+ logger.trace(msg, os);
+ }
+
+ @Override
+ public void trace(String msg) {
+ logger.trace(msg);
+ }
+
+ @Override
+ public void trace(String msg, Object[] os, Throwable t) {
+ logger.trace(msg, os);
+ logger.trace("", t);
+ }
+
+ @Override
+ public boolean isWarnEnabled() {
+ return logger.isWarnEnabled();
+ }
+
+ @Override
+ public boolean isTraceEnabled() {
+ return logger.isTraceEnabled();
+ }
+
+ @Override
+ public boolean isInfoEnabled() {
+ return logger.isInfoEnabled();
+ }
+
+ @Override
+ public boolean isErrorEnabled() {
+ return logger.isErrorEnabled();
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return logger.isDebugEnabled();
+ }
+
+ @Override
+ public void info(String msg, Throwable t) {
+ logger.info(msg, t);
+ }
+
+ @Override
+ public void info(String msg, Object[] os) {
+ logger.info(msg, os);
+ }
+
+ @Override
+ public void info(String msg) {
+ logger.info(msg);
+
+ }
+
+ @Override
+ public void info(String msg, Object[] os, Throwable t) {
+ logger.trace(msg, os);
+ logger.trace("", t);
+
+ }
+
+ @Override
+ public String getName() {
+ return logger.getName();
+ }
+
+ @Override
+ public void error(String msg, Throwable t) {
+ logger.error(msg, t);
+ }
+
+ @Override
+ public void error(String msg, Object[] os) {
+ logger.error(msg, os);
+ }
+
+ @Override
+ public void error(String msg) {
+ logger.error(msg);
+ }
+
+ @Override
+ public void error(String msg, Object[] os, Throwable t) {
+ logger.error(msg, os);
+ logger.error("", t);
+ }
+
+ @Override
+ public void debug(String msg, Throwable t) {
+ logger.debug(msg, t);
+ }
+
+ @Override
+ public void debug(String msg, Object[] os) {
+ logger.debug(msg, os);
+ }
+
+ @Override
+ public void debug(String msg, Object[] os, Throwable t) {
+ logger.debug(msg, os);
+ logger.debug("", t);
+ }
+
+ @Override
+ public void debug(String msg) {
+ logger.debug(msg);
+ }
+
+ @Override
+ public void log(LogLevel level, String msg, Throwable t) {
+ switch (level) {
+ case DEBUG:
+ debug(msg, t);
+ break;
+ case ERROR:
+ case FATAL:
+ error(msg, t);
+ break;
+ case INFO:
+ info(msg, t);
+ break;
+ case TRACE:
+ trace(msg, t);
+ break;
+ case WARN:
+ warn(msg, t);
+ break;
+ }
+ }
+
+ @Override
+ public void log(LogLevel level, String msg, Object[] os) {
+ switch (level) {
+ case DEBUG:
+ debug(msg, os);
+ break;
+ case ERROR:
+ case FATAL:
+ error(msg, os);
+ break;
+ case INFO:
+ info(msg, os);
+ break;
+ case TRACE:
+ trace(msg, os);
+ break;
+ case WARN:
+ warn(msg, os);
+ break;
+ }
+ }
+
+ @Override
+ public void log(LogLevel level, String msg) {
+ switch (level) {
+ case DEBUG:
+ debug(msg);
+ break;
+ case ERROR:
+ case FATAL:
+ error(msg);
+ break;
+ case INFO:
+ info(msg);
+ break;
+ case TRACE:
+ trace(msg);
+ break;
+ case WARN:
+ warn(msg);
+ break;
+ }
+ }
+
+ @Override
+ public void log(LogLevel level, String msg, Object[] os, Throwable t) {
+ switch (level) {
+ case DEBUG:
+ debug(msg, os, t);
+ break;
+ case ERROR:
+ case FATAL:
+ error(msg, os, t);
+ break;
+ case INFO:
+ info(msg, os, t);
+ break;
+ case TRACE:
+ trace(msg, os, t);
+ break;
+ case WARN:
+ warn(msg, os, t);
+ break;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
new file mode 100644
index 0000000..d1e73fb
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
@@ -0,0 +1,48 @@
+/*
+ * 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.mock;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.PropertyValue;
+import org.apache.nifi.controller.ConfigurationContext;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class MockConfigurationContext implements ConfigurationContext {
+
+ @Override
+ public PropertyValue getProperty(PropertyDescriptor property) {
+ return null;
+ }
+
+ @Override
+ public Map<PropertyDescriptor, String> getProperties() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public String getSchedulingPeriod() {
+ return "0 secs";
+ }
+
+ @Override
+ public Long getSchedulingPeriod(final TimeUnit timeUnit) {
+ return 0L;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceInitializationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceInitializationContext.java
new file mode 100644
index 0000000..b111ad2
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceInitializationContext.java
@@ -0,0 +1,68 @@
+/*
+ * 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.mock;
+
+import org.apache.nifi.components.state.StateManager;
+import org.apache.nifi.controller.ControllerServiceInitializationContext;
+import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.logging.ComponentLog;
+
+import java.io.File;
+
+/**
+ * A Mock ControllerServiceInitializationContext so that ControllerServices can
+ * be initialized for the purpose of generating documentation.
+ *
+ *
+ */
+public class MockControllerServiceInitializationContext implements ControllerServiceInitializationContext {
+
+ @Override
+ public String getIdentifier() {
+ return "mock-controller-service";
+ }
+
+ @Override
+ public ControllerServiceLookup getControllerServiceLookup() {
+ return new MockControllerServiceLookup();
+ }
+
+ @Override
+ public ComponentLog getLogger() {
+ return new MockComponentLogger();
+ }
+
+ @Override
+ public StateManager getStateManager() {
+ return null;
+ }
+
+ @Override
+ public String getKerberosServicePrincipal() {
+ return null;
+ }
+
+ @Override
+ public File getKerberosServiceKeytab() {
+ return null;
+ }
+
+ @Override
+ public File getKerberosConfigurationFile() {
+ return null;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceLookup.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceLookup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceLookup.java
new file mode 100644
index 0000000..5307ac4
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceLookup.java
@@ -0,0 +1,63 @@
+/*
+ * 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.mock;
+
+import org.apache.nifi.controller.ControllerService;
+import org.apache.nifi.controller.ControllerServiceLookup;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * A Mock ControllerServiceLookup that can be used so that
+ * ConfigurableComponents can be initialized for the purpose of generating
+ * documentation
+ *
+ *
+ */
+public class MockControllerServiceLookup implements ControllerServiceLookup {
+
+ @Override
+ public ControllerService getControllerService(final String serviceIdentifier) {
+ return null;
+ }
+
+ @Override
+ public boolean isControllerServiceEnabled(final String serviceIdentifier) {
+ return false;
+ }
+
+ @Override
+ public boolean isControllerServiceEnabled(final ControllerService service) {
+ return false;
+ }
+
+ @Override
+ public Set<String> getControllerServiceIdentifiers(final Class<? extends ControllerService> serviceType) throws IllegalArgumentException {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public boolean isControllerServiceEnabling(final String serviceIdentifier) {
+ return false;
+ }
+
+ @Override
+ public String getControllerServiceName(final String serviceIdentifier) {
+ return serviceIdentifier;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockNodeTypeProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockNodeTypeProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockNodeTypeProvider.java
new file mode 100644
index 0000000..61390e1
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockNodeTypeProvider.java
@@ -0,0 +1,40 @@
+/*
+ * 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.mock;
+
+import org.apache.nifi.controller.NodeTypeProvider;
+
+/**
+ * A Mock NodeTypeProvider that can be used so that
+ * ConfigurableComponents can be initialized for the purpose of generating
+ * documentation
+ *
+ *
+ */
+public class MockNodeTypeProvider implements NodeTypeProvider {
+
+ @Override
+ public boolean isClustered() {
+ return false;
+ }
+
+ @Override
+ public boolean isPrimary() {
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
new file mode 100644
index 0000000..cf2e2cf
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
@@ -0,0 +1,116 @@
+/*
+ * 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.mock;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.PropertyValue;
+import org.apache.nifi.components.state.StateManager;
+import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.Relationship;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+public class MockProcessContext implements ProcessContext {
+
+ @Override
+ public PropertyValue getProperty(PropertyDescriptor descriptor) {
+ return null;
+ }
+
+ @Override
+ public PropertyValue getProperty(String propertyName) {
+ return null;
+ }
+
+ @Override
+ public PropertyValue newPropertyValue(String rawValue) {
+ return null;
+ }
+
+ @Override
+ public void yield() {
+
+ }
+
+ @Override
+ public int getMaxConcurrentTasks() {
+ return 0;
+ }
+
+ @Override
+ public String getAnnotationData() {
+ return "";
+ }
+
+ @Override
+ public Map<PropertyDescriptor, String> getProperties() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public String encrypt(String unencrypted) {
+ return unencrypted;
+ }
+
+ @Override
+ public String decrypt(String encrypted) {
+ return encrypted;
+ }
+
+ @Override
+ public ControllerServiceLookup getControllerServiceLookup() {
+ return new MockControllerServiceLookup();
+ }
+
+ @Override
+ public Set<Relationship> getAvailableRelationships() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public boolean hasIncomingConnection() {
+ return true;
+ }
+
+ @Override
+ public boolean hasNonLoopConnection() {
+ return true;
+ }
+
+ @Override
+ public boolean hasConnection(Relationship relationship) {
+ return false;
+ }
+
+ @Override
+ public boolean isExpressionLanguagePresent(PropertyDescriptor property) {
+ return false;
+ }
+
+ @Override
+ public StateManager getStateManager() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessorInitializationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessorInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessorInitializationContext.java
new file mode 100644
index 0000000..d9320b2
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessorInitializationContext.java
@@ -0,0 +1,68 @@
+/*
+ * 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.mock;
+
+import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.controller.NodeTypeProvider;
+import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.processor.ProcessorInitializationContext;
+
+import java.io.File;
+
+/**
+ * A Mock ProcessorInitializationContext that can be used so that Processors can
+ * be initialized for the purpose of generating documentation.
+ *
+ *
+ */
+public class MockProcessorInitializationContext implements ProcessorInitializationContext {
+
+ @Override
+ public String getIdentifier() {
+ return "mock-processor";
+ }
+
+ @Override
+ public ComponentLog getLogger() {
+ return new MockComponentLogger();
+ }
+
+ @Override
+ public ControllerServiceLookup getControllerServiceLookup() {
+ return new MockControllerServiceLookup();
+ }
+
+ @Override
+ public NodeTypeProvider getNodeTypeProvider() {
+ return new MockNodeTypeProvider();
+ }
+
+ @Override
+ public String getKerberosServicePrincipal() {
+ return null;
+ }
+
+ @Override
+ public File getKerberosServiceKeytab() {
+ return null;
+ }
+
+ @Override
+ public File getKerberosConfigurationFile() {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockReportingInitializationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockReportingInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockReportingInitializationContext.java
new file mode 100644
index 0000000..630c657
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockReportingInitializationContext.java
@@ -0,0 +1,83 @@
+/*
+ * 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.mock;
+
+import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.reporting.ReportingInitializationContext;
+import org.apache.nifi.scheduling.SchedulingStrategy;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A Mock ReportingInitializationContext that can be used to initialize a
+ * ReportingTask for the purposes of documentation generation.
+ *
+ */
+public class MockReportingInitializationContext implements ReportingInitializationContext {
+
+ @Override
+ public String getIdentifier() {
+ return "mock-reporting-task";
+ }
+
+ @Override
+ public String getName() {
+ return "";
+ }
+
+ @Override
+ public long getSchedulingPeriod(TimeUnit timeUnit) {
+ return 0;
+ }
+
+ @Override
+ public ControllerServiceLookup getControllerServiceLookup() {
+ return new MockControllerServiceLookup();
+ }
+
+ @Override
+ public String getSchedulingPeriod() {
+ return "";
+ }
+
+ @Override
+ public SchedulingStrategy getSchedulingStrategy() {
+ return SchedulingStrategy.TIMER_DRIVEN;
+ }
+
+ @Override
+ public ComponentLog getLogger() {
+ return new MockComponentLogger();
+ }
+
+ @Override
+ public String getKerberosServicePrincipal() {
+ return null;
+ }
+
+ @Override
+ public File getKerberosServiceKeytab() {
+ return null;
+ }
+
+ @Override
+ public File getKerberosConfigurationFile() {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
index 745ed9c..1cff3af 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
@@ -19,29 +19,43 @@ package org.apache.nifi.nar;
import org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading;
import org.apache.nifi.authentication.LoginIdentityProvider;
import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.bundle.Bundle;
+import org.apache.nifi.bundle.BundleCoordinate;
+import org.apache.nifi.bundle.BundleDetails;
+import org.apache.nifi.components.ConfigurableComponent;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.state.StateProvider;
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.init.ConfigurableComponentInitializer;
+import org.apache.nifi.init.ConfigurableComponentInitializerFactory;
import org.apache.nifi.processor.Processor;
import org.apache.nifi.provenance.ProvenanceRepository;
+import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.reporting.ReportingTask;
+import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
/**
* Scans through the classpath to load all FlowFileProcessors, FlowFileComparators, and ReportingTasks using the service provider API and running through all classloaders (root, NARs).
@@ -53,10 +67,15 @@ public class ExtensionManager {
private static final Logger logger = LoggerFactory.getLogger(ExtensionManager.class);
+ public static final BundleCoordinate SYSTEM_BUNDLE_COORDINATE = new BundleCoordinate(
+ BundleCoordinate.DEFAULT_GROUP, "system", BundleCoordinate.DEFAULT_VERSION);
+
// Maps a service definition (interface) to those classes that implement the interface
private static final Map<Class, Set<Class>> definitionMap = new HashMap<>();
- private static final Map<String, ClassLoader> extensionClassloaderLookup = new HashMap<>();
+ private static final Map<String, List<Bundle>> classNameBundleLookup = new HashMap<>();
+ private static final Map<BundleCoordinate, Bundle> bundleCoordinateBundleLookup = new HashMap<>();
+ private static final Map<ClassLoader, Bundle> classLoaderBundleLookup = new HashMap<>();
private static final Set<String> requiresInstanceClassLoading = new HashSet<>();
private static final Map<String, ClassLoader> instanceClassloaderLookup = new ConcurrentHashMap<>();
@@ -73,28 +92,32 @@ public class ExtensionManager {
definitionMap.put(FlowFileRepository.class, new HashSet<>());
definitionMap.put(FlowFileSwapManager.class, new HashSet<>());
definitionMap.put(ContentRepository.class, new HashSet<>());
+ definitionMap.put(StateProvider.class, new HashSet<>());
}
/**
* Loads all FlowFileProcessor, FlowFileComparator, ReportingTask class types that can be found on the bootstrap classloader and by creating classloaders for all NARs found within the classpath.
- * @param extensionLoaders the loaders to scan through in search of extensions
+ * @param narBundles the bundles to scan through in search of extensions
*/
- public static void discoverExtensions(final Set<ClassLoader> extensionLoaders) {
- final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
-
+ public static void discoverExtensions(final Bundle systemBundle, final Set<Bundle> narBundles) {
// get the current context class loader
ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
- // consider the system class loader
- loadExtensions(systemClassLoader);
+ // load the system bundle first so that any extensions found in JARs directly in lib will be registered as
+ // being from the system bundle and not from all the other NARs
+ loadExtensions(systemBundle);
+ bundleCoordinateBundleLookup.put(systemBundle.getBundleDetails().getCoordinate(), systemBundle);
// consider each nar class loader
- for (final ClassLoader ncl : extensionLoaders) {
-
+ for (final Bundle bundle : narBundles) {
// Must set the context class loader to the nar classloader itself
// so that static initialization techniques that depend on the context class loader will work properly
+ final ClassLoader ncl = bundle.getClassLoader();
Thread.currentThread().setContextClassLoader(ncl);
- loadExtensions(ncl);
+ loadExtensions(bundle);
+
+ // Create a look-up from coordinate to bundle
+ bundleCoordinateBundleLookup.put(bundle.getBundleDetails().getCoordinate(), bundle);
}
// restore the current context class loader if appropriate
@@ -104,73 +127,195 @@ public class ExtensionManager {
}
/**
- * Loads extensions from the specified class loader.
+ * Returns a bundle representing the system class loader.
+ *
+ * @param niFiProperties a NiFiProperties instance which will be used to obtain the default NAR library path,
+ * which will become the working directory of the returned bundle
+ * @return a bundle for the system class loader
+ */
+ public static Bundle createSystemBundle(final NiFiProperties niFiProperties) {
+ final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+
+ final String narLibraryDirectory = niFiProperties.getProperty(NiFiProperties.NAR_LIBRARY_DIRECTORY);
+ if (StringUtils.isBlank(narLibraryDirectory)) {
+ throw new IllegalStateException("Unable to create system bundle because " + NiFiProperties.NAR_LIBRARY_DIRECTORY + " was null or empty");
+ }
+
+ final BundleDetails systemBundleDetails = new BundleDetails.Builder()
+ .workingDir(new File(narLibraryDirectory))
+ .coordinate(SYSTEM_BUNDLE_COORDINATE)
+ .build();
+
+ return new Bundle(systemBundleDetails, systemClassLoader);
+ }
+
+ /**
+ * Loads extensions from the specified bundle.
*
- * @param classLoader from which to load extensions
+ * @param bundle from which to load extensions
*/
@SuppressWarnings("unchecked")
- private static void loadExtensions(final ClassLoader classLoader) {
+ private static void loadExtensions(final Bundle bundle) {
for (final Map.Entry<Class, Set<Class>> entry : definitionMap.entrySet()) {
- final ServiceLoader<?> serviceLoader = ServiceLoader.load(entry.getKey(), classLoader);
+ final boolean isControllerService = ControllerService.class.equals(entry.getKey());
+ final boolean isProcessor = Processor.class.equals(entry.getKey());
+ final boolean isReportingTask = ReportingTask.class.equals(entry.getKey());
+ final ServiceLoader<?> serviceLoader = ServiceLoader.load(entry.getKey(), bundle.getClassLoader());
for (final Object o : serviceLoader) {
- registerServiceClass(o.getClass(), extensionClassloaderLookup, classLoader, entry.getValue());
+ // only consider extensions discovered directly in this bundle
+ boolean registerExtension = bundle.getClassLoader().equals(o.getClass().getClassLoader());
+
+ if (registerExtension) {
+ final Class extensionType = o.getClass();
+ if (isControllerService && !checkControllerServiceEligibility(extensionType)) {
+ registerExtension = false;
+ logger.error(String.format(
+ "Skipping Controller Service %s because it is bundled with its supporting APIs and requires instance class loading.", extensionType.getName()));
+ }
+
+ final boolean canReferenceControllerService = (isControllerService || isProcessor || isReportingTask) && o instanceof ConfigurableComponent;
+ if (canReferenceControllerService && !checkControllerServiceReferenceEligibility((ConfigurableComponent) o, bundle.getClassLoader())) {
+ registerExtension = false;
+ logger.error(String.format(
+ "Skipping component %s because it is bundled with its referenced Controller Service APIs and requires instance class loading.", extensionType.getName()));
+ }
+
+ if (registerExtension) {
+ registerServiceClass(o.getClass(), classNameBundleLookup, bundle, entry.getValue());
+ }
+ }
}
+
+ classLoaderBundleLookup.put(bundle.getClassLoader(), bundle);
}
}
+ private static boolean checkControllerServiceReferenceEligibility(final ConfigurableComponent component, final ClassLoader classLoader) {
+ // if the extension does not require instance classloading, its eligible
+ final boolean requiresInstanceClassLoading = component.getClass().isAnnotationPresent(RequiresInstanceClassLoading.class);
+
+ ConfigurableComponentInitializer initializer = null;
+ try {
+ initializer = ConfigurableComponentInitializerFactory.createComponentInitializer(component.getClass());
+ initializer.initialize(component);
+
+ final Set<Class> cobundledApis = new HashSet<>();
+ try (final NarCloseable closeable = NarCloseable.withComponentNarLoader(component.getClass().getClassLoader())) {
+ final List<PropertyDescriptor> descriptors = component.getPropertyDescriptors();
+ if (descriptors != null && !descriptors.isEmpty()) {
+ for (final PropertyDescriptor descriptor : descriptors) {
+ final Class<? extends ControllerService> serviceApi = descriptor.getControllerServiceDefinition();
+ if (serviceApi != null && classLoader.equals(serviceApi.getClassLoader())) {
+ cobundledApis.add(serviceApi);
+ }
+ }
+ }
+ }
+
+ if (!cobundledApis.isEmpty()) {
+ logger.warn(String.format(
+ "Component %s is bundled with its referenced Controller Service APIs %s. The service APIs should not be bundled with component implementations that reference it.",
+ component.getClass().getName(), StringUtils.join(cobundledApis.stream().map(cls -> cls.getName()).collect(Collectors.toSet()), ", ")));
+ }
+
+ // the component is eligible when it does not require instance classloading or when the supporting APIs are bundled in a parent NAR
+ return requiresInstanceClassLoading == false || cobundledApis.isEmpty();
+ } catch (final InitializationException e) {
+ logger.warn(String.format("Unable to verify if component %s references any bundled Controller Service APIs due to %s", component.getClass().getName(), e.getMessage()));
+ return true;
+ } finally {
+ if (initializer != null) {
+ initializer.teardown(component);
+ }
+ }
+ }
+
+ private static boolean checkControllerServiceEligibility(Class extensionType) {
+ final Class originalExtensionType = extensionType;
+ final ClassLoader originalExtensionClassLoader = extensionType.getClassLoader();
+
+ // if the extension does not require instance classloading, its eligible
+ final boolean requiresInstanceClassLoading = extensionType.isAnnotationPresent(RequiresInstanceClassLoading.class);
+
+ final Set<Class> cobundledApis = new HashSet<>();
+ while (extensionType != null) {
+ for (final Class i : extensionType.getInterfaces()) {
+ if (originalExtensionClassLoader.equals(i.getClassLoader())) {
+ cobundledApis.add(i);
+ }
+ }
+
+ extensionType = extensionType.getSuperclass();
+ }
+
+ if (!cobundledApis.isEmpty()) {
+ logger.warn(String.format("Controller Service %s is bundled with its supporting APIs %s. The service APIs should not be bundled with the implementations.",
+ originalExtensionType.getName(), StringUtils.join(cobundledApis.stream().map(cls -> cls.getName()).collect(Collectors.toSet()), ", ")));
+ }
+
+ // the service is eligible when it does not require instance classloading or when the supporting APIs are bundled in a parent NAR
+ return requiresInstanceClassLoading == false || cobundledApis.isEmpty();
+ }
+
/**
- * Registers extension for the specified type from the specified ClassLoader.
+ * Registers extension for the specified type from the specified Bundle.
*
* @param type the extension type
- * @param classloaderMap mapping of classname to classloader
- * @param classLoader the classloader being mapped to
+ * @param classNameBundleMap mapping of classname to Bundle
+ * @param bundle the Bundle being mapped to
* @param classes to map to this classloader but which come from its ancestors
*/
- private static void registerServiceClass(final Class<?> type, final Map<String, ClassLoader> classloaderMap, final ClassLoader classLoader, final Set<Class> classes) {
+ private static void registerServiceClass(final Class<?> type, final Map<String, List<Bundle>> classNameBundleMap, final Bundle bundle, final Set<Class> classes) {
final String className = type.getName();
- final ClassLoader registeredClassLoader = classloaderMap.get(className);
- // see if this class is already registered (this should happen when the class is loaded by an ancestor of the specified classloader)
- if (registeredClassLoader == null) {
- classloaderMap.put(className, classLoader);
- classes.add(type);
+ // get the bundles that have already been registered for the class name
+ List<Bundle> registeredBundles = classNameBundleMap.get(className);
- // keep track of which classes require a class loader per component instance
- if (type.isAnnotationPresent(RequiresInstanceClassLoading.class)) {
- requiresInstanceClassLoading.add(className);
+ if (registeredBundles == null) {
+ registeredBundles = new ArrayList<>();
+ classNameBundleMap.put(className, registeredBundles);
+ }
+
+ boolean alreadyRegistered = false;
+ for (final Bundle registeredBundle : registeredBundles) {
+ final BundleCoordinate registeredCoordinate = registeredBundle.getBundleDetails().getCoordinate();
+
+ // if the incoming bundle has the same coordinate as one of the registered bundles then consider it already registered
+ if (registeredCoordinate.equals(bundle.getBundleDetails().getCoordinate())) {
+ alreadyRegistered = true;
+ break;
}
- } else {
- boolean loadedFromAncestor = false;
-
- // determine if this class was loaded from an ancestor
- ClassLoader ancestorClassLoader = classLoader.getParent();
- while (ancestorClassLoader != null) {
- if (ancestorClassLoader == registeredClassLoader) {
- loadedFromAncestor = true;
- break;
- }
- ancestorClassLoader = ancestorClassLoader.getParent();
+ // if the type wasn't loaded from an ancestor, and the type isn't a processor, cs, or reporting task, then
+ // fail registration because we don't support multiple versions of any other types
+ if (!multipleVersionsAllowed(type)) {
+ throw new IllegalStateException("Attempt was made to load " + className + " from "
+ + bundle.getBundleDetails().getCoordinate().getCoordinate()
+ + " but that class name is already loaded/registered from " + registeredBundle.getBundleDetails().getCoordinate()
+ + " and multiple versions are not supported for this type"
+ );
}
+ }
- // if this class was loaded from a non ancestor class loader, report potential unexpected behavior
- if (!loadedFromAncestor) {
- logger.warn("Attempt was made to load " + className + " from " + classLoader
- + " but that class name is already loaded/registered from " + registeredClassLoader
- + ". This may cause unpredictable behavior. Order of NARs is not guaranteed.");
+ // if none of the above was true then register the new bundle
+ if (!alreadyRegistered) {
+ registeredBundles.add(bundle);
+ classes.add(type);
+
+ if (type.isAnnotationPresent(RequiresInstanceClassLoading.class)) {
+ requiresInstanceClassLoading.add(className);
}
}
+
}
/**
- * Determines the effective classloader for classes of the given type. If returns null it indicates the given type is not known or was not detected.
- *
- * @param classType to lookup the classloader of
- * @return String of fully qualified class name; null if not a detected type
+ * @param type a Class that we found from a service loader
+ * @return true if the given class is a processor, controller service, or reporting task
*/
- public static ClassLoader getClassLoader(final String classType) {
- return extensionClassloaderLookup.get(classType);
+ private static boolean multipleVersionsAllowed(Class<?> type) {
+ return Processor.class.isAssignableFrom(type) || ControllerService.class.isAssignableFrom(type) || ReportingTask.class.isAssignableFrom(type);
}
/**
@@ -178,40 +323,50 @@ public class ExtensionManager {
*
* @param classType the type of class to lookup the ClassLoader for
* @param instanceIdentifier the identifier of the specific instance of the classType to look up the ClassLoader for
+ * @param bundle the bundle where the classType exists
* @return the ClassLoader for the given instance of the given type, or null if the type is not a detected extension type
*/
- public static ClassLoader getClassLoader(final String classType, final String instanceIdentifier) {
- if (StringUtils.isEmpty(classType) || StringUtils.isEmpty(instanceIdentifier)) {
- throw new IllegalArgumentException("Class Type and Instance Identifier must be provided");
+ public static ClassLoader createInstanceClassLoader(final String classType, final String instanceIdentifier, final Bundle bundle) {
+ if (StringUtils.isEmpty(classType)) {
+ throw new IllegalArgumentException("Class-Type is required");
}
- // Check if we already have a ClassLoader for this instance
- ClassLoader instanceClassLoader = instanceClassloaderLookup.get(instanceIdentifier);
+ if (StringUtils.isEmpty(instanceIdentifier)) {
+ throw new IllegalArgumentException("Instance Identifier is required");
+ }
- // If we don't then we'll create a new ClassLoader for this instance and add it to the map for future lookups
- if (instanceClassLoader == null) {
- final ClassLoader registeredClassLoader = getClassLoader(classType);
- if (registeredClassLoader == null) {
- return null;
- }
+ if (bundle == null) {
+ throw new IllegalArgumentException("Bundle is required");
+ }
- // If the class is annotated with @RequiresInstanceClassLoading and the registered ClassLoader is a URLClassLoader
- // then make a new InstanceClassLoader that is a full copy of the NAR Class Loader, otherwise create an empty
- // InstanceClassLoader that has the NAR ClassLoader as a parent
- if (requiresInstanceClassLoading.contains(classType) && (registeredClassLoader instanceof URLClassLoader)) {
- final URLClassLoader registeredUrlClassLoader = (URLClassLoader) registeredClassLoader;
- instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, registeredUrlClassLoader.getURLs(), registeredUrlClassLoader.getParent());
- } else {
- instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, new URL[0], registeredClassLoader);
- }
+ final ClassLoader bundleClassLoader = bundle.getClassLoader();
- instanceClassloaderLookup.put(instanceIdentifier, instanceClassLoader);
+ // If the class is annotated with @RequiresInstanceClassLoading and the registered ClassLoader is a URLClassLoader
+ // then make a new InstanceClassLoader that is a full copy of the NAR Class Loader, otherwise create an empty
+ // InstanceClassLoader that has the NAR ClassLoader as a parent
+ ClassLoader instanceClassLoader;
+ if (requiresInstanceClassLoading.contains(classType) && (bundleClassLoader instanceof URLClassLoader)) {
+ final URLClassLoader registeredUrlClassLoader = (URLClassLoader) bundleClassLoader;
+ instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, registeredUrlClassLoader.getURLs(), registeredUrlClassLoader.getParent());
+ } else {
+ instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, new URL[0], bundleClassLoader);
}
+ instanceClassloaderLookup.put(instanceIdentifier, instanceClassLoader);
return instanceClassLoader;
}
/**
+ * Retrieves the InstanceClassLoader for the component with the given identifier.
+ *
+ * @param instanceIdentifier the identifier of a component
+ * @return the instance class loader for the component
+ */
+ public static ClassLoader getInstanceClassLoader(final String instanceIdentifier) {
+ return instanceClassloaderLookup.get(instanceIdentifier);
+ }
+
+ /**
* Removes the ClassLoader for the given instance and closes it if necessary.
*
* @param instanceIdentifier the identifier of a component to remove the ClassLoader for
@@ -241,10 +396,56 @@ public class ExtensionManager {
* @return true if the class is found in the set of classes requiring instance level class loading, false otherwise
*/
public static boolean requiresInstanceClassLoading(final String classType) {
+ if (classType == null) {
+ throw new IllegalArgumentException("Class type cannot be null");
+ }
return requiresInstanceClassLoading.contains(classType);
}
+ /**
+ * Retrieves the bundles that have a class with the given name.
+ *
+ * @param classType the class name of an extension
+ * @return the list of bundles that contain an extension with the given class name
+ */
+ public static List<Bundle> getBundles(final String classType) {
+ if (classType == null) {
+ throw new IllegalArgumentException("Class type cannot be null");
+ }
+ final List<Bundle> bundles = classNameBundleLookup.get(classType);
+ return bundles == null ? Collections.emptyList() : new ArrayList<>(bundles);
+ }
+
+ /**
+ * Retrieves the bundle with the given coordinate.
+ *
+ * @param bundleCoordinate a coordinate to look up
+ * @return the bundle with the given coordinate, or null if none exists
+ */
+ public static Bundle getBundle(final BundleCoordinate bundleCoordinate) {
+ if (bundleCoordinate == null) {
+ throw new IllegalArgumentException("BundleCoordinate cannot be null");
+ }
+ return bundleCoordinateBundleLookup.get(bundleCoordinate);
+ }
+
+ /**
+ * Retrieves the bundle for the given class loader.
+ *
+ * @param classLoader the class loader to look up the bundle for
+ * @return the bundle for the given class loader
+ */
+ public static Bundle getBundle(final ClassLoader classLoader) {
+ if (classLoader == null) {
+ throw new IllegalArgumentException("ClassLoader cannot be null");
+ }
+ return classLoaderBundleLookup.get(classLoader);
+ }
+
public static Set<Class> getExtensions(final Class<?> definition) {
+ if (definition == null) {
+ throw new IllegalArgumentException("Class cannot be null");
+ }
final Set<Class> extensions = definitionMap.get(definition);
return (extensions == null) ? Collections.<Class>emptySet() : extensions;
}
@@ -252,12 +453,21 @@ public class ExtensionManager {
public static void logClassLoaderMapping() {
final StringBuilder builder = new StringBuilder();
- builder.append("Extension Type Mapping to Classloader:");
+ builder.append("Extension Type Mapping to Bundle:");
for (final Map.Entry<Class, Set<Class>> entry : definitionMap.entrySet()) {
- builder.append("\n\t=== ").append(entry.getKey().getSimpleName()).append(" type || Classloader ===");
+ builder.append("\n\t=== ").append(entry.getKey().getSimpleName()).append(" Type ===");
for (final Class type : entry.getValue()) {
- builder.append("\n\t").append(type.getName()).append(" || ").append(getClassLoader(type.getName()));
+ final List<Bundle> bundles = classNameBundleLookup.containsKey(type.getName())
+ ? classNameBundleLookup.get(type.getName()) : Collections.emptyList();
+
+ builder.append("\n\t").append(type.getName());
+
+ for (final Bundle bundle : bundles) {
+ final String coordinate = bundle.getBundleDetails().getCoordinate().getCoordinate();
+ final String workingDir = bundle.getBundleDetails().getWorkingDirectory().getPath();
+ builder.append("\n\t\t").append(coordinate).append(" || ").append(workingDir);
+ }
}
builder.append("\n\t=== End ").append(entry.getKey().getSimpleName()).append(" types ===");
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionMapping.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionMapping.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionMapping.java
index c478d97..698eb57 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionMapping.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionMapping.java
@@ -16,58 +16,108 @@
*/
package org.apache.nifi.nar;
-import java.util.ArrayList;
+import org.apache.nifi.bundle.BundleCoordinate;
+
import java.util.Collection;
import java.util.Collections;
-import java.util.List;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
public class ExtensionMapping {
- private final List<String> processorNames = new ArrayList<>();
- private final List<String> controllerServiceNames = new ArrayList<>();
- private final List<String> reportingTaskNames = new ArrayList<>();
+ private final Map<String, Set<BundleCoordinate>> processorNames = new HashMap<>();
+ private final Map<String, Set<BundleCoordinate>> controllerServiceNames = new HashMap<>();
+ private final Map<String, Set<BundleCoordinate>> reportingTaskNames = new HashMap<>();
+
+ private final BiFunction<Set<BundleCoordinate>, Set<BundleCoordinate>, Set<BundleCoordinate>> merger = (oldValue, newValue) -> {
+ final Set<BundleCoordinate> merged = new HashSet<>();
+ merged.addAll(oldValue);
+ merged.addAll(newValue);
+ return merged;
+ };
- void addProcessor(final String processorName) {
- processorNames.add(processorName);
+ void addProcessor(final BundleCoordinate coordinate, final String processorName) {
+ processorNames.computeIfAbsent(processorName, name -> new HashSet<>()).add(coordinate);
}
- void addAllProcessors(final Collection<String> processorNames) {
- this.processorNames.addAll(processorNames);
+ void addAllProcessors(final BundleCoordinate coordinate, final Collection<String> processorNames) {
+ processorNames.forEach(name -> {
+ addProcessor(coordinate, name);
+ });
}
- void addControllerService(final String controllerServiceName) {
- controllerServiceNames.add(controllerServiceName);
+ void addControllerService(final BundleCoordinate coordinate, final String controllerServiceName) {
+ controllerServiceNames.computeIfAbsent(controllerServiceName, name -> new HashSet<>()).add(coordinate);
}
- void addAllControllerServices(final Collection<String> controllerServiceNames) {
- this.controllerServiceNames.addAll(controllerServiceNames);
+ void addAllControllerServices(final BundleCoordinate coordinate, final Collection<String> controllerServiceNames) {
+ controllerServiceNames.forEach(name -> {
+ addControllerService(coordinate, name);
+ });
}
- void addReportingTask(final String reportingTaskName) {
- reportingTaskNames.add(reportingTaskName);
+ void addReportingTask(final BundleCoordinate coordinate, final String reportingTaskName) {
+ reportingTaskNames.computeIfAbsent(reportingTaskName, name -> new HashSet<>()).add(coordinate);
}
- void addAllReportingTasks(final Collection<String> reportingTaskNames) {
- this.reportingTaskNames.addAll(reportingTaskNames);
+ void addAllReportingTasks(final BundleCoordinate coordinate, final Collection<String> reportingTaskNames) {
+ reportingTaskNames.forEach(name -> {
+ addReportingTask(coordinate, name);
+ });
}
- public List<String> getProcessorNames() {
- return Collections.unmodifiableList(processorNames);
+ void merge(final ExtensionMapping other) {
+ other.getProcessorNames().forEach((name, otherCoordinates) -> {
+ processorNames.merge(name, otherCoordinates, merger);
+ });
+ other.getControllerServiceNames().forEach((name, otherCoordinates) -> {
+ controllerServiceNames.merge(name, otherCoordinates, merger);
+ });
+ other.getReportingTaskNames().forEach((name, otherCoordinates) -> {
+ reportingTaskNames.merge(name, otherCoordinates, merger);
+ });
}
- public List<String> getControllerServiceNames() {
- return Collections.unmodifiableList(controllerServiceNames);
+ public Map<String, Set<BundleCoordinate>> getProcessorNames() {
+ return Collections.unmodifiableMap(processorNames);
}
- public List<String> getReportingTaskNames() {
- return Collections.unmodifiableList(reportingTaskNames);
+ public Map<String, Set<BundleCoordinate>> getControllerServiceNames() {
+ return Collections.unmodifiableMap(controllerServiceNames);
}
- public List<String> getAllExtensionNames() {
- final List<String> extensionNames = new ArrayList<>();
- extensionNames.addAll(processorNames);
- extensionNames.addAll(controllerServiceNames);
- extensionNames.addAll(reportingTaskNames);
+ public Map<String, Set<BundleCoordinate>> getReportingTaskNames() {
+ return Collections.unmodifiableMap(reportingTaskNames);
+ }
+
+ public Map<String, Set<BundleCoordinate>> getAllExtensionNames() {
+ final Map<String, Set<BundleCoordinate>> extensionNames = new HashMap<>();
+ extensionNames.putAll(processorNames);
+ extensionNames.putAll(controllerServiceNames);
+ extensionNames.putAll(reportingTaskNames);
return extensionNames;
}
+
+ public int size() {
+ int size = 0;
+
+ for (final Set<BundleCoordinate> coordinates : processorNames.values()) {
+ size += coordinates.size();
+ }
+ for (final Set<BundleCoordinate> coordinates : controllerServiceNames.values()) {
+ size += coordinates.size();
+ }
+ for (final Set<BundleCoordinate> coordinates : reportingTaskNames.values()) {
+ size += coordinates.size();
+ }
+
+ return size;
+ }
+
+ public boolean isEmpty() {
+ return processorNames.isEmpty() && controllerServiceNames.isEmpty() && reportingTaskNames.isEmpty();
+ }
}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarBundleUtil.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarBundleUtil.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarBundleUtil.java
new file mode 100644
index 0000000..62afb37
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarBundleUtil.java
@@ -0,0 +1,74 @@
+/*
+ * 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 org.apache.nifi.bundle.BundleCoordinate;
+import org.apache.nifi.bundle.BundleDetails;
+import org.apache.nifi.util.StringUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+public class NarBundleUtil {
+
+ /**
+ * Creates a BundleDetails from the given NAR working directory.
+ *
+ * @param narDirectory the directory of an exploded NAR which contains a META-INF/MANIFEST.MF
+ *
+ * @return the BundleDetails constructed from the information in META-INF/MANIFEST.MF
+ */
+ public static BundleDetails fromNarDirectory(final File narDirectory) throws IOException, IllegalStateException {
+ if (narDirectory == null) {
+ throw new IllegalArgumentException("NAR Directory cannot be null");
+ }
+
+ final File manifestFile = new File(narDirectory, "META-INF/MANIFEST.MF");
+ try (final FileInputStream fis = new FileInputStream(manifestFile)) {
+ final Manifest manifest = new Manifest(fis);
+ final Attributes attributes = manifest.getMainAttributes();
+
+ final BundleDetails.Builder builder = new BundleDetails.Builder();
+ builder.workingDir(narDirectory);
+
+ final String group = attributes.getValue(NarManifestEntry.NAR_GROUP.getManifestName());
+ final String id = attributes.getValue(NarManifestEntry.NAR_ID.getManifestName());
+ final String version = attributes.getValue(NarManifestEntry.NAR_VERSION.getManifestName());
+ builder.coordinate(new BundleCoordinate(group, id, version));
+
+ final String dependencyGroup = attributes.getValue(NarManifestEntry.NAR_DEPENDENCY_GROUP.getManifestName());
+ final String dependencyId = attributes.getValue(NarManifestEntry.NAR_DEPENDENCY_ID.getManifestName());
+ final String dependencyVersion = attributes.getValue(NarManifestEntry.NAR_DEPENDENCY_VERSION.getManifestName());
+ if (!StringUtils.isBlank(dependencyId)) {
+ builder.dependencyCoordinate(new BundleCoordinate(dependencyGroup, dependencyId, dependencyVersion));
+ }
+
+ builder.buildBranch(attributes.getValue(NarManifestEntry.BUILD_BRANCH.getManifestName()));
+ builder.buildTag(attributes.getValue(NarManifestEntry.BUILD_TAG.getManifestName()));
+ builder.buildRevision(attributes.getValue(NarManifestEntry.BUILD_REVISION.getManifestName()));
+ builder.buildTimestamp(attributes.getValue(NarManifestEntry.BUILD_TIMESTAMP.getManifestName()));
+ builder.buildJdk(attributes.getValue(NarManifestEntry.BUILD_JDK.getManifestName()));
+ builder.builtBy(attributes.getValue(NarManifestEntry.BUILT_BY.getManifestName()));
+
+ return builder.build();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoader.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoader.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoader.java
index 8d55169..eb4539c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoader.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoader.java
@@ -21,6 +21,8 @@ import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Comparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -192,8 +194,12 @@ public class NarClassLoader extends URLClassLoader {
}
addURL(dependencies.toURI().toURL());
if (dependencies.isDirectory()) {
- for (File libJar : dependencies.listFiles(JAR_FILTER)) {
- addURL(libJar.toURI().toURL());
+ final File[] jarFiles = dependencies.listFiles(JAR_FILTER);
+ if (jarFiles != null) {
+ Arrays.sort(jarFiles, Comparator.comparing(File::getName));
+ for (File libJar : jarFiles) {
+ addURL(libJar.toURI().toURL());
+ }
}
}
}