You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by dk...@apache.org on 2021/01/18 19:44:44 UTC

[sling-org-apache-sling-app-cms] branch forms-enhancements updated: Adding support for deleting UGC and cleaning up the usage of component configurations

This is an automated email from the ASF dual-hosted git repository.

dklco pushed a commit to branch forms-enhancements
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-app-cms.git


The following commit(s) were added to refs/heads/forms-enhancements by this push:
     new 20e23e4  Adding support for deleting UGC and cleaning up the usage of component configurations
20e23e4 is described below

commit 20e23e4389f31888e28051f11f83ebff6aaa674a
Author: Dan Klco <dk...@apache.org>
AuthorDate: Mon Jan 18 14:44:05 2021 -0500

    Adding support for deleting UGC and cleaning up the usage of component configurations
---
 .../forms/impl/actions/CreateUserAction.java       |  21 +---
 ....java => DeleteUserGeneratedContentAction.java} |  74 ++++++------
 .../impl/actions/RequestPasswordResetAction.java   |  22 +---
 .../forms/impl/actions/ResetPasswordAction.java    |  21 +---
 .../forms/impl/actions/SendEmailAction.java        |  21 +---
 .../forms/impl/actions/UpdateProfileAction.java    |  25 +----
 ....java => UpdateUserGeneratedContentAction.java} |  61 +++++-----
 .../impl/actions/UserGeneratedContentAction.java   |  18 ++-
 .../forms/impl/fields/SelectionHandler.java        |  28 ++++-
 .../forms/impl/fields/TextareaHandler.java         |  28 ++++-
 .../forms/impl/fields/TextfieldHandler.java        |  25 ++++-
 .../main/resources/OSGI-INF/l10n/bundle.properties |  19 +---
 .../{updateresource.json => deleteugc.json}        |   2 +-
 .../updateresource.jsp => deleteugc/deleteugc.jsp} |   6 +-
 .../components/forms/actions/deleteugc/edit.json   |  14 +++
 .../forms/actions/updateresource/edit.json         |  32 ------
 .../{updateresource.json => updateugc.json}        |   2 +-
 .../components/forms/actions/updateugc/edit.json   |  14 +++
 .../updateresource.jsp => updateugc/updateugc.jsp} |   6 +-
 .../cms/reference/forms/FormActionResultTest.java  |   2 -
 .../cms/reference/forms/impl/FormHandlerTest.java  |  50 ++++++---
 .../reference/forms/impl/FormRequestImplTest.java  |  39 ++++++-
 .../forms/impl/actions/CreateUserActionTest.java   |  23 +---
 ...a => DeleteUserGeneratedContentActionTest.java} | 125 ++++++++++-----------
 .../actions/RequestPasswordResetActionTest.java    |  22 +---
 .../impl/actions/ResetPasswordActionTest.java      |  27 ++---
 .../forms/impl/actions/SendEmailActionTest.java    |  15 +--
 .../impl/actions/UpdateProfileActionTest.java      |  23 +---
 ...a => UpdateUserGeneratedContentActionTest.java} | 100 +++++++++--------
 .../actions/UserGeneratedContentActionTest.java    |  90 +++++++++++++++
 .../forms/impl/fields/HoneypotHandlerTest.java     |   3 -
 .../forms/impl/fields/SelectionHandlerTest.java    |  17 ++-
 .../forms/impl/fields/TextareaHandlerTest.java     |  20 +++-
 .../forms/impl/fields/TextfieldHandlerTest.java    |  16 ++-
 34 files changed, 551 insertions(+), 460 deletions(-)

diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/CreateUserAction.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/CreateUserAction.java
index 914f7a0..43bbd18 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/CreateUserAction.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/CreateUserAction.java
@@ -45,35 +45,28 @@ import org.apache.sling.cms.reference.forms.FormActionResult;
 import org.apache.sling.cms.reference.forms.FormConstants;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.FormRequest;
-import org.apache.sling.cms.reference.forms.FormUtils;
 import org.jetbrains.annotations.NotNull;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = { FormAction.class })
