Add a new tab to the layout. The new tab will be appended to the end of the list and named
with the BLANK_TAB_NAME variable.

@param request
@throws IOException
556086
@RequestMapping(method = RequestMethod.POST, params = "action=addTab")
    public ModelAndView addTab(
            HttpServletRequest request,
            HttpServletResponse response,
            @RequestParam("widths[]") String[] widths)
            throws IOException {

        IUserInstance ui = userInstanceManager.getUserInstance(request);
        IPerson person = getPerson(ui, response);
        UserPreferencesManager upm = (UserPreferencesManager) ui.getPreferencesManager();
        IUserLayoutManager ulm = upm.getUserLayoutManager();

        // Verify that the user has permission to add this tab
        final IAuthorizationPrincipal authPrincipal = this.getUserPrincipal(person.getUserName());
        if (!authPrincipal.hasPermission(
                IPermission.PORTAL_SYSTEM, IPermission.ADD_TAB_ACTIVITY, IPermission.ALL_TARGET)) {
            logger.warn(
                    "Attempt to add a tab through the REST API by unauthorized user '"
                            + person.getUserName()
                            + "'");
            response.sendError(HttpServletResponse.SC_FORBIDDEN);
            return new ModelAndView(
                    "jsonView", Collections.singletonMap("error", "Add tab disabled"));
        }

        // construct a brand new tab
        String id = "tbd";
        String tabName = request.getParameter("tabName");
        if (StringUtils.isBlank(tabName)) tabName = DEFAULT_TAB_NAME;
        IUserLayoutFolderDescription newTab = new UserLayoutFolderDescription();
        newTab.setName(tabName);
        newTab.setId(id);
        newTab.setFolderType(IUserLayoutFolderDescription.REGULAR_TYPE);
        newTab.setHidden(false);
        newTab.setUnremovable(false);
        newTab.setImmutable(false);

        // add the tab to the layout
        ulm.addNode(newTab, ulm.getRootFolderId(), null);

        try {
            // save the user's layout
            ulm.saveUserLayout();
        } catch (PortalException e) {
            return handlePersistError(request, response, e);
        }

        // get the id of the newly added tab
        String tabId = newTab.getId();

        for (String width : widths) {

            // create new column element
            IUserLayoutFolderDescription newColumn = new UserLayoutFolderDescription();
            newColumn.setName("Column");
            newColumn.setId("tbd");
            newColumn.setFolderType(IUserLayoutFolderDescription.REGULAR_TYPE);
            newColumn.setHidden(false);
            newColumn.setUnremovable(false);
            newColumn.setImmutable(false);

            // add the column to our layout
            ulm.addNode(newColumn, tabId, null);

            this.stylesheetUserPreferencesService.setLayoutAttribute(
                    request,
                    PreferencesScope.STRUCTURE,
                    newColumn.getId(),
                    CLASSIC_COLUMNS_WIDTH_USER_PREFERENCE_NAME,
                    width + "%");
            try {
                // This sets the column attribute in memory but doesn't persist it.  Comment says
                // saves changes "prior to persisting"
                Element folder = ulm.getUserLayoutDOM().getElementById(newColumn.getId());
                UserPrefsHandler.setUserPreference(
                        folder, CLASSIC_COLUMNS_WIDTH_USER_PREFERENCE_NAME, person);
            } catch (Exception e) {
                logger.error("Error saving new column widths", e);
            }
        }

        // ## 'tabGroup' value (optional feature)
        // Set the 'tabGroup' attribute on the folder element that describes
        // this new tab;  use the currently active tabGroup.
        if (request.getParameter(TAB_GROUP_PARAMETER) != null) {

            String tabGroup = request.getParameter(TAB_GROUP_PARAMETER).trim();
            if (logger.isDebugEnabled()) {
                logger.debug(TAB_GROUP_PARAMETER + "=" + tabGroup);
            }

            if (!TAB_GROUP_DEFAULT.equals(tabGroup) && tabGroup.length() != 0) {
                // Persists SSUP values to the database
                this.stylesheetUserPreferencesService.setLayoutAttribute(
                        request, PreferencesScope.STRUCTURE, tabId, TAB_GROUP_PARAMETER, tabGroup);
            }
        }

        try {
            // save the user's layout
            ulm.saveUserLayout();
        } catch (PortalException e) {
            return handlePersistError(request, response, e);
        }

        return new ModelAndView("jsonView", Collections.singletonMap("tabId", tabId));
    }
