Repository: incubator-nifi
Updated Branches:
  refs/heads/NIFI-250 e750579d7 -> 6c0587785


NIFI-250:
- Starting to refactor support for UI extensions.
- Deprecating previous support.

Project: http://git-wip-us.apache.org/repos/asf/incubator-nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-nifi/commit/6c058778
Tree: http://git-wip-us.apache.org/repos/asf/incubator-nifi/tree/6c058778
Diff: http://git-wip-us.apache.org/repos/asf/incubator-nifi/diff/6c058778

Branch: refs/heads/NIFI-250
Commit: 6c058778534adae967ee34ec5fb2b8c20b66d43b
Parents: e750579
Author: Matt Gilman <[email protected]>
Authored: Wed Mar 18 16:09:44 2015 -0400
Committer: Matt Gilman <[email protected]>
Committed: Wed Mar 18 16:09:44 2015 -0400

----------------------------------------------------------------------
 .../apache/nifi/web/ComponentConfiguration.java | 122 ++++++
 .../apache/nifi/web/ConfigurationAction.java    |  86 +++++
 .../org/apache/nifi/web/NiFiWebContext.java     |   1 +
 .../apache/nifi/web/NiFiWebContextConfig.java   |   1 +
 .../nifi/web/ProcessorConfigurationAction.java  |   1 +
 .../java/org/apache/nifi/web/ProcessorInfo.java |   1 +
 .../nifi/web/UiExtensionRequestContext.java     |  95 +++++
 ...kControllerServiceInitializationContext.java |   6 +
 .../mock/MockControllerServiceLookup.java       |   5 +
 .../MockReportingInitializationContext.java     |   7 +
 .../web/HttpServletRequestContextConfig.java    |   1 +
 .../nifi-framework/nifi-web/nifi-jetty/pom.xml  |  10 +
 .../nifi-ui-extension-controller/pom.xml        |  66 ++++
 .../extension/ConfigureComponentController.java | 253 +++++++++++++
 .../src/main/webapp/WEB-INF/web.xml             |  26 ++
 .../nifi-web/nifi-ui-extension/pom.xml          |  21 ++
 .../apache/nifi/ui/extension/UiExtension.java   |  46 +++
 .../nifi/ui/extension/UiExtensionMapping.java   |  40 ++
 .../nifi/ui/extension/UiExtensionType.java      |  26 ++
 .../controller/UiExtensionControllerFacade.java | 101 +++++
 .../UiExtensionControllerRequest.java           |  64 ++++
 .../nifi-web/nifi-web-api/pom.xml               |   5 +
 .../apache/nifi/web/StandardNiFiWebContext.java |   1 +
 .../StandardUiExtensionControllerFacade.java    | 377 +++++++++++++++++++
 .../src/main/resources/nifi-web-api-context.xml |   7 +
 .../nifi-framework/nifi-web/pom.xml             |  13 +-
 nifi/pom.xml                                    |   5 +
 27 files changed, 1384 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-api/src/main/java/org/apache/nifi/web/ComponentConfiguration.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ComponentConfiguration.java 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ComponentConfiguration.java