-@Designate(ocd = CreateUserAction.Config.class)
 public class CreateUserAction implements FormAction {
 
     private static final Logger log = LoggerFactory.getLogger(CreateUserAction.class);
-    public static final String DEFAULT_RESOURCE_TYPE = "reference/components/forms/actions/createuser";
+    public static final String RESOURCE_TYPE = "reference/components/forms/actions/createuser";
     public static final String PROFILE_PROPERTIES = "profileProperties";
     public static final String GROUPS = "groups";
     public static final String PN_USERNAME = "username";
     public static final String PN_INTERMEDIATE_PATH = "intermediatePath";
 
     private final ResourceResolverFactory factory;
-    private final Config config;
 
     @Activate
-    public CreateUserAction(@Reference ResourceResolverFactory factory, Config config) {
+    public CreateUserAction(@Reference ResourceResolverFactory factory) {
         this.factory = factory;
-        this.config = config;
     }
 
     @Override
@@ -151,15 +144,7 @@ public class CreateUserAction implements FormAction {
 
     @Override
     public boolean handles(Resource actionResource) {
-        return FormUtils.handles(config.supportedTypes(), actionResource);
-    }
-
-    @ObjectClassDefinition(name = "%cms.reference.createuser.name", description = "%cms.reference.createuser.description", localization = "OSGI-INF/l10n/bundle")
-    public @interface Config {
-
-        @AttributeDefinition(name = "%cms.reference.supportedTypes.name", description = "%cms.reference.supportedTypes.description", defaultValue = {
-                DEFAULT_RESOURCE_TYPE })
-        String[] supportedTypes() default { DEFAULT_RESOURCE_TYPE };
+        return RESOURCE_TYPE.equals(actionResource.getResourceType());
     }
 
 }
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceAction.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/DeleteUserGeneratedContentAction.java
similarity index 50%
copy from reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceAction.java
copy to reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/DeleteUserGeneratedContentAction.java
index b6b4203..8f9f6b0 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceAction.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/DeleteUserGeneratedContentAction.java
@@ -16,24 +16,18 @@
  */
 package org.apache.sling.cms.reference.forms.impl.actions;
 
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.Map;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.text.StringSubstitutor;
-import org.apache.jackrabbit.JcrConstants;
 import org.apache.sling.api.resource.LoginException;
-import org.apache.sling.api.resource.ModifiableValueMap;
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.cms.CMSConstants;
 import org.apache.sling.cms.reference.forms.FormAction;
 import org.apache.sling.cms.reference.forms.FormActionResult;
-import org.apache.sling.cms.reference.forms.FormConstants;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.FormRequest;
 import org.osgi.service.component.annotations.Activate;
@@ -43,14 +37,14 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = FormAction.class, immediate = true)
-public class UpdateResourceAction implements FormAction {
+public class DeleteUserGeneratedContentAction implements FormAction {
 
-    private static final Logger log = LoggerFactory.getLogger(UpdateResourceAction.class);
+    private static final Logger log = LoggerFactory.getLogger(DeleteUserGeneratedContentAction.class);
 
     private ResourceResolverFactory factory;
 
     @Activate
-    public UpdateResourceAction(@Reference ResourceResolverFactory factory) {
+    public DeleteUserGeneratedContentAction(@Reference ResourceResolverFactory factory) {
         this.factory = factory;
     }
 
@@ -60,54 +54,50 @@ public class UpdateResourceAction implements FormAction {
 
         ValueMap properties = actionResource.getValueMap();
 
-        String[] allowedProperties = properties.get(FormConstants.PN_ALLOWED_PROPERTIES, String[].class);
-        ResourceResolver resolver = null;
-        try {
-            resolver = getResourceResolver(actionResource);
+        try (ResourceResolver resolver = getResourceResolver()) {
             StringSubstitutor sub = new StringSubstitutor(request.getFormData());
 
             String path = sub.replace(properties.get("path", String.class));
-            log.debug("Upserting resource at path: {}", path);
-            Resource resource = ResourceUtil.getOrCreateResource(resolver, path,
-                    Collections.singletonMap(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED),
-                    JcrConstants.NT_UNSTRUCTURED, false);
-
-            ModifiableValueMap mvm = resource.adaptTo(ModifiableValueMap.class);
-            Map<String, Object> formData = request.getFormData();
-            if (allowedProperties != null && allowedProperties.length > 0) {
-                Arrays.stream(allowedProperties).filter(formData::containsKey).forEach(p -> {
-                    log.debug("Setting property {}", p);
-                    mvm.put(p, formData.get(p));
-                });
-            } else {
-                mvm.putAll(formData);
+            log.debug("Deleting UGC resource at path: {}", path);
+
+            Resource resource = resolver.getResource(path);
+            if (resource == null) {
+                throw new FormException("Could not find UGC resource at path: " + path);
+            }
+            Resource ugcParent = findUgcParent(resource);
+
+            if (!request.getOriginalRequest().getResourceResolver().getUserID()
+                    .equals(ugcParent.getValueMap().get("user", String.class))) {
+                throw new FormException("Cannot delete content not created by the current user");
             }
+
+            resolver.delete(ugcParent);
             resolver.commit();
-            log.debug("Successfully persisted resource");
-            return FormActionResult.success("Updated resource");
+            log.debug("Successfully deleted user generated content");
+            return FormActionResult.success("Deleted user generated content");
         } catch (LoginException | PersistenceException e) {
-            throw new FormException("Failed to update resource", e);
-        } finally {
-            if (StringUtils.isNotBlank(properties.get(FormConstants.PN_SERVICE_USER, String.class)) && resolver != null) {
-                resolver.close();
-            }
+            throw new FormException("Failed to delete user generated content", e);
         }
     }
 
-    private ResourceResolver getResourceResolver(Resource actionResource) throws LoginException {
-        String serviceUser = actionResource.getValueMap().get(FormConstants.PN_SERVICE_USER, String.class);
-        if (StringUtils.isNotBlank(serviceUser)) {
-            return factory.getServiceResourceResolver(
-                    Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, serviceUser));
+    private Resource findUgcParent(Resource resource) throws FormException {
+        if (CMSConstants.NT_UGC.equals(resource.getResourceType())) {
+            return resource;
+        } else if (resource.getParent() != null) {
+            return findUgcParent(resource.getParent());
         } else {
-            return actionResource.getResourceResolver();
+            throw new FormException("Failed to find UGC Parent");
         }
+    }
 
+    private ResourceResolver getResourceResolver() throws LoginException {
+        return factory.getServiceResourceResolver(
+                Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, "sling-cms-ugc"));
     }
 
     @Override
     public boolean handles(Resource actionResource) {
-        return "reference/components/forms/actions/updateresource".equals(actionResource.getResourceType());
+        return "reference/components/forms/actions/deleteugc".equals(actionResource.getResourceType());
     }
 
 }
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/RequestPasswordResetAction.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/RequestPasswordResetAction.java
index 9ab6da6..3e95ed9 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/RequestPasswordResetAction.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/RequestPasswordResetAction.java
@@ -19,7 +19,6 @@ package org.apache.sling.cms.reference.forms.impl.actions;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.UUID;
-import java.util.stream.Stream;
 
 import javax.jcr.Session;
 import javax.jcr.ValueFactory;
@@ -38,27 +37,22 @@ import org.apache.sling.cms.reference.forms.FormRequest;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = { FormAction.class })
-@Designate(ocd = RequestPasswordResetAction.Config.class)
 public class RequestPasswordResetAction implements FormAction {
 
-    public static final String DEFAULT_RESOURCE_TYPE = "reference/components/forms/actions/requestpasswordreset";
+    public static final String RESOURCE_TYPE = "reference/components/forms/actions/requestpasswordreset";
     public static final String PN_RESETTOKEN = "resettoken";
     public static final String PN_RESETTIMEOUT = "resettimeout";
     private static final Logger log = LoggerFactory.getLogger(RequestPasswordResetAction.class);
     private ResourceResolverFactory factory;
-    private Config config;
 
     @Activate
-    public RequestPasswordResetAction(@Reference ResourceResolverFactory factory, Config config) {
+    public RequestPasswordResetAction(@Reference ResourceResolverFactory factory) {
         this.factory = factory;
-        this.config = config;
+
     }
 
     @Override
@@ -101,15 +95,7 @@ public class RequestPasswordResetAction implements FormAction {
 
     @Override
     public boolean handles(Resource actionResource) {
-        return Stream.of(config.supportedTypes()).anyMatch(t -> t.equals(actionResource.getResourceType()));
-    }
-
-    @ObjectClassDefinition(name = "%cms.reference.requestpasswordreset.name", description = "%cms.reference.requestpasswordreset.description", localization = "OSGI-INF/l10n/bundle")
-    public @interface Config {
-
-        @AttributeDefinition(name = "%cms.reference.supportedTypes.name", description = "%cms.reference.supportedTypes.description", defaultValue = {
-                DEFAULT_RESOURCE_TYPE })
-        String[] supportedTypes() default { DEFAULT_RESOURCE_TYPE };
+        return RESOURCE_TYPE.equals(actionResource.getResourceType());
     }
 
 }
\ No newline at end of file
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/ResetPasswordAction.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/ResetPasswordAction.java
index 8edbfc8..56d8d1d 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/ResetPasswordAction.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/ResetPasswordAction.java
@@ -34,29 +34,22 @@ import org.apache.sling.cms.reference.forms.FormActionResult;
 import org.apache.sling.cms.reference.forms.FormConstants;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.FormRequest;
-import org.apache.sling.cms.reference.forms.FormUtils;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = { FormAction.class })
-@Designate(ocd = ResetPasswordAction.Config.class)
 public class ResetPasswordAction implements FormAction {
 
-    public static final String DEFAULT_RESOURCE_TYPE = "reference/components/forms/actions/resetpassword";
+    public static final String RESOURCE_TYPE = "reference/components/forms/actions/resetpassword";
     private static final Logger log = LoggerFactory.getLogger(ResetPasswordAction.class);
     private ResourceResolverFactory factory;
-    private Config config;
 
     @Activate
-    public ResetPasswordAction(@Reference ResourceResolverFactory factory, Config config) {
+    public ResetPasswordAction(@Reference ResourceResolverFactory factory) {
         this.factory = factory;
-        this.config = config;
     }
 
     @Override
@@ -111,15 +104,7 @@ public class ResetPasswordAction implements FormAction {
 
     @Override
     public boolean handles(Resource actionResource) {
-        return FormUtils.handles(config.supportedTypes(), actionResource);
-    }
-
-    @ObjectClassDefinition(name = "%cms.reference.resetpassword.name", description = "%cms.reference.resetpassword.description", localization = "OSGI-INF/l10n/bundle")
-    public @interface Config {
-
-        @AttributeDefinition(name = "%cms.reference.supportedTypes.name", description = "%cms.reference.supportedTypes.description", defaultValue = {
-                DEFAULT_RESOURCE_TYPE })
-        String[] supportedTypes() default { DEFAULT_RESOURCE_TYPE };
+        return RESOURCE_TYPE.equals(actionResource.getResourceType());
     }
 
 }
\ No newline at end of file
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/SendEmailAction.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/SendEmailAction.java
index cc20283..3a40c11 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/SendEmailAction.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/SendEmailAction.java
@@ -16,8 +16,6 @@
  */
 package org.apache.sling.cms.reference.forms.impl.actions;
 
-import java.util.stream.Stream;
-
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 
@@ -33,17 +31,13 @@ import org.jetbrains.annotations.NotNull;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = { FormAction.class })
-@Designate(ocd = SendEmailAction.Config.class)
 public class SendEmailAction implements FormAction {
 
-    public static final String DEFAULT_RESOURCE_TYPE = "reference/components/forms/actions/sendemail";
+    public static final String RESOURCE_TYPE = "reference/components/forms/actions/sendemail";
     public static final String FROM = "from";
     private static final Logger log = LoggerFactory.getLogger(SendEmailAction.class);
 
@@ -52,12 +46,10 @@ public class SendEmailAction implements FormAction {
     public static final String TO = "to";
 
     private final MailService mailService;
-    private Config config;
 
     @Activate
-    public SendEmailAction(@Reference MailService mailService, Config config) {
+    public SendEmailAction(@Reference MailService mailService) {
         this.mailService = mailService;
-        this.config = config;
     }
 
     @Override
@@ -87,14 +79,7 @@ public class SendEmailAction implements FormAction {
 
     @Override
     public boolean handles(Resource actionResource) {
-        return Stream.of(config.supportedTypes()).anyMatch(t -> t.equals(actionResource.getResourceType()));
+        return RESOURCE_TYPE.equals(actionResource.getResourceType());
     }
 
-    @ObjectClassDefinition(name = "%cms.reference.sendemail.name", description = "%cms.reference.sendemail.description", localization = "OSGI-INF/l10n/bundle")
-    public @interface Config {
-
-        @AttributeDefinition(name = "%cms.reference.supportedTypes.name", description = "%cms.reference.supportedTypes.description", defaultValue = {
-                DEFAULT_RESOURCE_TYPE })
-        String[] supportedTypes() default { DEFAULT_RESOURCE_TYPE };
-    }
 }
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateProfileAction.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateProfileAction.java
index 58ffa08..84dea5f 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateProfileAction.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateProfileAction.java
@@ -18,8 +18,8 @@ package org.apache.sling.cms.reference.forms.impl.actions;
 
 import java.util.Arrays;
 import java.util.Calendar;
-import java.util.Optional;
 import java.util.Map.Entry;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 import javax.jcr.RepositoryException;
@@ -38,28 +38,17 @@ import org.apache.sling.cms.reference.forms.FormActionResult;
 import org.apache.sling.cms.reference.forms.FormConstants;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.FormRequest;
-import org.apache.sling.cms.reference.forms.FormUtils;
 import org.osgi.service.component.annotations.Component;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = FormAction.class)
-@Designate(ocd = UpdateProfileAction.Config.class)
 public class UpdateProfileAction implements FormAction {
 
-    public static final String DEFAULT_RESOURCE_TYPE = "reference/components/forms/actions/updateprofile";
+    public static final String RESOURCE_TYPE = "reference/components/forms/actions/updateprofile";
 
     private static final Logger log = LoggerFactory.getLogger(UpdateProfileAction.class);
 
-    private Config config;
-
-    public UpdateProfileAction(Config config) {
-        this.config = config;
-    }
-
     @Override
     public FormActionResult handleForm(Resource actionResource, FormRequest request) throws FormException {
         ResourceResolver resolver = request.getOriginalRequest().getResourceResolver();
@@ -115,15 +104,7 @@ public class UpdateProfileAction implements FormAction {
 
     @Override
     public boolean handles(Resource actionResource) {
-        return FormUtils.handles(config.supportedTypes(), actionResource);
-    }
-
-    @ObjectClassDefinition(name = "%cms.reference.updateprofile.name", description = "%cms.reference.updateprofile.description", localization = "OSGI-INF/l10n/bundle")
-    public @interface Config {
-
-        @AttributeDefinition(name = "%cms.reference.supportedTypes.name", description = "%cms.reference.supportedTypes.description", defaultValue = {
-                DEFAULT_RESOURCE_TYPE })
-        String[] supportedTypes() default { DEFAULT_RESOURCE_TYPE };
+        return RESOURCE_TYPE.equals(actionResource.getResourceType());
     }
 
 }
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceAction.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateUserGeneratedContentAction.java
similarity index 59%
rename from reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceAction.java
rename to reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateUserGeneratedContentAction.java
index b6b4203..2a94383 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceAction.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateUserGeneratedContentAction.java
@@ -16,24 +16,20 @@
  */
 package org.apache.sling.cms.reference.forms.impl.actions;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Map;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.text.StringSubstitutor;
-import org.apache.jackrabbit.JcrConstants;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ModifiableValueMap;
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.cms.CMSConstants;
 import org.apache.sling.cms.reference.forms.FormAction;
 import org.apache.sling.cms.reference.forms.FormActionResult;
-import org.apache.sling.cms.reference.forms.FormConstants;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.FormRequest;
 import org.osgi.service.component.annotations.Activate;
@@ -43,14 +39,14 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = FormAction.class, immediate = true)
-public class UpdateResourceAction implements FormAction {
+public class UpdateUserGeneratedContentAction implements FormAction {
 
-    private static final Logger log = LoggerFactory.getLogger(UpdateResourceAction.class);
+    private static final Logger log = LoggerFactory.getLogger(UpdateUserGeneratedContentAction.class);
 
     private ResourceResolverFactory factory;
 
     @Activate
-    public UpdateResourceAction(@Reference ResourceResolverFactory factory) {
+    public UpdateUserGeneratedContentAction(@Reference ResourceResolverFactory factory) {
         this.factory = factory;
     }
 
@@ -60,54 +56,49 @@ public class UpdateResourceAction implements FormAction {
 
         ValueMap properties = actionResource.getValueMap();
 
-        String[] allowedProperties = properties.get(FormConstants.PN_ALLOWED_PROPERTIES, String[].class);
-        ResourceResolver resolver = null;
-        try {
-            resolver = getResourceResolver(actionResource);
+        try (ResourceResolver resolver = getResourceResolver()) {
             StringSubstitutor sub = new StringSubstitutor(request.getFormData());
 
             String path = sub.replace(properties.get("path", String.class));
-            log.debug("Upserting resource at path: {}", path);
-            Resource resource = ResourceUtil.getOrCreateResource(resolver, path,
-                    Collections.singletonMap(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED),
-                    JcrConstants.NT_UNSTRUCTURED, false);
+            log.debug("Updating UGC resource at path: {}", path);
+
+            Resource resource = resolver.getResource(path);
+            Resource ugcParent = findUgcParent(resource);
+
+            if (!request.getOriginalRequest().getResourceResolver().getUserID()
+                    .equals(ugcParent.getValueMap().get("user", String.class))) {
+                throw new FormException("Cannot modify content not created by the current user");
+            }
 
             ModifiableValueMap mvm = resource.adaptTo(ModifiableValueMap.class);
             Map<String, Object> formData = request.getFormData();
-            if (allowedProperties != null && allowedProperties.length > 0) {
-                Arrays.stream(allowedProperties).filter(formData::containsKey).forEach(p -> {
-                    log.debug("Setting property {}", p);
-                    mvm.put(p, formData.get(p));
-                });
-            } else {
-                mvm.putAll(formData);
-            }
+            mvm.putAll(formData);
             resolver.commit();
             log.debug("Successfully persisted resource");
             return FormActionResult.success("Updated resource");
         } catch (LoginException | PersistenceException e) {
             throw new FormException("Failed to update resource", e);
-        } finally {
-            if (StringUtils.isNotBlank(properties.get(FormConstants.PN_SERVICE_USER, String.class)) && resolver != null) {
-                resolver.close();
-            }
         }
     }
 
-    private ResourceResolver getResourceResolver(Resource actionResource) throws LoginException {
-        String serviceUser = actionResource.getValueMap().get(FormConstants.PN_SERVICE_USER, String.class);
-        if (StringUtils.isNotBlank(serviceUser)) {
-            return factory.getServiceResourceResolver(
-                    Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, serviceUser));
+    private Resource findUgcParent(Resource resource) throws FormException {
+        if (CMSConstants.NT_UGC.equals(resource.getResourceType())) {
+            return resource;
+        } else if (resource.getParent() != null) {
+            return findUgcParent(resource.getParent());
         } else {
-            return actionResource.getResourceResolver();
+            throw new FormException("Failed to find UGC Parent");
         }
+    }
 
+    private ResourceResolver getResourceResolver() throws LoginException {
+        return factory.getServiceResourceResolver(
+                Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, "sling-cms-ugc"));
     }
 
     @Override
     public boolean handles(Resource actionResource) {
-        return "reference/components/forms/actions/updateresource".equals(actionResource.getResourceType());
+        return "reference/components/forms/actions/updateugc".equals(actionResource.getResourceType());
     }
 
 }
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UserGeneratedContentAction.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UserGeneratedContentAction.java
index 084d17f..fb5fa17 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UserGeneratedContentAction.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/actions/UserGeneratedContentAction.java
@@ -20,9 +20,10 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
-import org.apache.commons.text.StringSubstitutor;
 import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.text.StringSubstitutor;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
@@ -38,6 +39,7 @@ import org.apache.sling.cms.usergenerated.UGCBucketConfig;
 import org.apache.sling.cms.usergenerated.UserGeneratedContentService;
 import org.apache.sling.cms.usergenerated.UserGeneratedContentService.APPROVE_ACTION;
 import org.apache.sling.cms.usergenerated.UserGeneratedContentService.CONTENT_TYPE;
+import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
@@ -48,11 +50,15 @@ public class UserGeneratedContentAction implements FormAction {
 
     private static final Logger log = LoggerFactory.getLogger(UserGeneratedContentAction.class);
 
-    @Reference
-    private NameFilter filter;
+    private final NameFilter filter;
 
-    @Reference
-    private UserGeneratedContentService ugcService;
+    private final UserGeneratedContentService ugcService;
+
+    @Activate
+    public UserGeneratedContentAction(@Reference NameFilter filter, @Reference UserGeneratedContentService ugcService) {
+        this.filter = filter;
+        this.ugcService = ugcService;
+    }
 
     @Override
     public FormActionResult handleForm(Resource actionResource, FormRequest request) throws FormException {
@@ -82,7 +88,7 @@ public class UserGeneratedContentAction implements FormAction {
                     log.warn("Invalid value: {}", v);
                     return null;
                 }
-            }).forEach(v -> {
+            }).filter(Objects::nonNull).forEach(v -> {
                 log.debug("Adding additional property: {}", v);
                 contentProperties.put(v.getLeft(), v.getRight());
             });
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/SelectionHandler.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/SelectionHandler.java
index 955197b..1423d1d 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/SelectionHandler.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/SelectionHandler.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.cms.reference.forms.impl.fields;
 
+import java.lang.annotation.Annotation;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -27,18 +28,42 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.cms.reference.forms.FieldHandler;
 import org.apache.sling.cms.reference.forms.FormException;
+import org.apache.sling.cms.reference.forms.FormUtils;
+import org.apache.sling.cms.reference.impl.SearchServiceImpl.Config;
+import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = FieldHandler.class)
+@Designate(ocd = Config.class)
 public class SelectionHandler implements FieldHandler {
 
+    public static final String DEFAULT_RESOURCE_TYPE = "reference/components/forms/fields/selection";
+
     private static final Logger log = LoggerFactory.getLogger(SelectionHandler.class);
 
+    private final Config config;
+
+    @ObjectClassDefinition(name = "%cms.reference.selection.name", description = "%cms.reference.selection.description", localization = "OSGI-INF/l10n/bundle")
+    public @interface Config {
+
+        @AttributeDefinition(name = "%cms.reference.supportedTypes.name", description = "%cms.reference.supportedTypes.description", defaultValue = {
+                DEFAULT_RESOURCE_TYPE })
+        String[] supportedTypes() default { DEFAULT_RESOURCE_TYPE };
+    }
+
+    @Activate
+    public SelectionHandler(Config config) {
+        this.config = config;
+    }
+
     @Override
     public boolean handles(Resource fieldResource) {
-        return "reference/components/forms/fields/selection".equals(fieldResource.getResourceType());
+        return FormUtils.handles(config.supportedTypes(), fieldResource);
     }
 
     @Override
@@ -72,6 +97,7 @@ public class SelectionHandler implements FieldHandler {
                 formData.put(name, value);
             }
         }
+
     }
 
     private String[] stripBlank(String[] parameterValues) {
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/TextareaHandler.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/TextareaHandler.java
index 0b27346..ba44225 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/TextareaHandler.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/TextareaHandler.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sling.cms.reference.forms.impl.fields;
 
+import java.lang.annotation.Annotation;
 import java.util.Map;
 
 import org.apache.commons.lang3.StringUtils;
@@ -23,19 +24,42 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.cms.reference.forms.FieldHandler;
 import org.apache.sling.cms.reference.forms.FormException;
+import org.apache.sling.cms.reference.forms.FormUtils;
+import org.apache.sling.cms.reference.forms.impl.fields.TextareaHandler.Config;
+import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = FieldHandler.class)
+@Designate(ocd = Config.class)
 public class TextareaHandler implements FieldHandler {
 
+    public static final String DEFAULT_RESOURCE_TYPE = "reference/components/forms/fields/textarea";
+
     private static final Logger log = LoggerFactory.getLogger(TextareaHandler.class);
 
+    private Config config;
+
+    @ObjectClassDefinition(name = "%cms.reference.textarea.name", description = "%cms.reference.textarea.description", localization = "OSGI-INF/l10n/bundle")
+    public @interface Config {
+
+        @AttributeDefinition(name = "%cms.reference.supportedTypes.name", description = "%cms.reference.supportedTypes.description", defaultValue = {
+                DEFAULT_RESOURCE_TYPE })
+        String[] supportedTypes() default { DEFAULT_RESOURCE_TYPE };
+    }
+
+    @Activate
+    public TextareaHandler(Config config) {
+        this.config = config;
+    }
+
     @Override
     public boolean handles(Resource fieldResource) {
-        String resourceType = fieldResource.getResourceType();
-        return "reference/components/forms/fields/textarea".equals(resourceType);
+        return FormUtils.handles(config.supportedTypes(), fieldResource);
     }
 
     @Override
diff --git a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/TextfieldHandler.java b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/TextfieldHandler.java
index 7622a56..d3150a6 100644
--- a/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/TextfieldHandler.java
+++ b/reference/src/main/java/org/apache/sling/cms/reference/forms/impl/fields/TextfieldHandler.java
@@ -30,15 +30,22 @@ import org.apache.sling.api.request.RequestParameter;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.cms.reference.forms.FieldHandler;
 import org.apache.sling.cms.reference.forms.FormException;
+import org.apache.sling.cms.reference.forms.FormUtils;
+import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Component(service = FieldHandler.class)
+@Designate(ocd = TextfieldHandler.Config.class)
 public class TextfieldHandler implements FieldHandler {
 
     private static final Logger log = LoggerFactory.getLogger(TextfieldHandler.class);
     private static final Map<String, String> typePatterns = new HashMap<>();
+    public static final String DEFAULT_RESOURCE_TYPE = "reference/components/forms/fields/textfield";
     static {
         typePatterns.put("date", "\\d{4}-\\d{2}-\\d{2}");
         typePatterns.put("datetime-local", "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}");
@@ -52,10 +59,24 @@ public class TextfieldHandler implements FieldHandler {
         dateFormats.put("datetime-local", "yyyy-MM-ddThh:mm");
     }
 
+    private Config config;
+
+    @ObjectClassDefinition(name = "%cms.reference.textfield.name", description = "%cms.reference.textfield.description", localization = "OSGI-INF/l10n/bundle")
+    public @interface Config {
+
+        @AttributeDefinition(name = "%cms.reference.supportedTypes.name", description = "%cms.reference.supportedTypes.description", defaultValue = {
+                DEFAULT_RESOURCE_TYPE })
+        String[] supportedTypes() default { DEFAULT_RESOURCE_TYPE };
+    }
+
+    @Activate
+    public TextfieldHandler(Config config) {
+        this.config = config;
+    }
+
     @Override
     public boolean handles(Resource fieldResource) {
-        String resourceType = fieldResource.getResourceType();
-        return "reference/components/forms/fields/textfield".equals(resourceType);
+        return FormUtils.handles(config.supportedTypes(), fieldResource);
     }
 
     @Override
diff --git a/reference/src/main/resources/OSGI-INF/l10n/bundle.properties b/reference/src/main/resources/OSGI-INF/l10n/bundle.properties
index 7e4b1fb..a4d182f 100644
--- a/reference/src/main/resources/OSGI-INF/l10n/bundle.properties
+++ b/reference/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -60,18 +60,11 @@ to the SMTP server
 cms.reference.supportedTypes.name=Supported Types
 cms.reference.supportedTypes.description=The resource types supported by this action
 
-cms.reference.createuser.name=Apache Sling CMS - Reference Create User
-cms.reference.createuser.description=Form action for creating a user
+cms.reference.selection.name=Apache Sling CMS - Reference Selection Field
+cms.reference.selection.description=Configuration for the select form field
 
-cms.reference.requestpasswordreset.name=Apache Sling CMS - Reference Password Reset Request
-cms.reference.requestpasswordreset.description=Form action for initiating a password \
-reset request
+cms.reference.textarea.name=Apache Sling CMS - Reference Textarea Field
+cms.reference.selection.description=Configuration for the textarea form field
 
-cms.reference.resetpassword.name=Apache Sling CMS - Reference Password Reset
-cms.reference.requestpasswordreset.description=Form action for resetting a user password
-
-cms.reference.sendemail.name=Apache Sling CMS - Reference Send Email
-cms.reference.requestpasswordreset.description=Form action for sending an email
-
-cms.reference.sendemail.name=Apache Sling CMS - Reference Update Profile
-cms.reference.requestpasswordreset.description=Form action for updating a user profile
\ No newline at end of file
+cms.reference.textfield.name=pache Sling CMS - Reference Text field
+cms.reference.textfield.description=Configuration for the text field
\ No newline at end of file
diff --git a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource.json b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc.json
similarity index 61%
copy from reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource.json
copy to reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc.json
index 2ec03ee..5ce7fe5 100644
--- a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource.json
+++ b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc.json
@@ -1,5 +1,5 @@
 {
     "jcr:primaryType" : "sling:Component",
-    "jcr:title": "Update Resource",
+    "jcr:title": "Delete User Generated Content",
     "componentType": "Form Action"
 }
\ No newline at end of file
diff --git a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/updateresource.jsp b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc/deleteugc.jsp
similarity index 80%
copy from reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/updateresource.jsp
copy to reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc/deleteugc.jsp
index 3389be7..a6a6fea 100644
--- a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/updateresource.jsp
+++ b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc/deleteugc.jsp
@@ -18,13 +18,9 @@
  */ --%>
  <%@include file="/libs/sling-cms/global.jsp"%>
 <c:if test="${cmsEditEnabled == 'true'}">
-    <h3>Update Resource</h3>
+    <h3>Delete User Generated Content</h3>
     <dl>
-        <dt>Allowed Properties</dt>
-        <dd>${sling:encode(fn:join(properties.allowedProperties,','),'HTML')}</dd>
         <dt>Path</dt>
         <dd>${sling:encode(properties.path,'HTML')}</dd>
-        <dt>Service User</dt>
-        <dd>${sling:encode(properties.serviceUser,'HTML')}</dd>
     </dl>
 </c:if>
\ No newline at end of file
diff --git a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc/edit.json b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc/edit.json
new file mode 100644
index 0000000..759c096
--- /dev/null
+++ b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/deleteugc/edit.json
@@ -0,0 +1,14 @@
+{
+    "jcr:primaryType": "nt:unstructured",
+    "sling:resourceType": "sling-cms/components/editor/slingform",
+    "button": "Save",
+    "fields": {
+        "path": {
+            "jcr:primaryType": "nt:unstructured",
+            "sling:resourceType": "sling-cms/components/editor/fields/path",
+            "label": "Path",
+            "name": "path",
+            "required": true
+        }
+    }
+}
\ No newline at end of file
diff --git a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/edit.json b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/edit.json
deleted file mode 100644
index a67511b..0000000
--- a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/edit.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-    "jcr:primaryType": "nt:unstructured",
-    "sling:resourceType": "sling-cms/components/editor/slingform",
-    "button": "Save",
-    "fields": {
-        "allowedProperties": {
-            "jcr:primaryType": "nt:unstructured",
-            "sling:resourceType": "sling-cms/components/editor/fields/repeating",
-            "label": "Allowed Properties",
-            "name": "allowedProperties"
-        },
-        "allowedPropertiesTypeHint": {
-            "jcr:primaryType": "nt:unstructured",
-            "sling:resourceType": "sling-cms/components/editor/fields/hidden",
-            "name": "allowedProperties@TypeHint",
-            "value": "String[]"
-        },
-        "path": {
-            "jcr:primaryType": "nt:unstructured",
-            "sling:resourceType": "sling-cms/components/editor/fields/path",
-            "label": "Path",
-            "name": "path",
-            "required": true
-        },
-        "serviceUser": {
-            "jcr:primaryType": "nt:unstructured",
-            "sling:resourceType": "sling-cms/components/editor/fields/text",
-            "label": "Service User",
-            "name": "serviceUser"
-        }
-    }
-}
\ No newline at end of file
diff --git a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource.json b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc.json
similarity index 61%
rename from reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource.json
rename to reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc.json
index 2ec03ee..e1f4e64 100644
--- a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource.json
+++ b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc.json
@@ -1,5 +1,5 @@
 {
     "jcr:primaryType" : "sling:Component",
-    "jcr:title": "Update Resource",
+    "jcr:title": "Update User Generated Content",
     "componentType": "Form Action"
 }
\ No newline at end of file
diff --git a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc/edit.json b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc/edit.json
new file mode 100644
index 0000000..759c096
--- /dev/null
+++ b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc/edit.json
@@ -0,0 +1,14 @@
+{
+    "jcr:primaryType": "nt:unstructured",
+    "sling:resourceType": "sling-cms/components/editor/slingform",
+    "button": "Save",
+    "fields": {
+        "path": {
+            "jcr:primaryType": "nt:unstructured",
+            "sling:resourceType": "sling-cms/components/editor/fields/path",
+            "label": "Path",
+            "name": "path",
+            "required": true
+        }
+    }
+}
\ No newline at end of file
diff --git a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/updateresource.jsp b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc/updateugc.jsp
similarity index 80%
rename from reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/updateresource.jsp
rename to reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc/updateugc.jsp
index 3389be7..cdbf3fe 100644
--- a/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateresource/updateresource.jsp
+++ b/reference/src/main/resources/jcr_root/apps/reference/components/forms/actions/updateugc/updateugc.jsp
@@ -18,13 +18,9 @@
  */ --%>
  <%@include file="/libs/sling-cms/global.jsp"%>
 <c:if test="${cmsEditEnabled == 'true'}">
-    <h3>Update Resource</h3>
+    <h3>Update User Generated Content</h3>
     <dl>
-        <dt>Allowed Properties</dt>
-        <dd>${sling:encode(fn:join(properties.allowedProperties,','),'HTML')}</dd>
         <dt>Path</dt>
         <dd>${sling:encode(properties.path,'HTML')}</dd>
-        <dt>Service User</dt>
-        <dd>${sling:encode(properties.serviceUser,'HTML')}</dd>
     </dl>
 </c:if>
\ No newline at end of file
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/FormActionResultTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/FormActionResultTest.java
index 9ed86d7..9f7b5d0 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/FormActionResultTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/FormActionResultTest.java
@@ -20,8 +20,6 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import org.apache.sling.cms.reference.forms.FormActionResult;
-import org.apache.sling.cms.reference.forms.FormException;
 import org.junit.Test;
 
 public class FormActionResultTest {
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/FormHandlerTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/FormHandlerTest.java
index f8b80ce..70106fc 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/FormHandlerTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/FormHandlerTest.java
@@ -63,23 +63,47 @@ public class FormHandlerTest {
         context.currentResource(Mockito.mock(Resource.class));
 
         formRequest = new FormRequestImpl(context.request(), null,
-                Arrays.asList(new SelectionHandler(), new TextareaHandler(), new TextfieldHandler()));
+                Arrays.asList(new SelectionHandler(new SelectionHandler.Config() {
 
-        mailService = Mockito.mock(MailService.class);
-        Mockito.when(mailService.getMessageBuilder()).thenReturn(new MockMessageBuilder());
-        final SendEmailAction sendEmailAction = new SendEmailAction(mailService, new SendEmailAction.Config() {
+                    @Override
+                    public Class<? extends Annotation> annotationType() {
+                        return null;
+                    }
 
-            @Override
-            public Class<? extends Annotation> annotationType() {
-                return null;
-            }
+                    @Override
+                    public String[] supportedTypes() {
+                        return new String[] { SelectionHandler.DEFAULT_RESOURCE_TYPE };
+                    }
 
-            @Override
-            public String[] supportedTypes() {
-                return new String[] { SendEmailAction.DEFAULT_RESOURCE_TYPE };
-            }
+                }), new TextareaHandler(new TextareaHandler.Config() {
+
+                    @Override
+                    public Class<? extends Annotation> annotationType() {
+                        return null;
+                    }
+
+                    @Override
+                    public String[] supportedTypes() {
+                        return new String[] { TextareaHandler.DEFAULT_RESOURCE_TYPE };
+                    }
 
-        });
+                }), new TextfieldHandler(new TextfieldHandler.Config() {
+
+                    @Override
+                    public Class<? extends Annotation> annotationType() {
+                        return null;
+                    }
+
+                    @Override
+                    public String[] supportedTypes() {
+                        return new String[] { TextfieldHandler.DEFAULT_RESOURCE_TYPE };
+                    }
+
+                })));
+
+        mailService = Mockito.mock(MailService.class);
+        Mockito.when(mailService.getMessageBuilder()).thenReturn(new MockMessageBuilder());
+        final SendEmailAction sendEmailAction = new SendEmailAction(mailService);
         formHandler = new FormHandler(Arrays.asList(sendEmailAction)) {
             private static final long serialVersionUID = 1L;
 
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/FormRequestImplTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/FormRequestImplTest.java
index e90933f..1c3285c 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/FormRequestImplTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/FormRequestImplTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
+import java.lang.annotation.Annotation;
 import java.util.Arrays;
 
 import com.google.common.collect.ImmutableMap;
@@ -53,7 +54,43 @@ public class FormRequestImplTest {
                         .put("file", new ByteArrayInputStream(new byte[0])).put("datefield", "2019-02-02").build());
 
         formRequest = new FormRequestImpl(context.request(), null,
-                Arrays.asList(new SelectionHandler(), new TextareaHandler(), new TextfieldHandler()));
+                Arrays.asList(new SelectionHandler(new SelectionHandler.Config() {
+
+                    @Override
+                    public Class<? extends Annotation> annotationType() {
+                        return null;
+                    }
+
+                    @Override
+                    public String[] supportedTypes() {
+                        return new String[] { SelectionHandler.DEFAULT_RESOURCE_TYPE };
+                    }
+
+                }), new TextareaHandler(new TextareaHandler.Config() {
+
+                    @Override
+                    public Class<? extends Annotation> annotationType() {
+                        return null;
+                    }
+
+                    @Override
+                    public String[] supportedTypes() {
+                        return new String[] { TextareaHandler.DEFAULT_RESOURCE_TYPE };
+                    }
+
+                }), new TextfieldHandler(new TextfieldHandler.Config() {
+
+                    @Override
+                    public Class<? extends Annotation> annotationType() {
+                        return null;
+                    }
+
+                    @Override
+                    public String[] supportedTypes() {
+                        return new String[] { TextfieldHandler.DEFAULT_RESOURCE_TYPE };
+                    }
+
+                })));
         formRequest.initFields();
     }
 
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/CreateUserActionTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/CreateUserActionTest.java
index 534bf0f..bb767c5 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/CreateUserActionTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/CreateUserActionTest.java
@@ -19,7 +19,6 @@ package org.apache.sling.cms.reference.forms.impl.actions;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import java.lang.annotation.Annotation;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -90,12 +89,12 @@ public class CreateUserActionTest {
         Mockito.when(session.getUserManager()).thenReturn(userManager);
 
         User existingUser = Mockito.mock(User.class);
-        Mockito.when(userManager.getAuthorizable(Mockito.eq("existing@email.com"))).thenReturn(existingUser);
+        Mockito.when(userManager.getAuthorizable("existing@email.com")).thenReturn(existingUser);
         Mockito.when(existingUser.getPath()).thenReturn("/home");
 
         Group agroup = Mockito.mock(Group.class);
         Mockito.when(agroup.isGroup()).thenReturn(true);
-        Mockito.when(userManager.getAuthorizable(Mockito.eq("group1"))).thenReturn(agroup);
+        Mockito.when(userManager.getAuthorizable("group1")).thenReturn(agroup);
 
         Map<String, Object> properties = new HashMap<>();
         properties.put(CreateUserAction.PN_INTERMEDIATE_PATH, "app");
@@ -112,7 +111,7 @@ public class CreateUserActionTest {
     @Test
     public void testHandleForm() throws FormException, RepositoryException {
 
-        CreateUserAction action = new CreateUserAction(factory, null);
+        CreateUserAction action = new CreateUserAction(factory);
 
         Mockito.when(resolver.getUserID()).thenReturn("valid@email.com");
 
@@ -129,7 +128,7 @@ public class CreateUserActionTest {
     @Test
     public void testExistingUser() throws FormException, RepositoryException {
 
-        CreateUserAction action = new CreateUserAction(factory, null);
+        CreateUserAction action = new CreateUserAction(factory);
 
         FormRequest request = new FormRequestImpl(new MockSlingHttpServletRequest(resolver), null, null);
         request.getFormData().put(CreateUserAction.PN_USERNAME, "existing@email.com");
@@ -141,19 +140,9 @@ public class CreateUserActionTest {
 
     @Test
     public void testHandles() throws FormException {
-        CreateUserAction action = new CreateUserAction(factory, new CreateUserAction.Config() {
-            @Override
-            public Class<? extends Annotation> annotationType() {
-                return null;
-            }
-
-            @Override
-            public String[] supportedTypes() {
-                return new String[] { CreateUserAction.DEFAULT_RESOURCE_TYPE };
-            }
-        });
+        CreateUserAction action = new CreateUserAction(factory);
         Resource validResource = Mockito.mock(Resource.class);
-        Mockito.when(validResource.getResourceType()).thenReturn(CreateUserAction.DEFAULT_RESOURCE_TYPE);
+        Mockito.when(validResource.getResourceType()).thenReturn(CreateUserAction.RESOURCE_TYPE);
         assertTrue(action.handles(validResource));
 
         Resource inValidResource = Mockito.mock(Resource.class);
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceActionTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/DeleteUserGeneratedContentActionTest.java
similarity index 56%
copy from reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceActionTest.java
copy to reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/DeleteUserGeneratedContentActionTest.java
index 49315cb..b91c14a 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceActionTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/DeleteUserGeneratedContentActionTest.java
@@ -21,73 +21,41 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.Collections;
 import java.util.HashMap;
 
 import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.api.wrappers.ModifiableValueMapDecorator;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.cms.CMSConstants;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.FormRequest;
 import org.junit.Test;
 import org.mockito.Mockito;
 
-public class UpdateResourceActionTest {
+public class DeleteUserGeneratedContentActionTest {
 
     @Test
     public void testHandles() {
 
-        UpdateResourceAction ur = new UpdateResourceAction(null);
+        DeleteUserGeneratedContentAction action = new DeleteUserGeneratedContentAction(null);
 
         Resource validResource = Mockito.mock(Resource.class);
-        Mockito.when(validResource.getResourceType()).thenReturn("reference/components/forms/actions/updateresource");
-        assertTrue(ur.handles(validResource));
+        Mockito.when(validResource.getResourceType()).thenReturn("reference/components/forms/actions/deleteugc");
+        assertTrue(action.handles(validResource));
 
         Resource invalidResource = Mockito.mock(Resource.class);
         Mockito.when(invalidResource.getResourceType())
                 .thenReturn("reference/components/forms/actions/someotheraction");
-        assertFalse(ur.handles(invalidResource));
-    }
-
-    @Test
-    public void testActionResolver() throws FormException {
-
-        UpdateResourceAction ur = new UpdateResourceAction(null);
-
-        ModifiableValueMap contentData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
-        contentData.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
-        Resource contentResource = Mockito.mock(Resource.class);
-        Mockito.when(contentResource.getValueMap()).thenReturn(contentData);
-        Mockito.when(contentResource.adaptTo(Mockito.any())).thenReturn(contentData);
-
-        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-        Mockito.when(resolver.getResource(Mockito.eq("/content/test"))).thenReturn(contentResource);
-
-        ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
-        actionData.put("allowedProperties", new String[] { "name1", "name3", "name4" });
-        actionData.put("path", "/content/test");
-
-        Resource actionResource = Mockito.mock(Resource.class);
-        Mockito.when(actionResource.getValueMap()).thenReturn(actionData);
-        Mockito.when(actionResource.getResourceResolver()).thenReturn(resolver);
-
-        FormRequest formRequest = Mockito.mock(FormRequest.class);
-        ValueMap formData = new ValueMapDecorator(new HashMap<>());
-        formData.put("name2", "value2");
-        formData.put("name3", "value3");
-        Mockito.when(formRequest.getFormData()).thenReturn(formData);
-
-        ur.handleForm(actionResource, formRequest);
-
-        assertEquals(2, contentResource.getValueMap().keySet().size());
-        assertEquals("value3", contentResource.getValueMap().get("name3"));
-        assertFalse(contentResource.getValueMap().containsKey("name2"));
-
+        assertFalse(action.handles(invalidResource));
     }
 
     @Test
@@ -97,24 +65,14 @@ public class UpdateResourceActionTest {
         ResourceResolverFactory factory = Mockito.mock(ResourceResolverFactory.class);
         Mockito.when(factory.getServiceResourceResolver(Mockito.anyMap())).thenThrow(le);
 
-        UpdateResourceAction ur = new UpdateResourceAction(factory);
-
-        ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
-        actionData.put("allowedProperties", new String[] { "name1", "name3", "name4" });
-        actionData.put("path", "/content/test");
-        actionData.put("serviceUser", "bob");
+        DeleteUserGeneratedContentAction action = new DeleteUserGeneratedContentAction(factory);
 
         Resource actionResource = Mockito.mock(Resource.class);
-        Mockito.when(actionResource.getValueMap()).thenReturn(actionData);
 
         FormRequest formRequest = Mockito.mock(FormRequest.class);
-        ValueMap formData = new ValueMapDecorator(new HashMap<>());
-        formData.put("name2", "value2");
-        formData.put("name3", "value3");
-        Mockito.when(formRequest.getFormData()).thenReturn(formData);
 
         try {
-            ur.handleForm(actionResource, formRequest);
+            action.handleForm(actionResource, formRequest);
             fail();
         } catch (FormException fe) {
             assertEquals(le, fe.getCause());
@@ -122,7 +80,7 @@ public class UpdateResourceActionTest {
     }
 
     @Test
-    public void testServiceUser() throws FormException, LoginException {
+    public void testHandleForm() throws FormException, LoginException, PersistenceException {
 
         ModifiableValueMap contentData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
         contentData.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
@@ -130,33 +88,66 @@ public class UpdateResourceActionTest {
         Mockito.when(contentResource.getValueMap()).thenReturn(contentData);
         Mockito.when(contentResource.adaptTo(Mockito.any())).thenReturn(contentData);
 
+        Resource ugcResource = Mockito.mock(Resource.class);
+        Mockito.when(ugcResource.getResourceType()).thenReturn(CMSConstants.NT_UGC);
+        Mockito.when(ugcResource.getValueMap())
+                .thenReturn(new ValueMapDecorator(Collections.singletonMap("user", "auser")));
+        Mockito.when(contentResource.getParent()).thenReturn(ugcResource);
+
         ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-        Mockito.when(resolver.getResource(Mockito.eq("/content/test"))).thenReturn(contentResource);
+        Mockito.when(resolver.getUserID()).thenReturn("auser");
+        SlingHttpServletRequest request = Mockito.mock(SlingHttpServletRequest.class);
+        Mockito.when(request.getResourceResolver()).thenReturn(resolver);
+        Mockito.when(resolver.getResource("/etc/usergenerated/test")).thenReturn(contentResource);
 
         ResourceResolverFactory factory = Mockito.mock(ResourceResolverFactory.class);
         Mockito.when(factory.getServiceResourceResolver(Mockito.anyMap())).thenReturn(resolver);
 
-        UpdateResourceAction ur = new UpdateResourceAction(factory);
+        DeleteUserGeneratedContentAction action = new DeleteUserGeneratedContentAction(factory);
 
         ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
-        actionData.put("allowedProperties", new String[] { "name1", "name3", "name4" });
-        actionData.put("path", "/content/test");
-        actionData.put("serviceUser", "bob");
+        actionData.put("path", "/etc/usergenerated/test");
 
         Resource actionResource = Mockito.mock(Resource.class);
         Mockito.when(actionResource.getValueMap()).thenReturn(actionData);
 
         FormRequest formRequest = Mockito.mock(FormRequest.class);
-        ValueMap formData = new ValueMapDecorator(new HashMap<>());
-        formData.put("name2", "value2");
-        formData.put("name3", "value3");
-        Mockito.when(formRequest.getFormData()).thenReturn(formData);
+        Mockito.when(formRequest.getFormData()).thenReturn(new ValueMapDecorator(Collections.emptyMap()));
+        Mockito.when(formRequest.getOriginalRequest()).thenReturn(request);
+
+        action.handleForm(actionResource, formRequest);
+
+        Mockito.verify(resolver).delete(ugcResource);
+
+    }
+
+    @Test
+    public void testNoParent() throws FormException, LoginException {
+
+        Resource contentResource = Mockito.mock(Resource.class);
+
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        Mockito.when(resolver.getResource("/etc/usergenerated/test")).thenReturn(contentResource);
+
+        ResourceResolverFactory factory = Mockito.mock(ResourceResolverFactory.class);
+        Mockito.when(factory.getServiceResourceResolver(Mockito.anyMap())).thenReturn(resolver);
+
+        DeleteUserGeneratedContentAction action = new DeleteUserGeneratedContentAction(factory);
 
-        ur.handleForm(actionResource, formRequest);
+        ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
+        actionData.put("path", "/etc/usergenerated/test");
+
+        Resource actionResource = Mockito.mock(Resource.class);
+        Mockito.when(actionResource.getValueMap()).thenReturn(actionData);
 
-        assertEquals(2, contentResource.getValueMap().keySet().size());
-        assertEquals("value3", contentResource.getValueMap().get("name3"));
-        assertFalse(contentResource.getValueMap().containsKey("name2"));
+        FormRequest formRequest = Mockito.mock(FormRequest.class);
+        Mockito.when(formRequest.getFormData()).thenReturn(new ValueMapDecorator(Collections.emptyMap()));
 
+        try {
+            action.handleForm(actionResource, formRequest);
+            fail();
+        } catch (FormException fe) {
+            assertEquals("Failed to find UGC Parent", fe.getMessage());
+        }
     }
 }
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/RequestPasswordResetActionTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/RequestPasswordResetActionTest.java
index 78ee756..cd12d85 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/RequestPasswordResetActionTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/RequestPasswordResetActionTest.java
@@ -19,7 +19,6 @@ package org.apache.sling.cms.reference.forms.impl.actions;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import java.lang.annotation.Annotation;
 import java.util.Collections;
 
 import javax.jcr.AccessDeniedException;
@@ -40,7 +39,6 @@ import org.apache.sling.cms.reference.forms.FormActionResult;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.FormRequest;
 import org.apache.sling.cms.reference.forms.impl.FormRequestImpl;
-import org.apache.sling.cms.reference.forms.impl.actions.RequestPasswordResetAction.Config;
 import org.apache.sling.servlethelpers.MockSlingHttpServletRequest;
 import org.apache.sling.testing.resourceresolver.MockResource;
 import org.junit.Before;
@@ -84,14 +82,14 @@ public class RequestPasswordResetActionTest {
         UserManager userManager = Mockito.mock(UserManager.class);
         Mockito.when(session.getUserManager()).thenReturn(userManager);
 
-        Mockito.when(userManager.getAuthorizable(Mockito.eq("test@email.com"))).thenReturn(Mockito.mock(User.class));
+        Mockito.when(userManager.getAuthorizable("test@email.com")).thenReturn(Mockito.mock(User.class));
 
     }
 
     @Test
     public void testHandleForm() throws FormException {
 
-        RequestPasswordResetAction action = new RequestPasswordResetAction(factory, null);
+        RequestPasswordResetAction action = new RequestPasswordResetAction(factory);
 
         FormRequest request = new FormRequestImpl(new MockSlingHttpServletRequest(resolver), null, null);
         request.getFormData().put("email", "test@email.com");
@@ -107,7 +105,7 @@ public class RequestPasswordResetActionTest {
     @Test
     public void testNoUser() throws FormException {
 
-        RequestPasswordResetAction action = new RequestPasswordResetAction(factory, null);
+        RequestPasswordResetAction action = new RequestPasswordResetAction(factory);
 
         FormRequest request = new FormRequestImpl(new MockSlingHttpServletRequest(resolver), null, null);
         request.getFormData().put("email", "test1@email.com");
@@ -122,20 +120,10 @@ public class RequestPasswordResetActionTest {
 
     @Test
     public void testHandles() throws FormException {
-        Config config = new Config() {
-            @Override
-            public Class<? extends Annotation> annotationType() {
-                return null;
-            }
 
-            @Override
-            public String[] supportedTypes() {
-                return new String[] { RequestPasswordResetAction.DEFAULT_RESOURCE_TYPE };
-            }
-        };
-        RequestPasswordResetAction action = new RequestPasswordResetAction(null, config);
+        RequestPasswordResetAction action = new RequestPasswordResetAction(null);
         Resource validResource = Mockito.mock(Resource.class);
-        Mockito.when(validResource.getResourceType()).thenReturn(RequestPasswordResetAction.DEFAULT_RESOURCE_TYPE);
+        Mockito.when(validResource.getResourceType()).thenReturn(RequestPasswordResetAction.RESOURCE_TYPE);
         assertTrue(action.handles(validResource));
 
         Resource inValidResource = Mockito.mock(Resource.class);
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/ResetPasswordActionTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/ResetPasswordActionTest.java
index 5e8a66f..9db49ca 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/ResetPasswordActionTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/ResetPasswordActionTest.java
@@ -19,11 +19,8 @@ package org.apache.sling.cms.reference.forms.impl.actions;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import java.lang.annotation.Annotation;
 import java.util.Calendar;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.RepositoryException;
@@ -97,12 +94,12 @@ public class ResetPasswordActionTest {
         cal.add(Calendar.HOUR, 24);
         Mockito.when(validUser.getProperty(FormConstants.PN_RESETTIMEOUT))
                 .thenReturn(new Value[] { new DateValue(cal) });
-        Mockito.when(userManager.getAuthorizable(Mockito.eq("valid@email.com"))).thenReturn(validUser);
+        Mockito.when(userManager.getAuthorizable("valid@email.com")).thenReturn(validUser);
 
         User invalidUser = Mockito.mock(User.class);
         Mockito.when(invalidUser.getProperty(FormConstants.PN_RESETTOKEN))
                 .thenReturn(new Value[] { new StringValue("456") });
-        Mockito.when(userManager.getAuthorizable(Mockito.eq("invalid@email.com"))).thenReturn(invalidUser);
+        Mockito.when(userManager.getAuthorizable("invalid@email.com")).thenReturn(invalidUser);
 
         User expiredUser = Mockito.mock(User.class);
         Mockito.when(expiredUser.getProperty(FormConstants.PN_RESETTOKEN))
@@ -111,14 +108,14 @@ public class ResetPasswordActionTest {
         cal.add(Calendar.HOUR, -24);
         Mockito.when(expiredUser.getProperty(FormConstants.PN_RESETTIMEOUT))
                 .thenReturn(new Value[] { new DateValue(cal) });
-        Mockito.when(userManager.getAuthorizable(Mockito.eq("expired@email.com"))).thenReturn(expiredUser);
+        Mockito.when(userManager.getAuthorizable("expired@email.com")).thenReturn(expiredUser);
 
     }
 
     @Test
     public void testHandleForm() throws FormException {
 
-        ResetPasswordAction action = new ResetPasswordAction(factory, null);
+        ResetPasswordAction action = new ResetPasswordAction(factory);
 
         FormRequest request = new FormRequestImpl(new MockSlingHttpServletRequest(resolver), null, null);
         request.getFormData().put("email", "valid@email.com");
@@ -135,7 +132,7 @@ public class ResetPasswordActionTest {
 
     public FormActionResult doReset(String email) throws FormException {
 
-        ResetPasswordAction action = new ResetPasswordAction(factory, null);
+        ResetPasswordAction action = new ResetPasswordAction(factory);
 
         FormRequest request = new FormRequestImpl(new MockSlingHttpServletRequest(resolver), null, null);
         request.getFormData().put("email", email);
@@ -158,19 +155,9 @@ public class ResetPasswordActionTest {
 
     @Test
     public void testHandles() throws FormException {
-        ResetPasswordAction action = new ResetPasswordAction(null, new ResetPasswordAction.Config() {
-            @Override
-            public Class<? extends Annotation> annotationType() {
-                return null;
-            }
-
-            @Override
-            public String[] supportedTypes() {
-                return new String[] { ResetPasswordAction.DEFAULT_RESOURCE_TYPE };
-            }
-        });
+        ResetPasswordAction action = new ResetPasswordAction(null);
         Resource validResource = Mockito.mock(Resource.class);
-        Mockito.when(validResource.getResourceType()).thenReturn(ResetPasswordAction.DEFAULT_RESOURCE_TYPE);
+        Mockito.when(validResource.getResourceType()).thenReturn(ResetPasswordAction.RESOURCE_TYPE);
         assertTrue(action.handles(validResource));
 
         Resource inValidResource = Mockito.mock(Resource.class);
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/SendEmailActionTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/SendEmailActionTest.java
index 815dd5e..66150e7 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/SendEmailActionTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/SendEmailActionTest.java
@@ -19,8 +19,6 @@ package org.apache.sling.cms.reference.forms.impl.actions;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import java.lang.annotation.Annotation;
-
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.cms.reference.forms.FormActionResult;
 import org.apache.sling.cms.reference.forms.FormException;
@@ -51,18 +49,7 @@ public class SendEmailActionTest {
         resolver = context.resourceResolver();
         mailService = Mockito.mock(MailService.class);
         Mockito.when(mailService.getMessageBuilder()).thenReturn(new MockMessageBuilder());
-        action = new SendEmailAction(mailService, new SendEmailAction.Config() {
-
-            @Override
-            public Class<? extends Annotation> annotationType() {
-                return null;
-            }
-
-            @Override
-            public String[] supportedTypes() {
-                return new String[] { SendEmailAction.DEFAULT_RESOURCE_TYPE };
-            }
-        });
+        action = new SendEmailAction(mailService);
     }
 
     @Test
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateProfileActionTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateProfileActionTest.java
index 8dd730f..af8d167 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateProfileActionTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateProfileActionTest.java
@@ -19,7 +19,6 @@ package org.apache.sling.cms.reference.forms.impl.actions;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import java.lang.annotation.Annotation;
 import java.util.Calendar;
 import java.util.Collections;
 
@@ -89,14 +88,14 @@ public class UpdateProfileActionTest {
         Mockito.when(session.getUserManager()).thenReturn(userManager);
 
         validUser = Mockito.mock(User.class);
-        Mockito.when(userManager.getAuthorizable(Mockito.eq("valid@email.com"))).thenReturn(validUser);
+        Mockito.when(userManager.getAuthorizable("valid@email.com")).thenReturn(validUser);
 
     }
 
     @Test
     public void testHandleForm() throws FormException, RepositoryException {
 
-        UpdateProfileAction action = new UpdateProfileAction(null);
+        UpdateProfileAction action = new UpdateProfileAction();
 
         Mockito.when(resolver.getUserID()).thenReturn("valid@email.com");
 
@@ -119,7 +118,7 @@ public class UpdateProfileActionTest {
     @Test
     public void testMissingUser() throws FormException, RepositoryException {
 
-        UpdateProfileAction action = new UpdateProfileAction(null);
+        UpdateProfileAction action = new UpdateProfileAction();
 
         Mockito.when(resolver.getUserID()).thenReturn("invalid@email.com");
 
@@ -136,7 +135,7 @@ public class UpdateProfileActionTest {
     @Test
     public void testError() throws FormException, RepositoryException, PersistenceException {
 
-        UpdateProfileAction action = new UpdateProfileAction(null);
+        UpdateProfileAction action = new UpdateProfileAction();
 
         Mockito.when(resolver.getUserID()).thenReturn("valid@email.com");
         Mockito.doThrow(new PersistenceException("I'm a sad panda")).when(resolver).commit();
@@ -153,19 +152,9 @@ public class UpdateProfileActionTest {
 
     @Test
     public void testHandles() throws FormException {
-        UpdateProfileAction action = new UpdateProfileAction(new UpdateProfileAction.Config() {
-            @Override
-            public Class<? extends Annotation> annotationType() {
-                return null;
-            }
-
-            @Override
-            public String[] supportedTypes() {
-                return new String[] { UpdateProfileAction.DEFAULT_RESOURCE_TYPE };
-            }
-        });
+        UpdateProfileAction action = new UpdateProfileAction();
         Resource validResource = Mockito.mock(Resource.class);
-        Mockito.when(validResource.getResourceType()).thenReturn(UpdateProfileAction.DEFAULT_RESOURCE_TYPE);
+        Mockito.when(validResource.getResourceType()).thenReturn(UpdateProfileAction.RESOURCE_TYPE);
         assertTrue(action.handles(validResource));
 
         Resource inValidResource = Mockito.mock(Resource.class);
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceActionTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateUserGeneratedContentActionTest.java
similarity index 72%
rename from reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceActionTest.java
rename to reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateUserGeneratedContentActionTest.java
index 49315cb..e2d59fb 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateResourceActionTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UpdateUserGeneratedContentActionTest.java
@@ -21,9 +21,11 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.Collections;
 import java.util.HashMap;
 
 import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ModifiableValueMap;
 import org.apache.sling.api.resource.Resource;
@@ -32,20 +34,21 @@ import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.api.wrappers.ModifiableValueMapDecorator;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.cms.CMSConstants;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.FormRequest;
 import org.junit.Test;
 import org.mockito.Mockito;
 
-public class UpdateResourceActionTest {
+public class UpdateUserGeneratedContentActionTest {
 
     @Test
     public void testHandles() {
 
-        UpdateResourceAction ur = new UpdateResourceAction(null);
+        UpdateUserGeneratedContentAction ur = new UpdateUserGeneratedContentAction(null);
 
         Resource validResource = Mockito.mock(Resource.class);
-        Mockito.when(validResource.getResourceType()).thenReturn("reference/components/forms/actions/updateresource");
+        Mockito.when(validResource.getResourceType()).thenReturn("reference/components/forms/actions/updateugc");
         assertTrue(ur.handles(validResource));
 
         Resource invalidResource = Mockito.mock(Resource.class);
@@ -55,49 +58,13 @@ public class UpdateResourceActionTest {
     }
 
     @Test
-    public void testActionResolver() throws FormException {
-
-        UpdateResourceAction ur = new UpdateResourceAction(null);
-
-        ModifiableValueMap contentData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
-        contentData.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
-        Resource contentResource = Mockito.mock(Resource.class);
-        Mockito.when(contentResource.getValueMap()).thenReturn(contentData);
-        Mockito.when(contentResource.adaptTo(Mockito.any())).thenReturn(contentData);
-
-        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-        Mockito.when(resolver.getResource(Mockito.eq("/content/test"))).thenReturn(contentResource);
-
-        ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
-        actionData.put("allowedProperties", new String[] { "name1", "name3", "name4" });
-        actionData.put("path", "/content/test");
-
-        Resource actionResource = Mockito.mock(Resource.class);
-        Mockito.when(actionResource.getValueMap()).thenReturn(actionData);
-        Mockito.when(actionResource.getResourceResolver()).thenReturn(resolver);
-
-        FormRequest formRequest = Mockito.mock(FormRequest.class);
-        ValueMap formData = new ValueMapDecorator(new HashMap<>());
-        formData.put("name2", "value2");
-        formData.put("name3", "value3");
-        Mockito.when(formRequest.getFormData()).thenReturn(formData);
-
-        ur.handleForm(actionResource, formRequest);
-
-        assertEquals(2, contentResource.getValueMap().keySet().size());
-        assertEquals("value3", contentResource.getValueMap().get("name3"));
-        assertFalse(contentResource.getValueMap().containsKey("name2"));
-
-    }
-
-    @Test
     public void testInvalidServiceUser() throws FormException, LoginException {
 
         LoginException le = new LoginException();
         ResourceResolverFactory factory = Mockito.mock(ResourceResolverFactory.class);
         Mockito.when(factory.getServiceResourceResolver(Mockito.anyMap())).thenThrow(le);
 
-        UpdateResourceAction ur = new UpdateResourceAction(factory);
+        UpdateUserGeneratedContentAction ur = new UpdateUserGeneratedContentAction(factory);
 
         ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
         actionData.put("allowedProperties", new String[] { "name1", "name3", "name4" });
@@ -122,7 +89,7 @@ public class UpdateResourceActionTest {
     }
 
     @Test
-    public void testServiceUser() throws FormException, LoginException {
+    public void testHandleForm() throws FormException, LoginException {
 
         ModifiableValueMap contentData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
         contentData.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
@@ -130,13 +97,22 @@ public class UpdateResourceActionTest {
         Mockito.when(contentResource.getValueMap()).thenReturn(contentData);
         Mockito.when(contentResource.adaptTo(Mockito.any())).thenReturn(contentData);
 
+        Resource ugcResource = Mockito.mock(Resource.class);
+        Mockito.when(ugcResource.getResourceType()).thenReturn(CMSConstants.NT_UGC);
+        Mockito.when(ugcResource.getValueMap())
+                .thenReturn(new ValueMapDecorator(Collections.singletonMap("user", "auser")));
+        Mockito.when(contentResource.getParent()).thenReturn(ugcResource);
+
         ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-        Mockito.when(resolver.getResource(Mockito.eq("/content/test"))).thenReturn(contentResource);
+        Mockito.when(resolver.getUserID()).thenReturn("auser");
+        SlingHttpServletRequest request = Mockito.mock(SlingHttpServletRequest.class);
+        Mockito.when(request.getResourceResolver()).thenReturn(resolver);
+        Mockito.when(resolver.getResource("/content/test")).thenReturn(contentResource);
 
         ResourceResolverFactory factory = Mockito.mock(ResourceResolverFactory.class);
         Mockito.when(factory.getServiceResourceResolver(Mockito.anyMap())).thenReturn(resolver);
 
-        UpdateResourceAction ur = new UpdateResourceAction(factory);
+        UpdateUserGeneratedContentAction ur = new UpdateUserGeneratedContentAction(factory);
 
         ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
         actionData.put("allowedProperties", new String[] { "name1", "name3", "name4" });
@@ -147,6 +123,8 @@ public class UpdateResourceActionTest {
         Mockito.when(actionResource.getValueMap()).thenReturn(actionData);
 
         FormRequest formRequest = Mockito.mock(FormRequest.class);
+        Mockito.when(formRequest.getOriginalRequest()).thenReturn(request);
+
         ValueMap formData = new ValueMapDecorator(new HashMap<>());
         formData.put("name2", "value2");
         formData.put("name3", "value3");
@@ -154,9 +132,41 @@ public class UpdateResourceActionTest {
 
         ur.handleForm(actionResource, formRequest);
 
-        assertEquals(2, contentResource.getValueMap().keySet().size());
+        assertEquals(3, contentResource.getValueMap().keySet().size());
         assertEquals("value3", contentResource.getValueMap().get("name3"));
-        assertFalse(contentResource.getValueMap().containsKey("name2"));
 
     }
+
+    @Test
+    public void testNoParent() throws FormException, LoginException {
+
+        Resource contentResource = Mockito.mock(Resource.class);
+
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        Mockito.when(resolver.getResource("/etc/usergenerated/test")).thenReturn(contentResource);
+
+        ResourceResolverFactory factory = Mockito.mock(ResourceResolverFactory.class);
+        Mockito.when(factory.getServiceResourceResolver(Mockito.anyMap())).thenReturn(resolver);
+
+        UpdateUserGeneratedContentAction ur = new UpdateUserGeneratedContentAction(factory);
+
+        ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
+        actionData.put("path", "/etc/usergenerated/test");
+
+        Resource actionResource = Mockito.mock(Resource.class);
+        Mockito.when(actionResource.getValueMap()).thenReturn(actionData);
+
+        FormRequest formRequest = Mockito.mock(FormRequest.class);
+        ValueMap formData = new ValueMapDecorator(new HashMap<>());
+        formData.put("name2", "value2");
+        formData.put("name3", "value3");
+        Mockito.when(formRequest.getFormData()).thenReturn(formData);
+
+        try {
+            ur.handleForm(actionResource, formRequest);
+            fail();
+        } catch (FormException fe) {
+            assertEquals("Failed to find UGC Parent", fe.getMessage());
+        }
+    }
 }
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UserGeneratedContentActionTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UserGeneratedContentActionTest.java
new file mode 100644
index 0000000..065d19c
--- /dev/null
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/actions/UserGeneratedContentActionTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.sling.cms.reference.forms.impl.actions;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ModifiableValueMapDecorator;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.cms.NameFilter;
+import org.apache.sling.cms.reference.forms.FormException;
+import org.apache.sling.cms.reference.forms.FormRequest;
+import org.apache.sling.cms.usergenerated.UserGeneratedContentService;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class UserGeneratedContentActionTest {
+
+    @Test
+    public void testHandles() {
+
+        NameFilter filter = Mockito.mock(NameFilter.class);
+        UserGeneratedContentService ugcService = Mockito.mock(UserGeneratedContentService.class);
+
+        UserGeneratedContentAction ur = new UserGeneratedContentAction(filter, ugcService);
+
+        Resource validResource = Mockito.mock(Resource.class);
+        Mockito.when(validResource.getResourceType())
+                .thenReturn("reference/components/forms/actions/usergeneratedcontent");
+        assertTrue(ur.handles(validResource));
+
+        Resource invalidResource = Mockito.mock(Resource.class);
+        Mockito.when(invalidResource.getResourceType())
+                .thenReturn("reference/components/forms/actions/someotheraction");
+        assertFalse(ur.handles(invalidResource));
+    }
+
+    @Test
+    public void testActionResolver() throws FormException, PersistenceException {
+
+        NameFilter filter = Mockito.mock(NameFilter.class);
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+
+        Resource container = Mockito.mock(Resource.class);
+        Mockito.when(container.getResourceResolver()).thenReturn(resolver);
+
+        UserGeneratedContentService ugcService = Mockito.mock(UserGeneratedContentService.class);
+        Mockito.when(ugcService.createUGCContainer(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
+                .thenReturn(container);
+
+        UserGeneratedContentAction ur = new UserGeneratedContentAction(filter, ugcService);
+
+        ValueMap actionData = new ModifiableValueMapDecorator(new HashMap<String, Object>());
+        actionData.put("additionalProperties", new String[] { "name1=value1", "name3=vale2", "name4" });
+        actionData.put("path", "/content/test");
+
+        Resource actionResource = Mockito.mock(Resource.class);
+        Mockito.when(actionResource.getValueMap()).thenReturn(actionData);
+        Mockito.when(actionResource.getResourceResolver()).thenReturn(resolver);
+
+        FormRequest formRequest = Mockito.mock(FormRequest.class);
+        ValueMap formData = new ValueMapDecorator(new HashMap<>());
+        formData.put("name2", "value2");
+        formData.put("name3", "value3");
+        Mockito.when(formRequest.getFormData()).thenReturn(formData);
+        ur.handleForm(actionResource, formRequest);
+        assertTrue(true);
+
+    }
+}
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/HoneypotHandlerTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/HoneypotHandlerTest.java
index 7deb692..260b315 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/HoneypotHandlerTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/HoneypotHandlerTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sling.cms.reference.forms.impl.fields;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -25,8 +24,6 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import com.google.common.collect.ImmutableMap;
-
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.cms.reference.forms.FormException;
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/SelectionHandlerTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/SelectionHandlerTest.java
index 33baf32..7f6eaa3 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/SelectionHandlerTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/SelectionHandlerTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.lang.annotation.Annotation;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -30,6 +31,7 @@ import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.impl.SlingContextHelper;
+import org.apache.sling.cms.reference.forms.impl.fields.SelectionHandler.Config;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.junit.Before;
 import org.junit.Rule;
@@ -48,7 +50,20 @@ public class SelectionHandlerTest {
         context.request().setResource(context.resourceResolver().getResource("/form/jcr:content/container/form"));
 
         resolver = context.resourceResolver();
-        handler = new SelectionHandler();
+        handler = new SelectionHandler(new Config() {
+
+            @Override
+            public Class<? extends Annotation> annotationType() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public String[] supportedTypes() {
+                return new String[] { SelectionHandler.DEFAULT_RESOURCE_TYPE };
+            }
+
+        });
     }
 
     @Test
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/TextareaHandlerTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/TextareaHandlerTest.java
index 3fb6f73..6b64af5 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/TextareaHandlerTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/TextareaHandlerTest.java
@@ -21,20 +21,22 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.lang.annotation.Annotation;
 import java.util.HashMap;
 import java.util.Map;
 
+import com.google.common.collect.ImmutableMap;
+
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.impl.SlingContextHelper;
+import org.apache.sling.cms.reference.forms.impl.fields.TextareaHandler.Config;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
-import com.google.common.collect.ImmutableMap;
-
 public class TextareaHandlerTest {
 
     @Rule
@@ -48,7 +50,19 @@ public class TextareaHandlerTest {
         context.request().setResource(context.resourceResolver().getResource("/form/jcr:content/container/form"));
 
         resolver = context.resourceResolver();
-        handler = new TextareaHandler();
+        handler = new TextareaHandler(new Config() {
+
+            @Override
+            public Class<? extends Annotation> annotationType() {
+                return null;
+            }
+
+            @Override
+            public String[] supportedTypes() {
+                return new String[] { TextareaHandler.DEFAULT_RESOURCE_TYPE };
+            }
+
+        });
     }
 
     @Test
diff --git a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/TextfieldHandlerTest.java b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/TextfieldHandlerTest.java
index 855127f..9d85b95 100644
--- a/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/TextfieldHandlerTest.java
+++ b/reference/src/test/java/org/apache/sling/cms/reference/forms/impl/fields/TextfieldHandlerTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.ByteArrayInputStream;
+import java.lang.annotation.Annotation;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.HashMap;
@@ -34,6 +35,7 @@ import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.cms.reference.forms.FormException;
 import org.apache.sling.cms.reference.forms.impl.SlingContextHelper;
+import org.apache.sling.cms.reference.forms.impl.fields.TextfieldHandler.Config;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.junit.Before;
 import org.junit.Rule;
@@ -52,7 +54,19 @@ public class TextfieldHandlerTest {
         context.request().setResource(context.resourceResolver().getResource("/form/jcr:content/container/form"));
 
         resolver = context.resourceResolver();
-        handler = new TextfieldHandler();
+        handler = new TextfieldHandler(new Config() {
+
+            @Override
+            public Class<? extends Annotation> annotationType() {
+                return null;
+            }
+
+            @Override
+            public String[] supportedTypes() {
+                return new String[] { TextfieldHandler.DEFAULT_RESOURCE_TYPE };
+            }
+
+        });
     }
 
     @Test