You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by mc...@apache.org on 2015/01/22 21:24:45 UTC

incubator-nifi git commit: NIFI-250: - Adding an endpoint to manage ControllerServices.

Repository: incubator-nifi
Updated Branches:
  refs/heads/NIFI-250 c8ea68306 -> e604cafe7


NIFI-250:
- Adding an endpoint to manage ControllerServices.

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

Branch: refs/heads/NIFI-250
Commit: e604cafe79f5a90e9179a9f2e46e3cbbb7f47380
Parents: c8ea683
Author: Matt Gilman <ma...@gmail.com>
Authored: Thu Jan 22 15:24:17 2015 -0500
Committer: Matt Gilman <ma...@gmail.com>
Committed: Thu Jan 22 15:24:17 2015 -0500

----------------------------------------------------------------------
 .../nifi/web/api/dto/ControllerServiceDTO.java  | 134 ++++++
 .../nifi/web/api/dto/ProcessorConfigDTO.java    | 209 --------
 .../nifi/web/api/dto/PropertyDescriptorDTO.java | 229 +++++++++
 .../web/api/entity/ControllerServiceEntity.java |  45 ++
 .../api/entity/ControllerServicesEntity.java    |  46 ++
 .../apache/nifi/controller/TemplateManager.java |   2 +-
 .../org/apache/nifi/web/NiFiServiceFacade.java  |  61 +++
 .../nifi/web/StandardNiFiServiceFacade.java     |  96 ++++
 .../apache/nifi/web/api/ControllerResource.java |  12 +-
 .../nifi/web/api/ControllerServiceResource.java | 476 +++++++++++++++++++
 .../org/apache/nifi/web/api/dto/DtoFactory.java |  61 ++-
 .../nifi/web/dao/ControllerServiceDAO.java      |  88 ++++
 .../dao/impl/StandardControllerServiceDAO.java  | 138 ++++++
 .../src/main/resources/nifi-web-api-context.xml |   9 +
 14 files changed, 1391 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