new file mode 100644
index 0000000..bb47760
--- /dev/null
+++ 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ComponentConfiguration.java
@@ -0,0 +1,122 @@
+/*
+ * 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.web;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ *
+ */
+public class ComponentConfiguration {
+
+    private final String id;
+    private final String name;
+    private final String type;
+    private final String state;
+    private final String annotationData;
+    private final Map<String, String> properties;
+    private final Collection<String> validationErrors;
+
+    private ComponentConfiguration(final Builder builder) {
+        this.id = builder.id;
+        this.name = builder.name;
+        this.type = builder.type;
+        this.state = builder.state;
+        this.annotationData = builder.annotationData;
+        this.properties = builder.properties;
+        this.validationErrors = builder.validationErrors;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getType() {
+        return type;
+    }
+    
+    public String getState() {
+        return state;
+    }
+
+    public String getAnnotationData() {
+        return annotationData;
+    }
+
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
+    public Collection<String> getValidationErrors() {
+        return validationErrors;
+    }
+
+    public static final class Builder {
+
+        private String id;
+        private String name;
+        private String type;
+        private String state;
+        private String annotationData;
+        private Map<String, String> properties;
+        private Collection<String> validationErrors;
+
+        public Builder id(final String id) {
+            this.id = id;
+            return this;
+        }
+
+        public Builder name(final String name) {
+            this.name = name;
+            return this;
+        }
+        
+        public Builder type(final String type) {
+            this.type = type;
+            return this;
+        }
+
+        public Builder state(final String state) {
+            this.state = state;
+            return this;
+        }
+
+        public Builder annotationData(final String annotationData) {
+            this.annotationData = annotationData;
+            return this;
+        }
+
+        public Builder properties(final Map<String, String> properties) {
+            this.properties = properties;
+            return this;
+        }
+
+        public Builder validateErrors(final Collection<String> 
validationErrors) {
+            this.validationErrors = validationErrors;
+            return this;
+        }
+
+        public ComponentConfiguration build() {
+            return new ComponentConfiguration(this);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-api/src/main/java/org/apache/nifi/web/ConfigurationAction.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ConfigurationAction.java 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ConfigurationAction.java
new file mode 100644
index 0000000..d46d489
--- /dev/null
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ConfigurationAction.java
@@ -0,0 +1,86 @@
+/*
+ * 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.web;
+
+/**
+ *
+ */
+public class ConfigurationAction {
+
+    private final String field;
+    private final String previousValue;
+    private final String value;
+
+    private ConfigurationAction(final Builder builder) {
+        this.field = builder.field;
+        this.previousValue = builder.previousValue;
+        this.value = builder.value;
+    }
+
+    /**
+     * Gets the name of the field, property, etc that has been modified.
+     *
+     * @return
+     */
+    public String getField() {
+        return field;
+    }
+
+    /**
+     * Gets the previous value.
+     *
+     * @return
+     */
+    public String getPreviousValue() {
+        return previousValue;
+    }
+
+    /**
+     * Gets the new value.
+     *
+     * @return
+     */
+    public String getValue() {
+        return value;
+    }
+
+    public static class Builder {
+
+        private String field;
+        private String previousValue;
+        private String value;
+
+        public Builder field(final String field) {
+            this.field = field;
+            return this;
+        }
+
+        public Builder previousValue(final String previousValue) {
+            this.previousValue = previousValue;
+            return this;
+        }
+
+        public Builder value(final String value) {
+            this.value = value;
+            return this;
+        }
+
+        public ConfigurationAction build() {
+            return new ConfigurationAction(this);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java
index 4c4f25d..01702ad 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java
@@ -24,6 +24,7 @@ import org.apache.nifi.controller.ControllerService;
  * NiFi web context providing limited access to dataflow configuration for
  * processor custom UIs.
  */
+@Deprecated
 public interface NiFiWebContext {
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
index 808b9d6..2df94e4 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
@@ -19,6 +19,7 @@ package org.apache.nifi.web;
 /**
  * Context configuration for methods invoked from the NiFiWebContext.
  */
+@Deprecated
 public interface NiFiWebContextConfig {
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java
 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java
index 8385e4a..ce5e069 100644
--- 
a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java
+++ 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java
@@ -19,6 +19,7 @@ package org.apache.nifi.web;
 /**
  *
  */
+@Deprecated
 public class ProcessorConfigurationAction {
 
     private final String processorId;

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java
index 0481098..e87e73e 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java
@@ -22,6 +22,7 @@ import java.util.Map;
 /**
  *
  */
+@Deprecated
 public class ProcessorInfo {
 
     private final String id;

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-api/src/main/java/org/apache/nifi/web/UiExtensionRequestContext.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-api/src/main/java/org/apache/nifi/web/UiExtensionRequestContext.java
 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/UiExtensionRequestContext.java
new file mode 100644
index 0000000..24c4226
--- /dev/null
+++ 
b/nifi/nifi-api/src/main/java/org/apache/nifi/web/UiExtensionRequestContext.java
@@ -0,0 +1,95 @@
+/*
+ * 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.web;
+
+import java.util.Collection;
+
+import org.apache.nifi.controller.ControllerService;
+
+/**
+ * NiFi web context providing limited access to dataflow configuration for
+ * processor custom UIs.
+ */
+public interface UiExtensionRequestContext {
+    
+    public static final String ATTRIBUTE_KEY = "ui-extension-request-context";
+
+    /**
+     * Gets the ControllerService for the specified identifier. If a
+     * corresponding service cannot be found, null is returned. If this NiFi is
+     * clustered, the only services available will be those those
+     * availability is NCM only.
+     *
+     * @param serviceIdentifier
+     * @return
+     */
+    ControllerService getControllerService(String serviceIdentifier);
+
+    /**
+     * Provides a mechanism for custom UIs to save actions to appear in NiFi
+     * configuration history. Note all fields within each Action must be
+     * populated. Null values will result in a failure to insert the audit
+     * record. Since the saving to these actions is separate from the actual
+     * configuration change, a failure to insert here will just generate a
+     * warning log message. The recording of these actions typically happens
+     * after a configuration change is applied. Since those changes have 
already
+     * been applied to the flow, we cannot revert them because of a failure to
+     * insert an audit record.
+     *
+     * @param actions
+     */
+    void saveActions(Collection<ConfigurationAction> actions);
+
+    /**
+     * Gets the current user dn. Returns null if no user is found.
+     *
+     * @return
+     */
+    String getCurrentUserDn();
+
+    /**
+     * Gets the current user name. Returns null if no user is found.
+     *
+     * @return
+     */
+    String getCurrentUserName();
+
+    /**
+     * Sets the annotation data for the underlying component.
+     * 
+     * @param annotationData
+     * @return the configuration for the underlying component
+     * @throws ResourceNotFoundException if the underlying component does not 
exit
+     * @throws InvalidRevisionException if a revision other than the current
+     * revision is given
+     * @throws ClusterRequestException if the annotation data was unable to be
+     * set for the underlying component. This exception will only be thrown 
when operating
+     * in a cluster.
+     */
+    ComponentConfiguration setAnnotationData(String annotationData) throws 
ResourceNotFoundException, InvalidRevisionException, ClusterRequestException;
+    
+    /**
+     * Gets the configuration for the underlying component (including 
annotation data).
+     * 
+     * @return the configuration for the underlying component
+     * @throws ResourceNotFoundException if the underlying component does not 
exit
+     * @throws ClusterRequestException if the underlying component was unable 
to be
+     * retrieved from the cluster. This exception will only be thrown when
+     * operating in a cluster.
+     */
+    ComponentConfiguration getComponentDetails() throws 
ResourceNotFoundException, ClusterRequestException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceInitializationContext.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceInitializationContext.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceInitializationContext.java
index fcd3ea3..69ce8d9 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceInitializationContext.java
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceInitializationContext.java
@@ -18,6 +18,7 @@ package org.apache.nifi.documentation.mock;
 
 import org.apache.nifi.controller.ControllerServiceInitializationContext;
 import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.logging.ComponentLog;
 
 /**
  * A Mock ControllerServiceInitializationContext so that ControllerServices can
@@ -37,4 +38,9 @@ public class MockControllerServiceInitializationContext 
implements ControllerSer
         return new MockControllerServiceLookup();
     }
 
+    @Override
+    public ComponentLog getLogger() {
+        return null;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceLookup.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceLookup.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceLookup.java
index f11bc68..303c983 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceLookup.java
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockControllerServiceLookup.java
@@ -52,4 +52,9 @@ public class MockControllerServiceLookup implements 
ControllerServiceLookup {
         return Collections.emptySet();
     }
 
+    @Override
+    public String getControllerServiceName(String serviceIdentifier) {
+        return null;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockReportingInitializationContext.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockReportingInitializationContext.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockReportingInitializationContext.java
index 910ce5a..39baf0d 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockReportingInitializationContext.java
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/mock/MockReportingInitializationContext.java
@@ -19,6 +19,7 @@ package org.apache.nifi.documentation.mock;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.reporting.ReportingInitializationContext;
 import org.apache.nifi.scheduling.SchedulingStrategy;
 
@@ -60,4 +61,10 @@ public class MockReportingInitializationContext implements 
ReportingInitializati
     public SchedulingStrategy getSchedulingStrategy() {
         return SchedulingStrategy.TIMER_DRIVEN;
     }
+
+    @Override
+    public ComponentLog getLogger() {
+        return null;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
index e39ebcc..e376ab6 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-custom-ui-utilities/src/main/java/org/apache/nifi/web/HttpServletRequestContextConfig.java
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletRequest;
  * An implementation of the NiFiWebContextConfig that retrieves configuration
  * from a HttpServletRequest instance.
  */
+@Deprecated
 public class HttpServletRequestContextConfig implements NiFiWebContextConfig {
 
     public static final String PROCESSOR_ID_PARAM = "processorId";

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml
index 09a614d..d86961c 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml
@@ -120,6 +120,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-ui-extension</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-web-security</artifactId>
             <scope>compile</scope>
         </dependency>
@@ -155,6 +160,11 @@
         </dependency>   
         <dependency>
             <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-ui-extension-controller</artifactId>
+            <type>war</type>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-framework-cluster</artifactId>
             <scope>compile</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/pom.xml
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/pom.xml
new file mode 100644
index 0000000..ee2e22c
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <!--
+      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.
+    -->
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>nifi-web</artifactId>
+        <groupId>org.apache.nifi</groupId>
+        <version>0.1.0-incubating-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.nifi</groupId>
+    <artifactId>nifi-ui-extension-controller</artifactId>
+    <packaging>war</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-user-actions</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-ui-extension</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet.jsp</groupId>
+            <artifactId>javax.servlet.jsp-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.el</groupId>
+            <artifactId>javax.el-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet.jsp.jstl</groupId>
+            <artifactId>javax.servlet.jsp.jstl-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/src/main/java/org/apache/nifi/ui/extension/ConfigureComponentController.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/src/main/java/org/apache/nifi/ui/extension/ConfigureComponentController.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/src/main/java/org/apache/nifi/ui/extension/ConfigureComponentController.java
new file mode 100644
index 0000000..25103ef
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/src/main/java/org/apache/nifi/ui/extension/ConfigureComponentController.java
@@ -0,0 +1,253 @@
+/*
+ * 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.ui.extension;
+
+import org.apache.nifi.web.controller.UiExtensionControllerRequest;
+import org.apache.nifi.web.controller.UiExtensionControllerFacade;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.nifi.action.Action;
+import org.apache.nifi.action.Component;
+import org.apache.nifi.action.Operation;
+import org.apache.nifi.action.component.details.ExtensionDetails;
+import org.apache.nifi.action.details.ConfigureDetails;
+import org.apache.nifi.controller.ControllerService;
+import org.apache.nifi.web.ClusterRequestException;
+import org.apache.nifi.web.ComponentConfiguration;
+import org.apache.nifi.web.ConfigurationAction;
+import org.apache.nifi.web.InvalidRevisionException;
+import org.apache.nifi.web.ResourceNotFoundException;
+import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.UiExtensionRequestContext;
+
+
+/**
+ *
+ */
+public class ConfigureComponentController extends HttpServlet {
+
+    public static final String ID_PARAM = "id";
+    public static final String CLIENT_ID_PARAM = "clientId";
+    public static final String VERSION_PARAM = "version";
+    
+    /**
+     *
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse 
response) throws ServletException, IOException {
+        // get the content
+        final ServletContext servletContext = request.getServletContext();
+        final Object extensionMappings = (Object) 
servletContext.getAttribute("nifi-ui-extension-mapping");
+        final UiExtensionControllerFacade controllerFacade = 
(UiExtensionControllerFacade) 
servletContext.getAttribute("nifi-ui-extension-controller-facade");
+        
+        // get the component type
+        final String type = request.getParameter("type");
+        
+        // ensure the request has 
+        if (type == null) {
+            response.getWriter().println("Request missing the component 
type.");
+            return;
+        }
+        
+        // change later
+        final UiExtensionType extensionType = UiExtensionType.Processor;
+        
+        // build the ui extension request context config
+        final UiExtensionControllerRequest config = 
getRequestContextConig(extensionType, request);
+        
+        // get the initial component details
+        final ComponentConfiguration details = 
controllerFacade.getComponentDetails(config);
+        
+        // lookup a viewer for the content
+        final String uiExtensionUri = servletContext.getInitParameter(type);
+        
+        // ensure the registered viewer is found
+        if (uiExtensionUri == null) {
+            response.getWriter().println("No custom UI is registered for " + 
type);
+        }
+        
+        // set the attribute for the custom ui to interact with nifi
+        request.setAttribute(UiExtensionRequestContext.ATTRIBUTE_KEY, new 
UiExtensionRequestContext() {
+            @Override
+            public ControllerService getControllerService(final String 
serviceIdentifier) {
+                return 
controllerFacade.getControllerService(serviceIdentifier);
+            }
+
+            @Override
+            public void saveActions(Collection<ConfigurationAction> 
uiExtensionActions) {
+                final Collection<Action> actions = new ArrayList<>();
+                
+                // conver the action models
+                if (uiExtensionActions != null) {
+                    final Date now = new Date();
+                    
+                    // create the extension details
+                    ExtensionDetails extensionDetails = new ExtensionDetails();
+                    extensionDetails.setType(details.getType());
+                    
+                    for (final ConfigurationAction extensionAction : 
uiExtensionActions) {
+                        // create the action details
+                        final ConfigureDetails actionDetails = new 
ConfigureDetails();
+                        actionDetails.setName(extensionAction.getField());
+                        actionDetails.setValue(extensionAction.getValue());
+                        
actionDetails.setPreviousValue(extensionAction.getPreviousValue());
+
+                        // create a configuration action
+                        Action configurationAction = new Action();
+                        configurationAction.setUserDn(getCurrentUserDn());
+                        configurationAction.setUserName(getCurrentUserName());
+                        configurationAction.setOperation(Operation.Configure);
+                        configurationAction.setTimestamp(now);
+                        configurationAction.setSourceId(details.getId());
+                        configurationAction.setSourceName(details.getName());
+                        configurationAction.setSourceType(Component.Processor);
+                        
configurationAction.setComponentDetails(extensionDetails);
+                        configurationAction.setActionDetails(actionDetails);
+                        
+                        // add the action
+                        actions.add(configurationAction);
+                    }
+                }
+                
+                // save the actions
+                if (!actions.isEmpty()) {
+                    controllerFacade.saveActions(actions);
+                }
+            }
+
+            @Override
+            public String getCurrentUserDn() {
+                return controllerFacade.getCurrentUserDn();
+            }
+
+            @Override
+            public String getCurrentUserName() {
+                return controllerFacade.getCurrentUserName();
+            }
+
+            @Override
+            public ComponentConfiguration setAnnotationData(String 
annotationData) throws ClusterRequestException, InvalidRevisionException, 
ResourceNotFoundException{
+                return controllerFacade.setAnnotationData(config, 
annotationData);
+            }
+
+            @Override
+            public ComponentConfiguration getComponentDetails() throws 
ClusterRequestException, ResourceNotFoundException {
+                return controllerFacade.getComponentDetails(config);
+            }
+        });
+        
+        // generate the content
+        final ServletContext customUiContext = 
servletContext.getContext(uiExtensionUri);
+        customUiContext.getRequestDispatcher("/configure").forward(request, 
response);
+    }
+    
+    /**
+     * Creates a UiExtensionRequestContextConfig from the specified request.
+     * 
+     * @param request
+     * @return 
+     */
+    private UiExtensionControllerRequest getRequestContextConig(final 
UiExtensionType extensionType, final HttpServletRequest request) {
+        return new UiExtensionControllerRequest() {
+
+            @Override
+            public UiExtensionType getExtensionType() {
+                return extensionType;
+            }
+
+            @Override
+            public String getScheme() {
+                return request.getScheme();
+            }
+
+            @Override
+            public String getId() {
+                return request.getParameter(ID_PARAM);
+            }
+
+            @Override
+            public Revision getRevision() {
+                final String versionParamVal = 
request.getParameter(VERSION_PARAM);
+                Long version;
+                try {
+                    version = Long.parseLong(versionParamVal);
+                } catch (final Exception ex) {
+                    version = null;
+                }
+
+                final String clientId = request.getParameter(CLIENT_ID_PARAM);
+
+                return new Revision(version, clientId);
+            }
+
+            @Override
+            public String getProxiedEntitiesChain() {
+                String xProxiedEntitiesChain = 
request.getHeader("X-ProxiedEntitiesChain");
+                final X509Certificate cert = extractClientCertificate(request);
+                if (cert != null) {
+                    final String extractedPrincipal = extractPrincipal(cert);
+                    final String formattedPrincipal = 
formatProxyDn(extractedPrincipal);
+                    if (xProxiedEntitiesChain == null || 
xProxiedEntitiesChain.trim().isEmpty()) {
+                        xProxiedEntitiesChain = formattedPrincipal;
+                    } else {
+                        xProxiedEntitiesChain += formattedPrincipal;
+                    }
+                }
+
+                return xProxiedEntitiesChain;
+            }
+        };
+    }
+
+    /**
+     * Utility methods that have been copied into this class to reduce the
+     * dependency footprint of this artifact. These utility methods typically
+     * live in web-utilities but that would pull in spring, jersey, jackson,
+     * etc.
+     */
+    
+    private X509Certificate extractClientCertificate(HttpServletRequest 
request) {
+        X509Certificate[] certs = (X509Certificate[]) 
request.getAttribute("javax.servlet.request.X509Certificate");
+
+        if (certs != null && certs.length > 0) {
+            return certs[0];
+        }
+
+        return null;
+    }
+    
+    private String extractPrincipal(X509Certificate cert) {
+        return cert.getSubjectDN().getName().trim();
+    }
+
+    private String formatProxyDn(String dn) {
+        return "<" + dn + ">";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/src/main/webapp/WEB-INF/web.xml
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..a2e6a39
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension-controller/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd";>
+    <display-name>nifi-ui-extension</display-name>
+    <servlet>
+        <servlet-name>configure-component-controller</servlet-name>
+        
<servlet-class>org.apache.nifi.ui.extension.ConfigureComponentController</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>configure-component-controller</servlet-name>
+        <url-pattern>/configure</url-pattern>
+    </servlet-mapping>
+</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/pom.xml
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/pom.xml
new file mode 100644
index 0000000..22388b3
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/pom.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.nifi</groupId>
+        <artifactId>nifi-web</artifactId>
+        <version>0.1.0-incubating-SNAPSHOT</version>
+    </parent>
+    <artifactId>nifi-ui-extension</artifactId>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-user-actions</artifactId>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtension.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtension.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtension.java
new file mode 100644
index 0000000..9040896
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtension.java
@@ -0,0 +1,46 @@
+/*
+ * 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.ui.extension;
+
+/**
+ * Information about a UI extension required to be invoked.
+ */
+public class UiExtension {
+
+    private final UiExtensionType extensionType;
+    private final String contextPath;
+    private final ClassLoader classloader;
+
+    public UiExtension(final UiExtensionType extensionType, final String 
contextPath, final ClassLoader classloader) {
+        this.extensionType = extensionType;
+        this.contextPath = contextPath;
+        this.classloader = classloader;
+    }
+
+    public UiExtensionType getExtensionType() {
+        return extensionType;
+    }
+
+    public String getContextPath() {
+        return contextPath;
+    }
+
+    public ClassLoader getClassloader() {
+        return classloader;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtensionMapping.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtensionMapping.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtensionMapping.java
new file mode 100644
index 0000000..6431686
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtensionMapping.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.ui.extension;
+
+import java.util.Map;
+
+/**
+ * Mapping of all discovered UI extensions.
+ */
+public class UiExtensionMapping {
+
+    private final Map<String, UiExtension> uiExtensions;
+
+    public UiExtensionMapping(Map<String, UiExtension> uiExtensions) {
+        this.uiExtensions = uiExtensions;
+    }
+
+    public boolean hasUiExtension(final String type) {
+        return uiExtensions.containsKey(type);
+    }
+    
+    public UiExtension getUiExtension(final String type) {
+        return uiExtensions.get(type);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtensionType.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtensionType.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtensionType.java
new file mode 100644
index 0000000..1beeea6
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/ui/extension/UiExtensionType.java
@@ -0,0 +1,26 @@
+/*
+ * 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.ui.extension;
+
+/**
+ * Types of UI extensions.
+ */
+public enum UiExtensionType {
+    ProcessorConfiguration,
+    ControllerServiceConfiguration,
+    ReportingTaskConfiguration
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/web/controller/UiExtensionControllerFacade.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/web/controller/UiExtensionControllerFacade.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/web/controller/UiExtensionControllerFacade.java
new file mode 100644
index 0000000..cf53b7b
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/web/controller/UiExtensionControllerFacade.java
@@ -0,0 +1,101 @@
+/*
+ * 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.web.controller;
+
+import java.util.Collection;
+import org.apache.nifi.action.Action;
+
+import org.apache.nifi.controller.ControllerService;
+import org.apache.nifi.web.ClusterRequestException;
+import org.apache.nifi.web.ComponentConfiguration;
+import org.apache.nifi.web.InvalidRevisionException;
+import org.apache.nifi.web.ResourceNotFoundException;
+
+/**
+ * Provides limited access to the controller for UI extensions.
+ */
+public interface UiExtensionControllerFacade {
+
+    /**
+     * Gets the ControllerService for the specified identifier. If a
+     * corresponding service cannot be found, null is returned. If this NiFi is
+     * clustered, the only services available will be those those
+     * availability is NCM only.
+     *
+     * @param serviceIdentifier
+     * @return
+     */
+    ControllerService getControllerService(String serviceIdentifier);
+
+    /**
+     * Provides a mechanism for custom UIs to save actions to appear in NiFi
+     * configuration history. Note all fields within each Action must be
+     * populated. Null values will result in a failure to insert the audit
+     * record. Since the saving to these actions is separate from the actual
+     * configuration change, a failure to insert here will just generate a
+     * warning log message. The recording of these actions typically happens
+     * after a configuration change is applied. Since those changes have 
already
+     * been applied to the flow, we cannot revert them because of a failure to
+     * insert an audit record.
+     *
+     * @param actions
+     */
+    void saveActions(Collection<Action> actions);
+
+    /**
+     * Gets the current user dn. Returns null if no user is found.
+     *
+     * @return
+     */
+    String getCurrentUserDn();
+
+    /**
+     * Gets the current user name. Returns null if no user is found.
+     *
+     * @return
+     */
+    String getCurrentUserName();
+
+    /**
+     * Sets the annotation data for the component in the specified request.
+     * 
+     * @param configurationRequest
+     * @param annotationData 
+     * @return the configuration for the component specified request
+     * @throws ResourceNotFoundException if the specified component does not 
exit
+     * @throws InvalidRevisionException if a revision other than the current
+     * revision is given
+     * @throws ClusterRequestException if the annotation data was unable to be
+     * set for the component. This exception will only be thrown when operating
+     * in a cluster.
+     */
+    ComponentConfiguration setAnnotationData(UiExtensionControllerRequest 
configurationRequest, String annotationData)
+            throws ResourceNotFoundException, InvalidRevisionException, 
ClusterRequestException;
+    
+    /**
+     * Gets the configuration for the underlying component.
+     * 
+     * @param configurationRequest
+     * @return the configuration for the component specified in request
+     * @throws ResourceNotFoundException if the processor does not exit
+     * @throws ClusterRequestException if the component was unable to be
+     * retrieved from the cluster. This exception will only be thrown when
+     * operating in a cluster.
+     */
+    ComponentConfiguration getComponentDetails(UiExtensionControllerRequest 
configurationRequest)
+            throws ResourceNotFoundException, ClusterRequestException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/web/controller/UiExtensionControllerRequest.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/web/controller/UiExtensionControllerRequest.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/web/controller/UiExtensionControllerRequest.java
new file mode 100644
index 0000000..f3d591f
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-ui-extension/src/main/java/org/apache/nifi/web/controller/UiExtensionControllerRequest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.web.controller;
+
+import org.apache.nifi.ui.extension.UiExtensionType;
+import org.apache.nifi.web.Revision;
+
+/**
+ * A UI extensions request object containing required items to querying the 
controller.
+ */
+public interface UiExtensionControllerRequest {
+
+    /**
+     * The type of UI extension supports.
+     * 
+     * @return 
+     */
+    UiExtensionType getExtensionType();
+    
+    /**
+     * The request protocol scheme (http or https). When scheme is https, the
+     * X509Certificate can be used for subsequent remote requests.
+     *
+     * @return the protocol scheme
+     */
+    String getScheme();
+
+    /**
+     * @return the component ID
+     */
+    String getId();
+
+    /**
+     * @return the revision
+     */
+    Revision getRevision();
+
+    /**
+     * Returns the proxied entities chain. The format of the chain is as
+     * follows:
+     *
+     * <code>
+     * 
&lt;CN=original-proxied-entity&gt;&lt;CN=first-proxy&gt;&lt;CN=second-proxy&gt;...
+     * </code>
+     *
+     * @return the proxied entities chain or null if no chain
+     */
+    String getProxiedEntitiesChain();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
index 0bd34cf..221eac5 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
@@ -154,6 +154,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-ui-extension</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-administration</artifactId>
             <scope>provided</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
index b4f49ee..b6ddabf 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
@@ -66,6 +66,7 @@ import org.apache.nifi.web.util.ClientResponseUtils;
  * Implements the NiFiWebContext interface to support a context in both
  * standalone and clustered environments.
  */
+@Deprecated
 public class StandardNiFiWebContext implements NiFiWebContext {
 
     private static final Logger logger = 
LoggerFactory.getLogger(StandardNiFiWebContext.class);

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/StandardUiExtensionControllerFacade.java
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/StandardUiExtensionControllerFacade.java
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/StandardUiExtensionControllerFacade.java
new file mode 100644
index 0000000..1466535
--- /dev/null
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/StandardUiExtensionControllerFacade.java
@@ -0,0 +1,377 @@
+/*
+ * 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.web.controller;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+
+import org.apache.nifi.action.Action;
+import org.apache.nifi.admin.service.AuditService;
+import org.apache.nifi.cluster.manager.NodeResponse;
+import org.apache.nifi.cluster.manager.impl.WebClusterManager;
+import org.apache.nifi.controller.ControllerService;
+import org.apache.nifi.web.security.user.NiFiUserDetails;
+import org.apache.nifi.web.security.user.NiFiUserUtils;
+import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
+import org.apache.nifi.web.api.dto.ProcessorDTO;
+import org.apache.nifi.web.api.dto.RevisionDTO;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.apache.nifi.web.util.WebUtils;
+import org.apache.nifi.ui.extension.UiExtensionType;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.web.ClusterRequestException;
+import org.apache.nifi.web.ComponentConfiguration;
+import org.apache.nifi.web.ConfigurationSnapshot;
+import org.apache.nifi.web.InvalidRevisionException;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.ResourceNotFoundException;
+import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.util.ClientResponseUtils;
+
+/**
+ * Implements the UiExtensionControllerFacade interface to supply a simplified 
+ * interface over a NiFi controller in both clustered and standalone 
environments.
+ */
+public class StandardUiExtensionControllerFacade implements 
UiExtensionControllerFacade {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(StandardUiExtensionControllerFacade.class);
+    
+    private static final String CLIENT_ID_PARAM = "clientId";
+    private static final String VERBOSE_PARAM = "verbose";
+
+    private NiFiProperties properties;
+    private NiFiServiceFacade serviceFacade;
+    private WebClusterManager clusterManager;
+    private ControllerServiceLookup controllerServiceLookup;
+    private AuditService auditService;
+
+    @Override
+    public ControllerService getControllerService(String serviceIdentifier) {
+        return controllerServiceLookup.getControllerService(serviceIdentifier);
+    }
+
+    @Override
+    @PreAuthorize("hasAnyRole('ROLE_DFM')")
+    public void saveActions(final Collection<Action> actions) {
+        Objects.requireNonNull(actions, "Actions cannot be null.");
+
+        // - when running standalone or cluster ncm - actions from custom UIs 
are stored locally
+        // - clustered nodes do not serve custom UIs directly to users so they 
should never be invoking this method
+
+        try {
+            // record the operations
+            auditService.addActions(actions);
+        } catch (Throwable t) {
+            logger.warn("Unable to record actions: " + t.getMessage());
+            if (logger.isDebugEnabled()) {
+                logger.warn(StringUtils.EMPTY, t);
+            }
+        }
+    }
+
+    @Override
+    public String getCurrentUserDn() {
+        String userDn = NiFiUser.ANONYMOUS_USER_DN;
+
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+        if (user != null) {
+            userDn = user.getDn();
+        }
+
+        return userDn;
+    }
+
+    @Override
+    public String getCurrentUserName() {
+        String userName = NiFiUser.ANONYMOUS_USER_DN;
+
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+        if (user != null) {
+            userName = user.getUserName();
+        }
+
+        return userName;
+    }
+
+    @Override
+    public ComponentConfiguration 
getComponentDetails(UiExtensionControllerRequest config) {
+        final String id = config.getId();
+
+        if (StringUtils.isBlank(id)) {
+            throw new ResourceNotFoundException(String.format("Context config 
did not have a component ID."));
+        }
+
+        // ensure the path could be 
+        if (config.getExtensionType() == null) {
+            throw new ResourceNotFoundException(String.format("The type must 
be one of ['%s']", StringUtils.join(UiExtensionType.values(), "', '")));
+        }
+        
+        // get the component facade for interacting directly with that type of 
object
+        ComponentFacade componentFacade = null;
+        switch (config.getExtensionType()) {
+            case ProcessorConfiguration:
+                componentFacade = new ProcessorFacade();
+                break;
+            case ControllerServiceConfiguration: 
+                break;
+            case ReportingTaskConfiguration:
+                break;
+        }
+        
+        if (componentFacade == null) {
+            throw new ResourceNotFoundException(String.format("The type must 
be one of ['%s']", StringUtils.join(UiExtensionType.values(), "', '")));
+        }
+        
+        return componentFacade.getComponentDetails(config);
+    }
+    
+    @Override
+    @PreAuthorize("hasAnyRole('ROLE_DFM')")
+    public ComponentConfiguration 
setAnnotationData(UiExtensionControllerRequest config, String annotationData) {
+        final String id = config.getId();
+
+        if (StringUtils.isBlank(id)) {
+            throw new ResourceNotFoundException(String.format("Context config 
did not have a component ID."));
+        }
+
+        // get the component facade for interacting directly with that type of 
object
+        ComponentFacade componentFacade = null;
+        switch (config.getExtensionType()) {
+            case ProcessorConfiguration:
+                componentFacade = new ProcessorFacade();
+                break;
+            case ControllerServiceConfiguration: 
+                break;
+            case ReportingTaskConfiguration:
+                break;
+        }
+        
+        if (componentFacade == null) {
+            throw new ResourceNotFoundException(String.format("The type must 
be one of ['%s']", StringUtils.join(UiExtensionType.values(), "', '")));
+        }
+        
+        return componentFacade.setAnnotationData(config, annotationData);
+    }
+
+    private interface ComponentFacade {
+        ComponentConfiguration 
getComponentDetails(UiExtensionControllerRequest config);
+        ComponentConfiguration setAnnotationData(UiExtensionControllerRequest 
config, String annotationData);
+    }
+    
+    private class ProcessorFacade implements ComponentFacade {
+        @Override
+        public ComponentConfiguration 
getComponentDetails(UiExtensionControllerRequest config) {
+            final Revision revision = config.getRevision();
+            final String id = config.getId();
+            
+            final ProcessorDTO processor;
+            if (properties.isClusterManager()) {
+                // create the request URL
+                URI requestUrl;
+                try {
+                    String path = "/nifi-api/cluster/processors/" + 
URLEncoder.encode(id, "UTF-8");
+                    requestUrl = new URI(config.getScheme(), null, 
"localhost", 0, path, null, null);
+                } catch (final URISyntaxException | 
UnsupportedEncodingException use) {
+                    throw new ClusterRequestException(use);
+                }
+
+                // set the request parameters
+                MultivaluedMap<String, String> parameters = new 
MultivaluedMapImpl();
+                parameters.add(CLIENT_ID_PARAM, revision.getClientId());
+                parameters.add(VERBOSE_PARAM, "true");
+
+                // replicate request
+                NodeResponse nodeResponse = 
clusterManager.applyRequest(HttpMethod.GET, requestUrl, parameters, 
getHeaders(config));
+
+                // check for issues replicating request
+                checkResponse(nodeResponse, revision, id);
+
+                // return processor
+                final ProcessorEntity entity = 
nodeResponse.getClientResponse().getEntity(ProcessorEntity.class);
+                processor = entity.getProcessor();
+            } else {
+                processor = serviceFacade.getProcessor(id);
+            }
+
+            // return the processor info
+            return getComponentConfiguration(processor);
+        }
+
+        @Override
+        public ComponentConfiguration 
setAnnotationData(UiExtensionControllerRequest config, String annotationData) {
+            final Revision revision = config.getRevision();
+            final String id = config.getId();
+            
+            final ProcessorDTO processor;
+            if (properties.isClusterManager()) {
+                // create the request URL
+                URI requestUrl;
+                try {
+                    String path = "/nifi-api/cluster/processors/" + 
URLEncoder.encode(id, "UTF-8");
+                    requestUrl = new URI(config.getScheme(), null, 
"localhost", 0, path, null, null);
+                } catch (final URISyntaxException | 
UnsupportedEncodingException use) {
+                    throw new ClusterRequestException(use);
+                }
+
+                // create the revision
+                RevisionDTO revisionDto = new RevisionDTO();
+                revisionDto.setClientId(revision.getClientId());
+                revisionDto.setVersion(revision.getVersion());
+
+                // create the processor entity
+                ProcessorEntity processorEntity = new ProcessorEntity();
+                processorEntity.setRevision(revisionDto);
+
+                // create the processor dto
+                ProcessorDTO processorDto = new ProcessorDTO();
+                processorEntity.setProcessor(processorDto);
+                processorDto.setId(id);
+
+                // create the processor configuration with the given 
annotation data
+                ProcessorConfigDTO configDto = new ProcessorConfigDTO();
+                processorDto.setConfig(configDto);
+                configDto.setAnnotationData(annotationData);
+
+                // set the content type to json
+                final Map<String, String> headers = getHeaders(config);
+                headers.put("Content-Type", "application/json");
+
+                // replicate request
+                NodeResponse nodeResponse = 
clusterManager.applyRequest(HttpMethod.PUT, requestUrl, processorEntity, 
headers);
+
+                // check for issues replicating request
+                checkResponse(nodeResponse, revision, id);
+                
+                // return processor
+                final ProcessorEntity entity = 
nodeResponse.getClientResponse().getEntity(ProcessorEntity.class);
+                processor = entity.getProcessor();
+            } else {
+                final ConfigurationSnapshot<ProcessorDTO> response = 
serviceFacade.setProcessorAnnotationData(revision, id, annotationData);
+                processor = response.getConfiguration();
+            }
+            
+            // return the processor info
+            return getComponentConfiguration(processor);
+        }
+        
+        private ComponentConfiguration getComponentConfiguration(final 
ProcessorDTO processor) {
+            final ProcessorConfigDTO processorConfig = processor.getConfig();
+            return new ComponentConfiguration.Builder()
+                    .id(processor.getId())
+                    .name(processor.getName())
+                    .state(processor.getState())
+                    .annotationData(processorConfig.getAnnotationData())
+                    .properties(processorConfig.getProperties())
+                    .validateErrors(processor.getValidationErrors()).build();
+        }
+    }
+    
+    /**
+     * Gets the headers for the request to replicate to each node while
+     * clustered.
+     *
+     * @param config
+     * @return
+     */
+    private Map<String, String> getHeaders(final UiExtensionControllerRequest 
config) {
+        final Map<String, String> headers = new HashMap<>();
+        headers.put("Accept", "application/json,application/xml");
+        if (StringUtils.isNotBlank(config.getProxiedEntitiesChain())) {
+            headers.put("X-ProxiedEntitiesChain", 
config.getProxiedEntitiesChain());
+        }
+
+        // add the user's authorities (if any) to the headers
+        final Authentication authentication = 
SecurityContextHolder.getContext().getAuthentication();
+        if (authentication != null) {
+            final Object userDetailsObj = authentication.getPrincipal();
+            if (userDetailsObj instanceof NiFiUserDetails) {
+                // serialize user details object
+                final String hexEncodedUserDetails = 
WebUtils.serializeObjectToHex((Serializable) userDetailsObj);
+
+                // put serialized user details in header
+                headers.put("X-ProxiedEntityUserDetails", 
hexEncodedUserDetails);
+            }
+        }
+        return headers;
+    }
+    
+    /**
+     * Checks the specified response and drains the stream appropriately.
+     * 
+     * @param nodeResponse
+     * @param revision
+     * @param id 
+     */
+    private void checkResponse(final NodeResponse nodeResponse, final Revision 
revision, final String id) {
+        if (nodeResponse.hasThrowable()) {
+            
ClientResponseUtils.drainClientResponse(nodeResponse.getClientResponse());
+            throw new ClusterRequestException(nodeResponse.getThrowable());
+        } else if (nodeResponse.getClientResponse().getStatus() == 
Response.Status.CONFLICT.getStatusCode()) {
+            
ClientResponseUtils.drainClientResponse(nodeResponse.getClientResponse());
+            throw new InvalidRevisionException(String.format("Invalid revision 
specified %s", revision));
+        } else if (nodeResponse.getClientResponse().getStatus() == 
Response.Status.NOT_FOUND.getStatusCode()) {
+            
ClientResponseUtils.drainClientResponse(nodeResponse.getClientResponse());
+            throw new ResourceNotFoundException("Unable to find component with 
id: " + id);
+        } else if (nodeResponse.getClientResponse().getStatus() != 
Response.Status.OK.getStatusCode()) {
+            
ClientResponseUtils.drainClientResponse(nodeResponse.getClientResponse());
+            throw new ClusterRequestException("Method resulted in an 
unsuccessful HTTP response code: " + 
nodeResponse.getClientResponse().getStatus());
+        }
+    }
+
+    public void setClusterManager(WebClusterManager clusterManager) {
+        this.clusterManager = clusterManager;
+    }
+
+    public void setProperties(NiFiProperties properties) {
+        this.properties = properties;
+    }
+
+    public void setServiceFacade(NiFiServiceFacade serviceFacade) {
+        this.serviceFacade = serviceFacade;
+    }
+
+    public void setAuditService(AuditService auditService) {
+        this.auditService = auditService;
+    }
+
+    public void setControllerServiceLookup(ControllerServiceLookup 
controllerServiceLookup) {
+        this.controllerServiceLookup = controllerServiceLookup;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
index 940eb62..d4ab6b7 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
@@ -124,6 +124,13 @@
         <property name="auditService" ref="auditService"/>
         <property name="controllerServiceLookup" 
ref="controllerServiceProvider"/>
     </bean>
+    <bean id="nifiUiExtensionControllerFacade" 
class="org.apache.nifi.web.controller.StandardUiExtensionControllerFacade">
+        <property name="serviceFacade" ref="serviceFacade"/>
+        <property name="properties" ref="nifiProperties"/>
+        <property name="clusterManager" ref="clusterManager"/>
+        <property name="auditService" ref="auditService"/>
+        <property name="controllerServiceLookup" 
ref="controllerServiceProvider"/>
+    </bean>
 
     <!-- rest endpoints -->
     <bean id="controllerResource" 
class="org.apache.nifi.web.api.ControllerResource" scope="singleton">

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/pom.xml 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/pom.xml
index 11c3c0a..7215672 100644
--- 
a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/pom.xml
+++ 
b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/pom.xml
@@ -12,8 +12,7 @@
   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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+--><project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.nifi</groupId>
@@ -31,6 +30,8 @@
         <module>nifi-web-docs</module>
         <module>nifi-web-ui</module>
         <module>nifi-jetty</module>
+        <module>nifi-ui-extension-controller</module>
+        <module>nifi-ui-extension</module>
     </modules>
     <dependencyManagement>
         <dependencies>
@@ -54,10 +55,16 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.nifi</groupId>
+                <artifactId>nifi-ui-extension-controller</artifactId>
+                <type>war</type>
+                <version>0.1.0-incubating-SNAPSHOT</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.nifi</groupId>
                 <artifactId>nifi-web-ui</artifactId>
                 <type>war</type>
                 <version>0.1.0-incubating-SNAPSHOT</version>
             </dependency>
         </dependencies>
     </dependencyManagement>
-</project>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/6c058778/nifi/pom.xml
----------------------------------------------------------------------
diff --git a/nifi/pom.xml b/nifi/pom.xml
index e7d8f5b..2e2346a 100644
--- a/nifi/pom.xml
+++ b/nifi/pom.xml
@@ -676,6 +676,11 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.nifi</groupId>
+                <artifactId>nifi-ui-extension</artifactId>
+                <version>0.1.0-incubating-SNAPSHOT</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.nifi</groupId>
                 <artifactId>nifi-flowfile-packager</artifactId>
                 <version>0.1.0-incubating-SNAPSHOT</version>
             </dependency>

Reply via email to