1208318
private void addQueryParams(final Request request) {
        if (absoluteDateCreated != null) {
            request.addQueryParam("DateCreated", absoluteDateCreated.toString(Request.QUERY_STRING_DATE_FORMAT));
        } else if (rangeDateCreated != null) {
            request.addQueryDateRange("DateCreated", rangeDateCreated);
        }

        if (getPageSize() != null) {
            request.addQueryParam("PageSize", Integer.toString(getPageSize()));
        }
    }
349718
private void addPostParams(final Request request) {
        if (permission != null) {
            for (String prop : permission) {
                request.addPostParam("Permission", prop);
            }
        }
    }
523334
private void addPostParams(final Request request) {
        if (binding != null) {
            request.addPostParam("Binding", binding);
        }

        if (friendlyName != null) {
            request.addPostParam("FriendlyName", friendlyName);
        }

        if (factorType != null) {
            request.addPostParam("FactorType", factorType.toString());
        }
    }
849318
private void addQueryParams(final Request request) {
        if (beta != null) {
            request.addQueryParam("Beta", beta.toString());
        }

        if (friendlyName != null) {
            request.addQueryParam("FriendlyName", friendlyName);
        }

        if (phoneNumber != null) {
            request.addQueryParam("PhoneNumber", phoneNumber.toString());
        }

        if (origin != null) {
            request.addQueryParam("Origin", origin);
        }

        if (getPageSize() != null) {
            request.addQueryParam("PageSize", Integer.toString(getPageSize()));
        }
    }
165332
private void addQueryParams(final Request request) {
        if (endDate != null) {
            request.addQueryParam("EndDate", endDate.toString());
        }

        if (friendlyName != null) {
            request.addQueryParam("FriendlyName", friendlyName);
        }

        if (minutes != null) {
            request.addQueryParam("Minutes", minutes.toString());
        }

        if (startDate != null) {
            request.addQueryParam("StartDate", startDate.toString());
        }

        if (taskChannel != null) {
            request.addQueryParam("TaskChannel", taskChannel);
        }

        if (splitByWaitTime != null) {
            request.addQueryParam("SplitByWaitTime", splitByWaitTime);
        }

        if (getPageSize() != null) {
            request.addQueryParam("PageSize", Integer.toString(getPageSize()));
        }
    }
183879
private void addQueryParams(final Request request) {
        if (status != null) {
            request.addQueryParam("Status", status.toString());
        }

        if (identity != null) {
            request.addQueryParam("Identity", identity);
        }

        if (dateCreatedAfter != null) {
            request.addQueryParam("DateCreatedAfter", dateCreatedAfter.toString());
        }

        if (dateCreatedBefore != null) {
            request.addQueryParam("DateCreatedBefore", dateCreatedBefore.toString());
        }

        if (getPageSize() != null) {
            request.addQueryParam("PageSize", Integer.toString(getPageSize()));
        }
    }
82144
private void addPostParams(final Request request) {
        if (friendlyName != null) {
            request.addPostParam("FriendlyName", friendlyName);
        }

        if (status != null) {
            request.addPostParam("Status", status.toString());
        }
    }
895272
private void addPostParams(final Request request) {
        if (defaults != null) {
            request.addPostParam("Defaults", Converter.mapToJson(defaults));
        }
    }
1216005
private void addPostParams(final Request request) {
        if (code != null) {
            request.addPostParam("Code", code);
        }

        if (to != null) {
            request.addPostParam("To", to);
        }

        if (verificationSid != null) {
            request.addPostParam("VerificationSid", verificationSid);
        }

        if (amount != null) {
            request.addPostParam("Amount", amount);
        }

        if (payee != null) {
            request.addPostParam("Payee", payee);
        }
    }
514157
private void addPostParams(final Request request) {
        if (friendlyName != null) {
            request.addPostParam("FriendlyName", friendlyName);
        }

        if (activitySid != null) {
            request.addPostParam("ActivitySid", activitySid);
        }

        if (attributes != null) {
            request.addPostParam("Attributes", attributes);
        }
    }
117556
private void addPostParams(final Request request) {
        if (callbackMethod != null) {
            request.addPostParam("CallbackMethod", callbackMethod.toString());
        }

        if (callbackUrl != null) {
            request.addPostParam("CallbackUrl", callbackUrl.toString());
        }

        if (friendlyName != null) {
            request.addPostParam("FriendlyName", friendlyName);
        }
    }
