docs: public PortletDefinitionForm savePortletRegistration(
              IPerson publisher, PortletDefinitionForm form) throws Exception {
          logger.trace("In savePortletRegistration() - for: {}", form.getPortletName());
          /* TODO:  Service-Layer Security Reboot (great need of refactoring with a community-approved plan in place) */
  
          // User must have the selected lifecycle permission over AT LEAST ONE
          // category in which this portlet resides.  (This is the same check that
          // is made when the user enters the lifecycle-selection step in the wizard.)
          if (!hasLifecyclePermission(publisher, form.getLifecycleState(), form.getCategories())) {
              logger.warn(
                      "User '"
                              + publisher.getUserName()
                              + "' attempted to save the following portlet without the selected MANAGE permission:  "
                              + form);
              throw new SecurityException("Not Authorized");
          }
  
          if (!form.isNew()) {
              // User must have the previous lifecycle permission
              // in AT LEAST ONE previous category as well
              IPortletDefinition def =
                      this.portletDefinitionRegistry.getPortletDefinition(form.getId());
              Set<PortletCategory> categories = portletCategoryRegistry.getParentCategories(def);
              SortedSet<JsonEntityBean> categoryBeans = new TreeSet<>();
              for (PortletCategory cat : categories) {
                  categoryBeans.add(new JsonEntityBean(cat));
              }
              if (!hasLifecyclePermission(publisher, def.getLifecycleState(), categoryBeans)) {
                  logger.warn(
                          "User '"
                                  + publisher.getUserName()
                                  + "' attempted to save the following portlet without the previous MANAGE permission:  "
                                  + form);
                  throw new SecurityException("Not Authorized");
              }
          }
  
          if (form.isNew()
                  || portletDefinitionRegistry.getPortletDefinition(form.getId()).getType().getId()
                          != form.getTypeId()) {
              // User must have access to the selected CPD if s/he selected it in this interaction
              final int selectedTypeId = form.getTypeId();
              final PortletPublishingDefinition cpd =
                      portletPublishingDefinitionDao.getChannelPublishingDefinition(selectedTypeId);
              final Map<IPortletType, PortletPublishingDefinition> allowableCpds =
                      this.getAllowableChannelPublishingDefinitions(publisher);
              if (!allowableCpds.containsValue(cpd)) {
                  logger.warn(
                          "User '"
                                  + publisher.getUserName()
                                  + "' attempted to administer the following portlet without the selected "
                                  + IPermission.PORTLET_MANAGER_SELECT_PORTLET_TYPE
                                  + " permission:  "
                                  + form);
                  throw new SecurityException("Not Authorized");
              }
          }
  
          // create the principal array from the form's principal list -- only principals with
          // permissions
          final Set<IGroupMember> subscribePrincipalSet = new HashSet<>(form.getPrincipals().size());
          final Set<IGroupMember> browsePrincipalSet = new HashSet<>(form.getPrincipals().size());
          final Set<IGroupMember> configurePrincipalSet = new HashSet<>(form.getPrincipals().size());
          for (JsonEntityBean bean : form.getPrincipals()) {
              final String subscribePerm =
                      bean.getTypeAndIdHash() + "_" + IPermission.PORTLET_SUBSCRIBER_ACTIVITY;
              final String browsePerm =
                      bean.getTypeAndIdHash() + "_" + IPermission.PORTLET_BROWSE_ACTIVITY;
              final String configurePerm =
                      bean.getTypeAndIdHash() + "_" + IPermission.PORTLET_MODE_CONFIG;
              final EntityEnum entityEnum = bean.getEntityType();
              final IGroupMember principal =
                      entityEnum.isGroup()
                              ? (GroupService.findGroup(bean.getId()))
                              : (GroupService.getGroupMember(bean.getId(), entityEnum.getClazz()));
              if (form.getPermissions().contains(subscribePerm)) {
                  logger.info(
                          "In savePortletRegistration() - Found a subscribePerm for principal: {}",
                          principal);
                  subscribePrincipalSet.add(principal);
              }
              if (form.getPermissions().contains(browsePerm)) {
                  logger.info(
                          "In savePortletRegistration() - Found a browsePerm for principal: {}",
                          principal);
                  browsePrincipalSet.add(principal);
              }
              if (form.getPermissions().contains(configurePerm)) {
                  logger.info(
                          "In savePortletRegistration() - Found a configurePerm for principal: {}",
                          principal);
                  configurePrincipalSet.add(principal);
              }
          }
  
          // create the category list from the form's category bean list
          List<PortletCategory> categories = new ArrayList<>();
          for (JsonEntityBean category : form.getCategories()) {
              String id = category.getId();
              String iCatID = id.startsWith("cat") ? id.substring(3) : id;
              categories.add(portletCategoryRegistry.getPortletCategory(iCatID));
          }
  
          final IPortletType portletType = portletTypeRegistry.getPortletType(form.getTypeId());
          if (portletType == null) {
              throw new IllegalArgumentException("No IPortletType exists for ID " + form.getTypeId());
          }
  
          IPortletDefinition portletDef;
          if (form.getId() == null) {
              portletDef =
                      new PortletDefinitionImpl(
                              portletType,
                              form.getFname(),
                              form.getName(),
                              form.getTitle(),
                              form.getApplicationId(),
                              form.getPortletName(),
                              form.isFramework());
          } else {
              portletDef = portletDefinitionRegistry.getPortletDefinition(form.getId());
              portletDef.setType(portletType);
              portletDef.setFName(form.getFname());
              portletDef.setName(form.getName());
              portletDef.setTitle(form.getTitle());
              portletDef.getPortletDescriptorKey().setWebAppName(form.getApplicationId());
              portletDef.getPortletDescriptorKey().setPortletName(form.getPortletName());
              portletDef.getPortletDescriptorKey().setFrameworkPortlet(form.isFramework());
          }
          portletDef.setDescription(form.getDescription());
          portletDef.setTimeout(form.getTimeout());
  
          // Make parameters (NB:  these are different from preferences) in the
          // portletDef reflect the state of the form, in case any have changed.
          for (String key : form.getParameters().keySet()) {
              String value = form.getParameters().get(key).getValue();
              if (!StringUtils.isBlank(value)) {
                  portletDef.addParameter(key, value);
              }
          }
          portletDef.addParameter(
                  IPortletDefinition.EDITABLE_PARAM, Boolean.toString(form.isEditable()));
          portletDef.addParameter(
                  IPortletDefinition.CONFIGURABLE_PARAM, Boolean.toString(form.isConfigurable()));
          portletDef.addParameter(
                  IPortletDefinition.HAS_HELP_PARAM, Boolean.toString(form.isHasHelp()));
          portletDef.addParameter(
                  IPortletDefinition.HAS_ABOUT_PARAM, Boolean.toString(form.isHasAbout()));
  
          // Now add portlet preferences
          List<IPortletPreference> preferenceList = new ArrayList<>();
          for (String key : form.getPortletPreferences().keySet()) {
              List<String> prefValues = form.getPortletPreferences().get(key).getValue();
              if (prefValues != null && prefValues.size() > 0) {
                  String[] values = prefValues.toArray(new String[prefValues.size()]);
                  BooleanAttribute readOnly = form.getPortletPreferenceReadOnly().get(key);
                  preferenceList.add(new PortletPreferenceImpl(key, readOnly.getValue(), values));
              }
          }
          portletDef.setPortletPreferences(preferenceList);
  
          // Lastly update the PortletDefinition's lifecycle state & lifecycle-related metadata
          updateLifecycleState(form, portletDef, publisher);
  
          // The final parameter of IGroupMembers is used to set the initial SUBSCRIBE permission set
          portletPublishingService.savePortletDefinition(
                  portletDef, publisher, categories, new ArrayList<>(subscribePrincipalSet));
          // updatePermissions(portletDef, subscribePrincipalSet,
          // IPermission.PORTLET_SUBSCRIBER_ACTIVITY);
          updatePermissions(
                  portletDef,
                  browsePrincipalSet,
                  IPermission.PORTAL_SUBSCRIBE,
                  IPermission.PORTLET_BROWSE_ACTIVITY);
          updatePermissions(
                  portletDef,
                  configurePrincipalSet,
                  IPermission.PORTAL_PUBLISH,
                  IPermission.PORTLET_MODE_CONFIG);
          return this.createPortletDefinitionForm(
                  publisher, portletDef.getPortletDefinitionId().getStringId());
      }