new file mode 100644
index 0000000..7662594
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
@@ -0,0 +1,134 @@
+/*
+ * 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.api.dto;
+
+import java.util.Map;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A connection between two connectable components.
+ */
+@XmlType(name = "controllerService")
+public class ControllerServiceDTO extends NiFiComponentDTO {
+
+    private String name;
+    private String type;
+    private String availability;
+    private Boolean enabled;
+    
+    private Map<String, String> properties;
+    private Map<String, PropertyDescriptorDTO> descriptors;
+ 
+    private String annotationData;
+
+    /**
+     * The controller service name.
+     * 
+     * @return 
+     */
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * The controller service type.
+     * 
+     * @return 
+     */
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Where this service is available. Possible values are CLUSTER_MANAGER_ONLY, NODE_ONLY, BOTH.
+     * 
+     * @return 
+     */
+    public String getAvailability() {
+        return availability;
+    }
+
+    public void setAvailability(String availability) {
+        this.availability = availability;
+    }
+
+    /**
+     * Whether the controller service is enabled.
+     * 
+     * @return 
+     */
+    public Boolean getEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(Boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    /**
+     * The controller service properties.
+     * 
+     * @return 
+     */
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
+    public void setProperties(Map<String, String> properties) {
+        this.properties = properties;
+    }
+
+    /**
+     * The descriptors for the controller service properties.
+     * 
+     * @return 
+     */
+    public Map<String, PropertyDescriptorDTO> getDescriptors() {
+        return descriptors;
+    }
+
+    public void setDescriptors(Map<String, PropertyDescriptorDTO> descriptors) {
+        this.descriptors = descriptors;
+    }
+
+    /**
+     * The annotation data for this controller service.
+     * 
+     * @return 
+     */
+    public String getAnnotationData() {
+        return annotationData;
+    }
+
+    public void setAnnotationData(String annotationData) {
+        this.annotationData = annotationData;
+    }
+    
+    @XmlType(name = "controllerServiceReference")
+    public static class ControllerServiceReferenceDTO {
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java
index 1481b0f..5978041 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java
@@ -274,213 +274,4 @@ public class ProcessorConfigDTO {
         this.defaultSchedulingPeriod = defaultSchedulingPeriod;
     }
 
-    /**
-     * The allowable values for a property with a constrained set of options.
-     */
-    @XmlType(name = "allowableValue")
-    public static class AllowableValueDTO {
-
-        private String displayName;
-        private String value;
-        private String description;
-
-        /**
-         * Returns the human-readable value that is allowed for this
-         * PropertyDescriptor
-         *
-         * @return
-         */
-        public String getDisplayName() {
-            return displayName;
-        }
-
-        public void setDisplayName(String displayName) {
-            this.displayName = displayName;
-        }
-
-        /**
-         * Returns the value for this allowable value.
-         *
-         * @return
-         */
-        public String getValue() {
-            return value;
-        }
-
-        public void setValue(String value) {
-            this.value = value;
-        }
-
-        /**
-         * Returns a description of this Allowable Value, or <code>null</code>
-         * if no description is given
-         *
-         * @return
-         */
-        public String getDescription() {
-            return description;
-        }
-
-        public void setDescription(String description) {
-            this.description = description;
-        }
-
-        @Override
-        public boolean equals(final Object obj) {
-            if (obj == this) {
-                return true;
-            }
-
-            if (!(obj instanceof AllowableValueDTO)) {
-                return false;
-            }
-
-            final AllowableValueDTO other = (AllowableValueDTO) obj;
-            return (this.value.equals(other.getValue()));
-        }
-
-        @Override
-        public int hashCode() {
-            return 23984731 + 17 * value.hashCode();
-        }
-    }
-
-    /**
-     * A description of a processor property.
-     */
-    @XmlType(name = "propertyDescriptor")
-    public static class PropertyDescriptorDTO {
-
-        private String name;
-        private String displayName;
-        private String description;
-        private String defaultValue;
-        private Set<AllowableValueDTO> allowableValues;
-        private boolean required;
-        private boolean sensitive;
-        private boolean dynamic;
-        private boolean supportsEl;
-
-        /**
-         * The set of allowable values for this property. If empty then the
-         * allowable values are not constrained.
-         *
-         * @return
-         */
-        public Set<AllowableValueDTO> getAllowableValues() {
-            return allowableValues;
-        }
-
-        public void setAllowableValues(Set<AllowableValueDTO> allowableValues) {
-            this.allowableValues = allowableValues;
-        }
-
-        /**
-         * The default value for this property.
-         *
-         * @return
-         */
-        public String getDefaultValue() {
-            return defaultValue;
-        }
-
-        public void setDefaultValue(String defaultValue) {
-            this.defaultValue = defaultValue;
-        }
-
-        /**
-         * And explanation of the meaning of the given property. This
-         * description is meant to be displayed to a user or simply provide a
-         * mechanism of documenting intent.
-         *
-         * @return
-         */
-        public String getDescription() {
-            return description;
-        }
-
-        public void setDescription(String description) {
-            this.description = description;
-        }
-
-        /**
-         * The property name.
-         *
-         * @return
-         */
-        public String getName() {
-            return name;
-        }
-
-        public void setName(String name) {
-            this.name = name;
-        }
-
-        /**
-         * The human-readable name to display to users.
-         *
-         * @return
-         */
-        public String getDisplayName() {
-            return displayName;
-        }
-
-        public void setDisplayName(String displayName) {
-            this.displayName = displayName;
-        }
-
-        /**
-         * Determines whether the property is required for this processor.
-         *
-         * @return
-         */
-        public boolean isRequired() {
-            return required;
-        }
-
-        public void setRequired(boolean required) {
-            this.required = required;
-        }
-
-        /**
-         * Indicates that the value for this property should be considered
-         * sensitive and protected whenever stored or represented.
-         *
-         * @return
-         */
-        public boolean isSensitive() {
-            return sensitive;
-        }
-
-        public void setSensitive(boolean sensitive) {
-            this.sensitive = sensitive;
-        }
-
-        /**
-         * Indicates whether this property is dynamic.
-         *
-         * @return
-         */
-        public boolean isDynamic() {
-            return dynamic;
-        }
-
-        public void setDynamic(boolean dynamic) {
-            this.dynamic = dynamic;
-        }
-
-        /**
-         * Specifies whether or not this property support expression language.
-         *
-         * @return
-         */
-        public boolean getSupportsEl() {
-            return supportsEl;
-        }
-
-        public void setSupportsEl(boolean supportsEl) {
-            this.supportsEl = supportsEl;
-        }
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java
new file mode 100644
index 0000000..ee4d250
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java
@@ -0,0 +1,229 @@
+/*
+ * 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.api.dto;
+
+import java.util.Set;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A description of a property.
+ */
+@XmlType(name = "propertyDescriptor")
+public class PropertyDescriptorDTO {
+
+    private String name;
+    private String displayName;
+    private String description;
+    private String defaultValue;
+    private Set<AllowableValueDTO> allowableValues;
+    private boolean required;
+    private boolean sensitive;
+    private boolean dynamic;
+    private boolean supportsEl;
+
+    /**
+     * The set of allowable values for this property. If empty then the
+     * allowable values are not constrained.
+     *
+     * @return
+     */
+    public Set<AllowableValueDTO> getAllowableValues() {
+        return allowableValues;
+    }
+
+    public void setAllowableValues(Set<AllowableValueDTO> allowableValues) {
+        this.allowableValues = allowableValues;
+    }
+
+    /**
+     * The default value for this property.
+     *
+     * @return
+     */
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    public void setDefaultValue(String defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    /**
+     * And explanation of the meaning of the given property. This
+     * description is meant to be displayed to a user or simply provide a
+     * mechanism of documenting intent.
+     *
+     * @return
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * The property name.
+     *
+     * @return
+     */
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * The human-readable name to display to users.
+     *
+     * @return
+     */
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+    /**
+     * Determines whether the property is required for this processor.
+     *
+     * @return
+     */
+    public boolean isRequired() {
+        return required;
+    }
+
+    public void setRequired(boolean required) {
+        this.required = required;
+    }
+
+    /**
+     * Indicates that the value for this property should be considered
+     * sensitive and protected whenever stored or represented.
+     *
+     * @return
+     */
+    public boolean isSensitive() {
+        return sensitive;
+    }
+
+    public void setSensitive(boolean sensitive) {
+        this.sensitive = sensitive;
+    }
+
+    /**
+     * Indicates whether this property is dynamic.
+     *
+     * @return
+     */
+    public boolean isDynamic() {
+        return dynamic;
+    }
+
+    public void setDynamic(boolean dynamic) {
+        this.dynamic = dynamic;
+    }
+
+    /**
+     * Specifies whether or not this property support expression language.
+     *
+     * @return
+     */
+    public boolean getSupportsEl() {
+        return supportsEl;
+    }
+
+    public void setSupportsEl(boolean supportsEl) {
+        this.supportsEl = supportsEl;
+    }
+    
+    /**
+     * The allowable values for a property with a constrained set of options.
+     */
+    @XmlType(name = "allowableValue")
+    public static class AllowableValueDTO {
+
+        private String displayName;
+        private String value;
+        private String description;
+
+        /**
+         * Returns the human-readable value that is allowed for this
+         * PropertyDescriptor
+         *
+         * @return
+         */
+        public String getDisplayName() {
+            return displayName;
+        }
+
+        public void setDisplayName(String displayName) {
+            this.displayName = displayName;
+        }
+
+        /**
+         * Returns the value for this allowable value.
+         *
+         * @return
+         */
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * Returns a description of this Allowable Value, or <code>null</code>
+         * if no description is given
+         *
+         * @return
+         */
+        public String getDescription() {
+            return description;
+        }
+
+        public void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            if (obj == this) {
+                return true;
+            }
+
+            if (!(obj instanceof AllowableValueDTO)) {
+                return false;
+            }
+
+            final AllowableValueDTO other = (AllowableValueDTO) obj;
+            return (this.value.equals(other.getValue()));
+        }
+
+        @Override
+        public int hashCode() {
+            return 23984731 + 17 * value.hashCode();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
new file mode 100644
index 0000000..44364e7
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.api.entity;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+
+/**
+ * A serialized representation of this class can be placed in the entity body of
+ * a response to the API. This particular entity holds a reference to a 
+ * controller service.
+ */
+@XmlRootElement(name = "controllerServiceEntity")
+public class ControllerServiceEntity extends Entity {
+
+    private ControllerServiceDTO controllerService;
+
+    /**
+     * The controller service that is being serialized.
+     *
+     * @return
+     */
+    public ControllerServiceDTO getControllerService() {
+        return controllerService;
+    }
+
+    public void setControllerService(ControllerServiceDTO controllerService) {
+        this.controllerService = controllerService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServicesEntity.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServicesEntity.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServicesEntity.java
new file mode 100644
index 0000000..4485b43
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServicesEntity.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.web.api.entity;
+
+import java.util.Set;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+
+/**
+ * A serialized representation of this class can be placed in the entity body of
+ * a response to the API. This particular entity holds a reference to a list of
+ * controller services.
+ */
+@XmlRootElement(name = "controllerServicesEntity")
+public class ControllerServicesEntity extends Entity {
+
+    private Set<ControllerServiceDTO> controllerServices;
+
+    /**
+     * The list of controller services that are being serialized.
+     *
+     * @return
+     */
+    public Set<ControllerServiceDTO> getControllerServices() {
+        return controllerServices;
+    }
+
+    public void setControllerServices(Set<ControllerServiceDTO> controllerServices) {
+        this.controllerServices = controllerServices;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java
index aa095d1..f615f63 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java
@@ -53,7 +53,7 @@ import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.api.dto.FlowSnippetDTO;
 import org.apache.nifi.web.api.dto.ProcessGroupDTO;
 import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
-import org.apache.nifi.web.api.dto.ProcessorConfigDTO.PropertyDescriptorDTO;
+import org.apache.nifi.web.api.dto.PropertyDescriptorDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupContentsDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.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/NiFiServiceFacade.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
index b0001ec..a357865 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
@@ -27,6 +27,7 @@ import org.apache.nifi.web.api.dto.ClusterDTO;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.api.dto.ControllerConfigurationDTO;
 import org.apache.nifi.web.api.dto.ControllerDTO;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
 import org.apache.nifi.web.api.dto.CounterDTO;
 import org.apache.nifi.web.api.dto.CountersDTO;
 import org.apache.nifi.web.api.dto.DocumentedTypeDTO;
@@ -939,6 +940,66 @@ public interface NiFiServiceFacade {
     ConfigurationSnapshot<Void> deleteLabel(Revision revision, String groupId, String labelId);
 
     // ----------------------------------------
+    // Controller Services methods
+    // ----------------------------------------
+    
+    /**
+     * Creates a controller service.
+     *
+     * @param revision Revision to compare with current base revision
+     * @param controllerServiceDTO The controller service DTO
+     * @return The controller service DTO
+     */
+    ConfigurationSnapshot<ControllerServiceDTO> createControllerService(Revision revision, ControllerServiceDTO controllerServiceDTO);
+    
+    /**
+     * Gets all controller services.
+     * 
+     * @return 
+     */
+    Set<ControllerServiceDTO> getControllerServices();
+    
+    /**
+     * Gets the specified controller service.
+     * 
+     * @param controllerServiceId
+     * @return 
+     */
+    ControllerServiceDTO getControllerService(String controllerServiceId);
+    
+    /**
+     * Updates the specified label.
+     *
+     * @param revision Revision to compare with current base revision
+     * @param controllerServiceDTO The controller service DTO
+     * @return The controller service DTO
+     */
+    ConfigurationSnapshot<ControllerServiceDTO> updateControllerService(Revision revision, ControllerServiceDTO controllerServiceDTO);
+
+    /**
+     * Deletes the specified label.
+     *
+     * @param revision Revision to compare with current base revision
+     * @param controllerServiceId The controller service id
+     * @return 
+     */
+    ConfigurationSnapshot<Void> deleteControllerService(Revision revision, String controllerServiceId);
+    
+    /**
+     * Verifies the specified controller service can be updated.
+     *
+     * @param controllerServiceDTO
+     */
+    void verifyUpdateControllerService(ControllerServiceDTO controllerServiceDTO);
+
+    /**
+     * Verifies the specified controller service can be removed.
+     *
+     * @param controllerServiceId
+     */
+    void verifyDeleteControllerService(String controllerServiceId);
+    
+    // ----------------------------------------
     // History methods
     // ----------------------------------------
     /**

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.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/StandardNiFiServiceFacade.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index 41660f2..a79b978 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -153,6 +153,9 @@ import org.apache.nifi.web.util.SnippetUtils;
 
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+import org.apache.nifi.web.dao.ControllerServiceDAO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.access.AccessDeniedException;
@@ -183,6 +186,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     private PortDAO inputPortDAO;
     private PortDAO outputPortDAO;
     private ConnectionDAO connectionDAO;
+    private ControllerServiceDAO controllerServiceDAO;
     private TemplateDAO templateDAO;
 
     // administrative services
@@ -244,6 +248,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     // -----------------------------------------
     // Verification Operations
     // -----------------------------------------
+    
     @Override
     public void verifyCreateConnection(String groupId, ConnectionDTO connectionDTO) {
         connectionDAO.verifyCreate(groupId, connectionDTO);
@@ -361,9 +366,20 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         remoteProcessGroupDAO.verifyDelete(groupId, remoteProcessGroupId);
     }
 
+    @Override
+    public void verifyUpdateControllerService(ControllerServiceDTO controllerServiceDTO) {
+        controllerServiceDAO.verifyUpdate(controllerServiceDTO);
+    }
+
+    @Override
+    public void verifyDeleteControllerService(String controllerServiceId) {
+        controllerServiceDAO.verifyDelete(controllerServiceId);
+    }
+
     // -----------------------------------------
     // Write Operations
     // -----------------------------------------
+    
     @Override
     public ConfigurationSnapshot<ConnectionDTO> updateConnection(Revision revision, String groupId, ConnectionDTO connectionDTO) {
 
@@ -1258,6 +1274,68 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
+    public ConfigurationSnapshot<ControllerServiceDTO> createControllerService(Revision revision, ControllerServiceDTO controllerServiceDTO) {
+        // ensure the proper revision before performing the update
+        checkRevision(revision);
+
+        // ensure id is set
+        if (StringUtils.isBlank(controllerServiceDTO.getId())) {
+            controllerServiceDTO.setId(UUID.randomUUID().toString());
+        }
+
+        final ControllerServiceNode controllerService = controllerServiceDAO.createControllerService(controllerServiceDTO);
+
+        // update the revision and generate a response
+        final Revision updatedRevision = updateRevision(revision);
+        final ConfigurationSnapshot<ControllerServiceDTO> response = new ConfigurationSnapshot<>(updatedRevision.getVersion(), dtoFactory.createControllerServiceDto(controllerService));
+
+        // save the flow
+        controllerFacade.save();
+
+        return response;
+    }
+
+    @Override
+    public ConfigurationSnapshot<ControllerServiceDTO> updateControllerService(Revision revision, ControllerServiceDTO controllerServiceDTO) {
+        // ensure the proper revision before performing the update
+        checkRevision(revision);
+
+        // if controller service does not exist, then create new controller service
+        if (controllerServiceDAO.hasControllerService(controllerServiceDTO.getId()) == false) {
+            return createControllerService(revision, controllerServiceDTO);
+        }
+
+        final ControllerServiceNode controllerService = controllerServiceDAO.updateControllerService(controllerServiceDTO);
+
+        // update the revision and generate a response
+        final Revision updatedRevision = updateRevision(revision);
+        final ConfigurationSnapshot<ControllerServiceDTO> response = new ConfigurationSnapshot<>(updatedRevision.getVersion(), dtoFactory.createControllerServiceDto(controllerService));
+
+        // save the flow
+        controllerFacade.save();
+
+        return response;
+    }
+
+    @Override
+    public ConfigurationSnapshot<Void> deleteControllerService(Revision revision, String controllerServiceId) {
+        // ensure the proper revision before performing the update
+        checkRevision(revision);
+
+        // delete the label
+        controllerServiceDAO.deleteControllerService(controllerServiceId);
+
+        // update the revision and generate a response
+        final Revision updatedRevision = updateRevision(revision);
+        final ConfigurationSnapshot<Void> response = new ConfigurationSnapshot<>(updatedRevision.getVersion());
+
+        // save the flow
+        controllerFacade.save();
+
+        return response;
+    }
+
+    @Override
     public void deleteActions(Date endDate) {
         // get the user from the request
         NiFiUser user = NiFiUserUtils.getNiFiUser();
@@ -1946,6 +2024,20 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
+    public Set<ControllerServiceDTO> getControllerServices() {
+        final Set<ControllerServiceDTO> controllerServiceDtos = new LinkedHashSet<>();
+        for (ControllerServiceNode controllerService : controllerServiceDAO.getControllerServices()) {
+            controllerServiceDtos.add(dtoFactory.createControllerServiceDto(controllerService));
+        }
+        return controllerServiceDtos;
+    }
+
+    @Override
+    public ControllerServiceDTO getControllerService(String controllerServiceId) {
+        return dtoFactory.createControllerServiceDto(controllerServiceDAO.getControllerService(controllerServiceId));
+    }
+
+    @Override
     public StatusHistoryDTO getProcessGroupStatusHistory(String groupId) {
         return controllerFacade.getProcessGroupStatusHistory(groupId);
     }
@@ -2729,6 +2821,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         this.processGroupDAO = processGroupDAO;
     }
 
+    public void setControllerServiceDAO(ControllerServiceDAO controllerServiceDAO) {
+        this.controllerServiceDAO = controllerServiceDAO;
+    }
+
     public void setTemplateDAO(TemplateDAO templateDAO) {
         this.templateDAO = templateDAO;
     }

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.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/api/ControllerResource.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
index d13e4ce..a77e9ea 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
@@ -151,7 +151,7 @@ public class ControllerResource extends ApplicationResource {
     }
 
     /**
-     * Locates the Template sub-resource.
+     * Locates the Snippets sub-resource.
      *
      * @return
      */
@@ -159,6 +159,16 @@ public class ControllerResource extends ApplicationResource {
     public SnippetResource getSnippetResource() {
         return resourceContext.getResource(SnippetResource.class);
     }
+    
+    /**
+     * Locates the Controller Services sub-resource.
+     *
+     * @return
+     */
+    @Path("/controller-services")
+    public ControllerServiceResource getControllerServiceResource() {
+        return resourceContext.getResource(ControllerServiceResource.class);
+    }
 
     /**
      * Locates the Group sub-resource.

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.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/api/ControllerServiceResource.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
new file mode 100644
index 0000000..c40f821
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
@@ -0,0 +1,476 @@
+/*
+ * 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.api;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.nifi.cluster.manager.impl.WebClusterManager;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.ConfigurationSnapshot;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.api.dto.FunnelDTO;
+import org.apache.nifi.web.api.dto.PositionDTO;
+import org.apache.nifi.web.api.dto.RevisionDTO;
+import org.apache.nifi.web.api.entity.FunnelEntity;
+import org.apache.nifi.web.api.entity.FunnelsEntity;
+import org.apache.nifi.web.api.request.ClientIdParameter;
+import org.apache.nifi.web.api.request.DoubleParameter;
+import org.apache.nifi.web.api.request.LongParameter;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+import org.apache.nifi.web.api.entity.ControllerServiceEntity;
+import org.apache.nifi.web.api.entity.ControllerServicesEntity;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.prepost.PreAuthorize;
+
+/**
+ * RESTful endpoint for managing a Funnel.
+ */
+public class ControllerServiceResource extends ApplicationResource {
+
+    private static final Logger logger = LoggerFactory.getLogger(ControllerServiceResource.class);
+
+    private NiFiServiceFacade serviceFacade;
+    private WebClusterManager clusterManager;
+    private NiFiProperties properties;
+
+    /**
+     * Populates the uri for the specified controller service.
+     * 
+     * @param controllerServices
+     * @return 
+     */
+    private Set<ControllerServiceDTO> populateRemainingControllerServicesContent(Set<ControllerServiceDTO> controllerServices) {
+        for (ControllerServiceDTO controllerService : controllerServices) {
+            populateRemainingControllerServiceContent(controllerService);
+        }
+        return controllerServices;
+    }
+
+    /**
+     * Populates the uri for the specified controller service.
+     */
+    private ControllerServiceDTO populateRemainingControllerServiceContent(ControllerServiceDTO controllerService) {
+        // populate the controller service href
+        controllerService.setUri(generateResourceUri("controller", "controller-services", controllerService.getId()));
+        return controllerService;
+    }
+
+    /**
+     * Retrieves all the of controller services in this NiFi.
+     *
+     * @param clientId Optional client id. If the client id is not specified, a
+     * new one will be generated. This value (whether specified or generated) is
+     * included in the response.
+     * @return A controllerServicesEntity.
+     */
+    @GET
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
+    @TypeHint(ControllerServicesEntity.class)
+    public Response getControllerServices(@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
+
+        // replicate if cluster manager
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
+        }
+
+        // get all the controller services
+        final Set<ControllerServiceDTO> controllerServices = populateRemainingControllerServicesContent(serviceFacade.getControllerServices());
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+
+        // create the response entity
+        final ControllerServicesEntity entity = new ControllerServicesEntity();
+        entity.setRevision(revision);
+        entity.setControllerServices(controllerServices);
+
+        // generate the response
+        return clusterContext(generateOkResponse(entity)).build();
+    }
+
+    /**
+     * Creates a new funnel.
+     *
+     * @param httpServletRequest
+     * @param version The revision is used to verify the client is working with
+     * the latest version of the flow.
+     * @param clientId Optional client id. If the client id is not specified, a
+     * new one will be generated. This value (whether specified or generated) is
+     * included in the response.
+     * @param type The type of controller service to create.
+     * @return A controllerServiceEntity.
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @PreAuthorize("hasRole('ROLE_DFM')")
+    @TypeHint(ControllerServiceEntity.class)
+    public Response createControllerService(
+            @Context HttpServletRequest httpServletRequest,
+            @FormParam(VERSION) LongParameter version,
+            @FormParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
+            @FormParam("type") String type) {
+
+        // create the controller service DTO
+        final ControllerServiceDTO controllerServiceDTO = new ControllerServiceDTO();
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+
+        if (version != null) {
+            revision.setVersion(version.getLong());
+        }
+
+        // create the controller service entity
+        final ControllerServiceEntity controllerServiceEntity = new ControllerServiceEntity();
+        controllerServiceEntity.setRevision(revision);
+        controllerServiceEntity.setControllerService(controllerServiceDTO);
+
+        return createControllerService(httpServletRequest, controllerServiceEntity);
+    }
+
+    /**
+     * Creates a new Controller Service.
+     *
+     * @param httpServletRequest
+     * @param controllerServiceEntity A controllerServiceEntity.
+     * @return A controllerServiceEntity.
+     */
+    @POST
+    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @PreAuthorize("hasRole('ROLE_DFM')")
+    @TypeHint(ControllerServiceEntity.class)
+    public Response createControllerService(
+            @Context HttpServletRequest httpServletRequest,
+            ControllerServiceEntity controllerServiceEntity) {
+
+        if (controllerServiceEntity == null || controllerServiceEntity.getControllerService()== null) {
+            throw new IllegalArgumentException("Controller service details must be specified.");
+        }
+
+        if (controllerServiceEntity.getRevision() == null) {
+            throw new IllegalArgumentException("Revision must be specified.");
+        }
+
+        if (controllerServiceEntity.getControllerService().getId() != null) {
+            throw new IllegalArgumentException("Controller service ID cannot be specified.");
+        }
+
+        // if cluster manager, convert POST to PUT (to maintain same ID across nodes) and replicate
+        if (properties.isClusterManager()) {
+
+            // create ID for resource
+            final String id = UUID.randomUUID().toString();
+
+            // set ID for resource
+            controllerServiceEntity.getControllerService().setId(id);
+
+            // convert POST request to PUT request to force entity ID to be the same across nodes
+            URI putUri = null;
+            try {
+                putUri = new URI(getAbsolutePath().toString() + "/" + id);
+            } catch (final URISyntaxException e) {
+                throw new WebApplicationException(e);
+            }
+
+            // change content type to JSON for serializing entity
+            final Map<String, String> headersToOverride = new HashMap<>();
+            headersToOverride.put("content-type", MediaType.APPLICATION_JSON);
+
+            // replicate put request
+            return (Response) clusterManager.applyRequest(HttpMethod.PUT, putUri, updateClientId(controllerServiceEntity), getHeaders(headersToOverride)).getResponse();
+        }
+
+        // handle expects request (usually from the cluster manager)
+        final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
+        if (expects != null) {
+            return generateContinueResponse().build();
+        }
+
+        // create the controller service and generate the json
+        final RevisionDTO revision = controllerServiceEntity.getRevision();
+        final ConfigurationSnapshot<ControllerServiceDTO> controllerResponse = serviceFacade.createControllerService(
+                new Revision(revision.getVersion(), revision.getClientId()), controllerServiceEntity.getControllerService());
+        final ControllerServiceDTO controllerService = controllerResponse.getConfiguration();
+        populateRemainingControllerServiceContent(controllerService);
+
+        // get the updated revision
+        final RevisionDTO updatedRevision = new RevisionDTO();
+        updatedRevision.setClientId(revision.getClientId());
+        updatedRevision.setVersion(controllerResponse.getRevision());
+
+        // build the response entity
+        final ControllerServiceEntity entity = new ControllerServiceEntity();
+        entity.setRevision(updatedRevision);
+        entity.setControllerService(controllerService);
+
+        // build the response
+        return clusterContext(generateCreatedResponse(URI.create(controllerService.getUri()), entity)).build();
+    }
+
+    /**
+     * Retrieves the specified controller service.
+     *
+     * @param clientId Optional client id. If the client id is not specified, a
+     * new one will be generated. This value (whether specified or generated) is
+     * included in the response.
+     * @param id The id of the controller service to retrieve
+     * @return A controllerServiceEntity.
+     */
+    @GET
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Path("{id}")
+    @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
+    @TypeHint(ControllerServiceEntity.class)
+    public Response getFunnel(@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId, @PathParam("id") String id) {
+
+        // replicate if cluster manager
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
+        }
+
+        // get the controller service
+        final ControllerServiceDTO funnel = serviceFacade.getControllerService(id);
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+
+        // create the response entity
+        final ControllerServiceEntity entity = new ControllerServiceEntity();
+        entity.setRevision(revision);
+        entity.setControllerService(populateRemainingControllerServiceContent(funnel));
+
+        return clusterContext(generateOkResponse(entity)).build();
+    }
+
+    /**
+     * Updates the specified controller service.
+     *
+     * @param httpServletRequest
+     * @param version The revision is used to verify the client is working with
+     * the latest version of the flow.
+     * @param clientId Optional client id. If the client id is not specified, a
+     * new one will be generated. This value (whether specified or generated) is
+     * included in the response.
+     * @param id The id of the controller service to update.
+     * @return A controllerServiceEntity.
+     */
+    @PUT
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Path("{id}")
+    @PreAuthorize("hasRole('ROLE_DFM')")
+    @TypeHint(ControllerServiceEntity.class)
+    public Response updateControllerService(
+            @Context HttpServletRequest httpServletRequest,
+            @FormParam(VERSION) LongParameter version,
+            @FormParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
+            @PathParam("id") String id) {
+
+        // create the controller service DTO
+        final ControllerServiceDTO controllerServiceDTO = new ControllerServiceDTO();
+        controllerServiceDTO.setId(id);
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+
+        if (version != null) {
+            revision.setVersion(version.getLong());
+        }
+
+        // create the controller service entity
+        final ControllerServiceEntity controllerServiceEntity = new ControllerServiceEntity();
+        controllerServiceEntity.setRevision(revision);
+        controllerServiceEntity.setControllerService(controllerServiceDTO);
+
+        // update the controller service
+        return updateFunnel(httpServletRequest, id, controllerServiceEntity);
+    }
+
+    /**
+     * Updates the specified a new Controller Service.
+     *
+     * @param httpServletRequest
+     * @param id The id of the controller service to update.
+     * @param controllerServiceEntity A controllerServiceEntity.
+     * @return A controllerServiceEntity.
+     */
+    @PUT
+    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Path("{id}")
+    @PreAuthorize("hasRole('ROLE_DFM')")
+    @TypeHint(ControllerServiceEntity.class)
+    public Response updateFunnel(
+            @Context HttpServletRequest httpServletRequest,
+            @PathParam("id") String id,
+            ControllerServiceEntity controllerServiceEntity) {
+
+        if (controllerServiceEntity == null || controllerServiceEntity.getControllerService()== null) {
+            throw new IllegalArgumentException("Controller service details must be specified.");
+        }
+
+        if (controllerServiceEntity.getRevision() == null) {
+            throw new IllegalArgumentException("Revision must be specified.");
+        }
+
+        // ensure the ids are the same
+        final ControllerServiceDTO requestControllerServiceDTO = controllerServiceEntity.getControllerService();
+        if (!id.equals(requestControllerServiceDTO.getId())) {
+            throw new IllegalArgumentException(String.format("The controller service id (%s) in the request body does not equal the "
+                    + "controller service id of the requested resource (%s).", requestControllerServiceDTO.getId(), id));
+        }
+
+        // replicate if cluster manager
+        if (properties.isClusterManager()) {
+            // change content type to JSON for serializing entity
+            final Map<String, String> headersToOverride = new HashMap<>();
+            headersToOverride.put("content-type", MediaType.APPLICATION_JSON);
+
+            // replicate the request
+            return clusterManager.applyRequest(HttpMethod.PUT, getAbsolutePath(), updateClientId(controllerServiceEntity), getHeaders(headersToOverride)).getResponse();
+        }
+
+        // handle expects request (usually from the cluster manager)
+        final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
+        if (expects != null) {
+            serviceFacade.verifyUpdateControllerService(requestControllerServiceDTO);
+            return generateContinueResponse().build();
+        }
+
+        // update the controller service
+        final RevisionDTO revision = controllerServiceEntity.getRevision();
+        final ConfigurationSnapshot<ControllerServiceDTO> controllerResponse = serviceFacade.updateControllerService(
+                new Revision(revision.getVersion(), revision.getClientId()), requestControllerServiceDTO);
+
+        // get the results
+        final ControllerServiceDTO responseControllerServiceDTO = controllerResponse.getConfiguration();
+        populateRemainingControllerServiceContent(responseControllerServiceDTO);
+
+        // get the updated revision
+        final RevisionDTO updatedRevision = new RevisionDTO();
+        updatedRevision.setClientId(revision.getClientId());
+        updatedRevision.setVersion(controllerResponse.getRevision());
+
+        // build the response entity
+        final ControllerServiceEntity entity = new ControllerServiceEntity();
+        entity.setRevision(updatedRevision);
+        entity.setControllerService(responseControllerServiceDTO);
+
+        return clusterContext(generateOkResponse(entity)).build();
+    }
+
+    /**
+     * Removes the specified controller service.
+     *
+     * @param httpServletRequest
+     * @param version The revision is used to verify the client is working with
+     * the latest version of the flow.
+     * @param clientId Optional client id. If the client id is not specified, a
+     * new one will be generated. This value (whether specified or generated) is
+     * included in the response.
+     * @param id The id of the controller service to remove.
+     * @return A entity containing the client id and an updated revision.
+     */
+    @DELETE
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Path("{id}")
+    @PreAuthorize("hasRole('ROLE_DFM')")
+    @TypeHint(ControllerServiceEntity.class)
+    public Response removeControllerService(
+            @Context HttpServletRequest httpServletRequest,
+            @QueryParam(VERSION) LongParameter version,
+            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
+            @PathParam("id") String id) {
+
+        // replicate if cluster manager
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.DELETE, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
+        }
+
+        // handle expects request (usually from the cluster manager)
+        final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
+        if (expects != null) {
+            serviceFacade.verifyDeleteControllerService(id);
+            return generateContinueResponse().build();
+        }
+
+        // determine the specified version
+        Long clientVersion = null;
+        if (version != null) {
+            clientVersion = version.getLong();
+        }
+
+        // delete the specified funnel
+        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteControllerService(new Revision(clientVersion, clientId.getClientId()), id);
+
+        // get the updated revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+        revision.setVersion(controllerResponse.getRevision());
+
+        // build the response entity
+        final ControllerServiceEntity entity = new ControllerServiceEntity();
+        entity.setRevision(revision);
+
+        return clusterContext(generateOkResponse(entity)).build();
+    }
+
+    // setters
+    public void setServiceFacade(NiFiServiceFacade serviceFacade) {
+        this.serviceFacade = serviceFacade;
+    }
+
+    public void setClusterManager(WebClusterManager clusterManager) {
+        this.clusterManager = clusterManager;
+    }
+
+    public void setProperties(NiFiProperties properties) {
+        this.properties = properties;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.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/api/dto/DtoFactory.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
index 027bae0..7d44624 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
@@ -99,8 +99,7 @@ import org.apache.nifi.user.NiFiUserGroup;
 import org.apache.nifi.util.FormatUtils;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.Revision;
-import org.apache.nifi.web.api.dto.ProcessorConfigDTO.AllowableValueDTO;
-import org.apache.nifi.web.api.dto.ProcessorConfigDTO.PropertyDescriptorDTO;
+import org.apache.nifi.web.api.dto.PropertyDescriptorDTO.AllowableValueDTO;
 import org.apache.nifi.web.api.dto.action.ActionDTO;
 import org.apache.nifi.web.api.dto.action.HistoryDTO;
 import org.apache.nifi.web.api.dto.action.component.details.ComponentDetailsDTO;
@@ -124,6 +123,7 @@ import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
 import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
 import org.apache.nifi.web.api.dto.status.StatusDTO;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.controller.service.ControllerServiceNode;
 
 /**
  *
@@ -835,6 +835,59 @@ public final class DtoFactory {
         return dto;
     }
 
+    public ControllerServiceDTO createControllerServiceDto(final ControllerServiceNode controllerServiceNode) {
+        if (controllerServiceNode == null) {
+            return null;
+        }
+        
+        final ControllerServiceDTO dto = new ControllerServiceDTO();
+        dto.setId(controllerServiceNode.getIdentifier());
+        dto.setName(controllerServiceNode.getName());
+        dto.setAvailability(controllerServiceNode.getAvailability().name());
+        dto.setEnabled(!controllerServiceNode.isDisabled());
+        
+        // sort a copy of the properties
+        final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() {
+            @Override
+            public int compare(PropertyDescriptor o1, PropertyDescriptor o2) {
+                return Collator.getInstance(Locale.US).compare(o1.getName(), o2.getName());
+            }
+        });
+        sortedProperties.putAll(controllerServiceNode.getProperties());
+
+        // get the property order from the controller service
+        final ControllerService controllerService = controllerServiceNode.getControllerService();
+        final Map<PropertyDescriptor, String> orderedProperties = new LinkedHashMap<>();
+        final List<PropertyDescriptor> descriptors = controllerService.getPropertyDescriptors();
+        if (descriptors != null && !descriptors.isEmpty()) {
+            for (PropertyDescriptor descriptor : descriptors) {
+                orderedProperties.put(descriptor, null);
+            }
+        }
+        orderedProperties.putAll(sortedProperties);
+        
+        // build the descriptor and property dtos
+        dto.setDescriptors(new LinkedHashMap<String, PropertyDescriptorDTO>());
+        dto.setProperties(new LinkedHashMap<String, String>());
+        for (final Map.Entry<PropertyDescriptor, String> entry : orderedProperties.entrySet()) {
+            final PropertyDescriptor descriptor = entry.getKey();
+
+            // store the property descriptor
+            dto.getDescriptors().put(descriptor.getName(), createPropertyDescriptorDto(descriptor));
+
+            // determine the property value - don't include sensitive properties
+            String propertyValue = entry.getValue();
+            if (propertyValue != null && descriptor.isSensitive()) {
+                propertyValue = "********";
+            }
+
+            // set the property value
+            dto.getProperties().put(descriptor.getName(), propertyValue);
+        }
+        
+        return dto;
+    }
+    
     public RemoteProcessGroupPortDTO createRemoteProcessGroupPortDto(final RemoteGroupPort port) {
         if (port == null) {
             return null;
@@ -1686,12 +1739,12 @@ public final class DtoFactory {
      * @param propertyDescriptor
      * @return
      */
-    private ProcessorConfigDTO.PropertyDescriptorDTO createPropertyDescriptorDto(final PropertyDescriptor propertyDescriptor) {
+    private PropertyDescriptorDTO createPropertyDescriptorDto(final PropertyDescriptor propertyDescriptor) {
         if (propertyDescriptor == null) {
             return null;
         }
 
-        final ProcessorConfigDTO.PropertyDescriptorDTO dto = new ProcessorConfigDTO.PropertyDescriptorDTO();
+        final PropertyDescriptorDTO dto = new PropertyDescriptorDTO();
 
         dto.setName(propertyDescriptor.getName());
         dto.setDisplayName(propertyDescriptor.getDisplayName());

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ControllerServiceDAO.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/dao/ControllerServiceDAO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ControllerServiceDAO.java
new file mode 100644
index 0000000..3fb1aed
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ControllerServiceDAO.java
@@ -0,0 +1,88 @@
+/*
+ * 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.dao;
+
+import java.util.Set;
+
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+
+/**
+ *
+ */
+public interface ControllerServiceDAO {
+
+    /**
+     * Determines if the specified controller service exists.
+     *
+     * @param controllerServiceId
+     * @return
+     */
+    boolean hasControllerService(String controllerServiceId);
+
+    /**
+     * Creates a controller service.
+     *
+     * @param controllerServiceDTO The controller service DTO
+     * @return The controller service
+     */
+    ControllerServiceNode createControllerService(ControllerServiceDTO controllerServiceDTO);
+
+    /**
+     * Gets the specified controller service.
+     *
+     * @param controllerServiceId The controller service id
+     * @return The controller service
+     */
+    ControllerServiceNode getControllerService(String controllerServiceId);
+
+    /**
+     * Gets all of the controller services.
+     *
+     * @return The controller services
+     */
+    Set<ControllerServiceNode> getControllerServices();
+
+    /**
+     * Updates the specified controller service.
+     *
+     * @param controllerServiceDTO The controller service DTO
+     * @return The controller service
+     */
+    ControllerServiceNode updateControllerService(ControllerServiceDTO controllerServiceDTO);
+
+    /**
+     * Determines whether this controller service can be updated.
+     *
+     * @param controllerServiceDTO
+     */
+    void verifyUpdate(ControllerServiceDTO controllerServiceDTO);
+    
+    /**
+     * Determines whether this controller service can be removed.
+     *
+     * @param controllerServiceId
+     */
+    void verifyDelete(String controllerServiceId);
+
+    /**
+     * Deletes the specified controller service.
+     *
+     * @param controllerServiceId The controller service id
+     */
+    void deleteControllerService(String controllerServiceId);
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardControllerServiceDAO.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/dao/impl/StandardControllerServiceDAO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardControllerServiceDAO.java
new file mode 100644
index 0000000..6feab86
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardControllerServiceDAO.java
@@ -0,0 +1,138 @@
+/*
+ * 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.dao.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.nifi.controller.FlowController;
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.web.ResourceNotFoundException;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+import org.apache.nifi.web.dao.ControllerServiceDAO;
+
+public class StandardControllerServiceDAO extends ComponentDAO implements ControllerServiceDAO {
+
+    private FlowController flowController;
+
+    /**
+     * Locates the specified controller service.
+     *
+     * @param controllerServiceId
+     * @return
+     */
+    private ControllerServiceNode locateControllerService(final String controllerServiceId) {
+        // get the controller service
+        final ControllerServiceNode controllerService = flowController.getControllerServiceNode(controllerServiceId);
+
+        // ensure the controller service exists
+        if (controllerService == null) {
+            throw new ResourceNotFoundException(String.format("Unable to locate controller service with id '%s'.", controllerServiceId));
+        }
+
+        return controllerService;
+    }
+
+    /**
+     * Creates a controller service.
+     *
+     * @param controllerServiceDTO The controller service DTO
+     * @return The controller service
+     */
+    @Override
+    public ControllerServiceNode createControllerService(final ControllerServiceDTO controllerServiceDTO) {
+        final Map<String, String> temp = new HashMap<>();
+        
+        // create the controller service
+        final ControllerServiceNode controllerService = flowController.createControllerService(controllerServiceDTO.getType(), controllerServiceDTO.getName(), temp);
+        return controllerService;
+    }
+
+    /**
+     * Gets the specified controller service.
+     *
+     * @param controllerServiceId The controller service id
+     * @return The controller service
+     */
+    @Override
+    public ControllerServiceNode getControllerService(final String controllerServiceId) {
+        return locateControllerService(controllerServiceId);
+    }
+
+    /**
+     * Determines if the specified controller service exists.
+     *
+     * @param controllerServiceId
+     * @return
+     */
+    @Override
+    public boolean hasControllerService(final String controllerServiceId) {
+        return flowController.getControllerServiceNode(controllerServiceId) != null;
+    }
+
+    /**
+     * Gets all of the controller services.
+     *
+     * @return The controller services
+     */
+    @Override
+    public Set<ControllerServiceNode> getControllerServices() {
+        return null;
+    }
+
+    /**
+     * Updates the specified controller service.
+     *
+     * @param controllerServiceDTO The controller service DTO
+     * @return The controller service
+     */
+    @Override
+    public ControllerServiceNode updateControllerService(final ControllerServiceDTO controllerServiceDTO) {
+        // get the controller service
+        final ControllerServiceNode controllerService = locateControllerService(controllerServiceDTO.getId());
+        
+        return controllerService;
+    }
+
+    @Override
+    public void verifyDelete(final String controllerServiceId) {
+        final ControllerServiceNode controllerService = locateControllerService(controllerServiceId);
+//        controllerService.verifyCanDelete();
+    }
+
+    @Override
+    public void verifyUpdate(final ControllerServiceDTO controllerServiceDTO) {
+        final ControllerServiceNode controllerService = locateControllerService(controllerServiceDTO.getId());
+//        controllerService.verifyCanDelete();
+    }
+    
+    /**
+     * Deletes the specified controller service.
+     *
+     * @param controllerServiceId The controller service id
+     */
+    @Override
+    public void deleteControllerService(String controllerServiceId) {
+        final ControllerServiceNode controllerService = locateControllerService(controllerServiceId);
+    }
+
+    /* setters */
+    public void setFlowController(FlowController flowController) {
+        this.flowController = flowController;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e604cafe/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 39677ca..a84416f 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
@@ -68,6 +68,9 @@
     <bean id="processorDAO" class="org.apache.nifi.web.dao.impl.StandardProcessorDAO">
         <property name="flowController" ref="flowController"/>
     </bean>
+    <bean id="controllerServiceDAO" class="org.apache.nifi.web.dao.impl.StandardControllerServiceDAO">
+        <property name="flowController" ref="flowController"/>
+    </bean>
     <bean id="templateDAO" class="org.apache.nifi.web.dao.impl.StandardTemplateDAO">
         <property name="flowController" ref="flowController"/>
         <property name="snippetUtils" ref="snippetUtils"/>
@@ -94,6 +97,7 @@
         <property name="labelDAO" ref="labelDAO"/>
         <property name="funnelDAO" ref="funnelDAO"/>
         <property name="connectionDAO" ref="connectionDAO"/>
+        <property name="controllerServiceDAO" ref="controllerServiceDAO"/>
         <property name="templateDAO" ref="templateDAO"/>
         <property name="snippetDAO" ref="snippetDAO"/>
         <property name="auditService" ref="auditService"/>
@@ -126,6 +130,11 @@
         <property name="properties" ref="nifiProperties"/>
         <property name="clusterManager" ref="clusterManager"/>
     </bean>
+    <bean id="controllerServiceResource" class="org.apache.nifi.web.api.ControllerServiceResource" scope="singleton">
+        <property name="serviceFacade" ref="serviceFacade"/>
+        <property name="properties" ref="nifiProperties"/>
+        <property name="clusterManager" ref="clusterManager"/>
+    </bean>
     <bean id="processGroupResource" class="org.apache.nifi.web.api.ProcessGroupResource" scope="prototype">
         <property name="serviceFacade" ref="serviceFacade"/>
         <property name="properties" ref="nifiProperties"/>