484418
private void addPostParams(final Request request) {
        if (url != null) {
            request.addPostParam("Url", url.toString());
        }

        if (method != null) {
            request.addPostParam("Method", method.toString());
        }

        if (status != null) {
            request.addPostParam("Status", status.toString());
        }

        if (fallbackUrl != null) {
            request.addPostParam("FallbackUrl", fallbackUrl.toString());
        }

        if (fallbackMethod != null) {
            request.addPostParam("FallbackMethod", fallbackMethod.toString());
        }

        if (statusCallback != null) {
            request.addPostParam("StatusCallback", statusCallback.toString());
        }

        if (statusCallbackMethod != null) {
            request.addPostParam("StatusCallbackMethod", statusCallbackMethod.toString());
        }
    }
812700
private void addPostParams(final Request request) {
        if (availableAddOnSid != null) {
            request.addPostParam("AvailableAddOnSid", availableAddOnSid);
        }

        if (acceptTermsOfService != null) {
            request.addPostParam("AcceptTermsOfService", acceptTermsOfService.toString());
        }

        if (configuration != null) {
            request.addPostParam("Configuration", Converter.mapToJson(configuration));
        }

        if (uniqueName != null) {
            request.addPostParam("UniqueName", uniqueName);
        }
    }
899283
private void addQueryParams(final Request request) {
        if (end != null) {
            request.addQueryParam("End", end);
        }

        if (start != null) {
            request.addQueryParam("Start", start);
        }
    }
1356185
public AddStepsResponse addSteps(AddStepsRequest request) {
        checkNotNull(request, "request should not be null.");
        checkNotNull(request.getSteps(), "The parameter steps should not be null.");
        checkStringNotEmpty(request.getClusterId(), "The parameter clusterId should not be null or empty string.");

        StringWriter writer = new StringWriter();
        List<StepConfig> steps = request.getSteps();
        try {
            JsonGenerator jsonGenerator = JsonUtils.jsonGeneratorOf(writer);
            jsonGenerator.writeStartObject();
            jsonGenerator.writeArrayFieldStart("steps");
            for (StepConfig step : steps) {
                jsonGenerator.writeStartObject();
                if (step.getName() != null) {
                    jsonGenerator.writeStringField("name", step.getName());
                }
                jsonGenerator.writeStringField("type", step.getType());
                jsonGenerator.writeStringField("actionOnFailure", step.getActionOnFailure());
                jsonGenerator.writeObjectFieldStart("properties");
                for (String propertyKey : step.getProperties().keySet()) {
                    jsonGenerator.writeObjectField(propertyKey, step.getProperties().get(propertyKey));
                }
                jsonGenerator.writeEndObject();
                jsonGenerator.writeArrayFieldStart("additionalFiles");
                for (AdditionalFile additionalFile : step.getAdditionalFiles()) {
                    jsonGenerator.writeStartObject();
                    jsonGenerator.writeStringField("remote", additionalFile.getRemote());
                    jsonGenerator.writeStringField("local", additionalFile.getLocal());
                    jsonGenerator.writeEndObject();
                }
                jsonGenerator.writeEndArray();
                jsonGenerator.writeEndObject();
            }
            jsonGenerator.writeEndArray();
            jsonGenerator.writeEndObject();
            jsonGenerator.close();
        } catch (IOException e) {
            throw new BceClientException("Fail to generate json", e);
        }

        byte[] json = null;
        try {
            json = writer.toString().getBytes(DEFAULT_ENCODING);
        } catch (UnsupportedEncodingException e) {
            throw new BceClientException("Fail to get UTF-8 bytes", e);
        }

        InternalRequest internalRequest = this.createRequest(
                request, HttpMethodName.POST, CLUSTER, request.getClusterId(), STEP);
        internalRequest.addHeader(Headers.CONTENT_LENGTH, String.valueOf(json.length));
        internalRequest.addHeader(Headers.CONTENT_TYPE, "application/json");

        internalRequest.setContent(RestartableInputStream.wrap(json));

        if (request.getClientToken() != null) {
            internalRequest.addParameter("clientToken", request.getClientToken());
        }

        return this.invokeHttpClient(internalRequest, AddStepsResponse.class);
    }
676813
private void addPostParams(final Request request) {
        if (name != null) {
            request.addPostParam("Name", name);
        }

        if (codeLength != null) {
            request.addPostParam("CodeLength", codeLength.toString());
        }
    }