Beispiel #1
0
 public String getPropertyOptions() {
   AppDefinition appDef = AppUtil.getCurrentAppDefinition();
   String appId = appDef.getId();
   String appVersion = appDef.getVersion().toString();
   Object[] arguments = new Object[] {appId, appVersion};
   String json =
       AppUtil.readPluginResource(
           getClass().getName(), "/properties/app/jsonTool.json", arguments, true, null);
   return json;
 }
Beispiel #2
0
 public String getPropertyOptions() {
   AppDefinition appDef = AppUtil.getCurrentAppDefinition();
   String appId = appDef.getId();
   String appVersion = appDef.getVersion().toString();
   Object[] arguments = new Object[] {appId, appVersion};
   String json =
       AppUtil.readPluginResource(
           getClass().getName(),
           "/properties/userview/dataListMenu.json",
           arguments,
           true,
           "message/userview/dataListMenu");
   return json;
 }
  protected DataListBinder createDataListBinderFromRequestInternal(
      AppDefinition appDef, String datalistId, String binderId, HttpServletRequest request) {
    DataListBinder binder = null;
    if (binderId != null && binderId.trim().length() > 0) {
      // create binder
      binder = dataListService.getBinder(binderId);

      if (request != null) {
        // get request params
        Enumeration e = request.getParameterNames();
        while (e.hasMoreElements()) {
          String paramName = (String) e.nextElement();
          if (paramName.startsWith(PREFIX_BINDER_PROPERTY)) {
            String[] paramValue = (String[]) request.getParameterValues(paramName);
            String propName = paramName.substring(PREFIX_BINDER_PROPERTY.length());

            String value = CsvUtil.getDeliminatedString(paramValue);

            if (value.contains(SecurityUtil.ENVELOPE)
                || value.contains(PropertyUtil.PASSWORD_PROTECTED_VALUE)) {
              DatalistDefinition datalist = datalistDefinitionDao.loadById(datalistId, appDef);

              if (datalist != null) {
                value = PropertyUtil.propertiesJsonStoreProcessing(datalist.getJson(), value);
              }
            }

            binder.setProperty(propName, AppUtil.processHashVariable(value, null, null, null));
          }
        }
      }
    }
    return binder;
  }
Beispiel #4
0
  protected DataList getDataList() throws BeansException {
    if (cacheDataList == null) {
      // get datalist
      ApplicationContext ac = AppUtil.getApplicationContext();
      AppService appService = (AppService) ac.getBean("appService");
      DataListService dataListService = (DataListService) ac.getBean("dataListService");
      DatalistDefinitionDao datalistDefinitionDao =
          (DatalistDefinitionDao) ac.getBean("datalistDefinitionDao");
      String id = getPropertyString("datalistId");
      AppDefinition appDef =
          appService.getAppDefinition(
              getRequestParameterString("appId"), getRequestParameterString("appVersion"));
      DatalistDefinition datalistDefinition = datalistDefinitionDao.loadById(id, appDef);

      if (datalistDefinition != null) {
        cacheDataList = dataListService.fromJson(datalistDefinition.getJson());

        if (getPropertyString(Userview.USERVIEW_KEY_NAME) != null
            && getPropertyString(Userview.USERVIEW_KEY_NAME).trim().length() > 0) {
          cacheDataList.addBinderProperty(
              Userview.USERVIEW_KEY_NAME, getPropertyString(Userview.USERVIEW_KEY_NAME));
        }
        if (getKey() != null && getKey().trim().length() > 0) {
          cacheDataList.addBinderProperty(Userview.USERVIEW_KEY_VALUE, getKey());
        }

        cacheDataList.setActionPosition(getPropertyString("buttonPosition"));
        cacheDataList.setSelectionType(getPropertyString("selectionType"));
        cacheDataList.setCheckboxPosition(getPropertyString("checkboxPosition"));
      }
    }
    return cacheDataList;
  }
Beispiel #5
0
  protected void storeToForm(WorkflowAssignment wfAssignment, Map properties, Map object) {
    String formDefId = (String) properties.get("formDefId");
    if (formDefId != null && formDefId.trim().length() > 0) {
      ApplicationContext ac = AppUtil.getApplicationContext();
      AppService appService = (AppService) ac.getBean("appService");
      AppDefinition appDef = (AppDefinition) properties.get("appDef");

      Object[] fieldMapping = (Object[]) properties.get("fieldMapping");
      String multirowBaseObjectName = (String) properties.get("multirowBaseObject");

      FormRowSet rowSet = new FormRowSet();

      if (multirowBaseObjectName != null && multirowBaseObjectName.trim().length() > 0) {
        Object[] baseObjectArray = (Object[]) getObjectFromMap(multirowBaseObjectName, object);
        if (baseObjectArray != null && baseObjectArray.length > 0) {
          rowSet.setMultiRow(true);
          for (int i = 0; i < baseObjectArray.length; i++) {
            rowSet.add(getRow(wfAssignment, multirowBaseObjectName, i, fieldMapping, object));
          }
        }
      } else {
        rowSet.add(getRow(wfAssignment, null, null, fieldMapping, object));
      }

      if (rowSet.size() > 0) {
        appService.storeFormData(
            appDef.getId(), appDef.getVersion().toString(), formDefId, rowSet, null);
      }
    }
  }
  @RequestMapping("/app/(*:appId)/(~:appVersion)/form/embed")
  public String appEmbedForm(
      ModelMap model,
      HttpServletRequest request,
      HttpServletResponse response,
      @RequestParam("appId") String appId,
      @RequestParam(value = "appVersion", required = false) String appVersion,
      @RequestParam("_submitButtonLabel") String buttonLabel,
      @RequestParam("_json") String json,
      @RequestParam("_callback") String callback,
      @RequestParam("_setting") String callbackSetting,
      @RequestParam(required = false) String id,
      @RequestParam(value = "_a", required = false) String action)
      throws JSONException, UnsupportedEncodingException {
    AppDefinition appDef = appService.getAppDefinition(appId, appVersion);

    if (appDef == null) {
      response.setStatus(HttpServletResponse.SC_NOT_FOUND);
      return null;
    }

    AppUtil.setCurrentAppDefinition(appDef);
    return embedForm(
        model, request, response, buttonLabel, json, callback, callbackSetting, id, action);
  }
  @RequestMapping("/client/app/(~:appId)/(~:version)/assignment/(*:activityId)")
  public String clientAssignmentView(
      HttpServletRequest request,
      ModelMap model,
      @RequestParam(required = false) String appId,
      @RequestParam(required = false) String version,
      @RequestParam("activityId") String activityId) {
    // check assignment
    WorkflowAssignment assignment = workflowManager.getAssignment(activityId);
    if (assignment == null) {
      return "client/app/assignmentUnavailable";
    }

    try {
      // get app
      AppDefinition appDef = null;
      if (appId != null && !appId.isEmpty()) {
        appDef = appService.getAppDefinition(appId, version);
      } else {
        appDef = appService.getAppDefinitionForWorkflowActivity(activityId);
        if (appDef != null) {
          appId = appDef.getId();
        }
      }

      FormData formData = new FormData();
      formData = formService.retrieveFormDataFromRequest(formData, request);

      // get form
      Long appVersion = (appDef != null) ? appDef.getVersion() : null;
      String formUrl =
          AppUtil.getRequestContextPath()
              + "/web/client/app/"
              + appId
              + "/"
              + appVersion
              + "/assignment/"
              + activityId
              + "/submit";
      PackageActivityForm activityForm =
          appService.viewAssignmentForm(appId, version, activityId, formData, formUrl);
      Form form = activityForm.getForm();

      // generate form HTML
      String formHtml = formService.retrieveFormHtml(form, formData);
      String formJson = formService.generateElementJson(form);

      model.addAttribute("appDef", appDef);
      model.addAttribute("assignment", assignment);
      model.addAttribute("activityForm", activityForm);
      model.addAttribute("form", form);
      model.addAttribute("formHtml", formHtml);
      model.addAttribute("formJson", formJson);
    } catch (Exception e) {
      Logger.getLogger(AppWebController.class.getName()).log(Level.SEVERE, null, e);
    }

    return "client/app/assignmentView";
  }
  protected DataList parseFromJsonParameter(
      ModelMap map, DataList dataList, String id, HttpServletRequest request) {
    // get parameters

    String jsonParam = new ParamEncoder(id).encodeParameterName("json");
    String json = request.getParameter(jsonParam);

    // use preview json if available
    if (json != null && json.trim().length() > 0) {
      try {
        String tempJson = json;
        if (tempJson.contains(SecurityUtil.ENVELOPE)
            || tempJson.contains(PropertyUtil.PASSWORD_PROTECTED_VALUE)) {
          AppDefinition appDef = AppUtil.getCurrentAppDefinition();
          DatalistDefinition datalist = datalistDefinitionDao.loadById(id, appDef);

          if (datalist != null) {
            tempJson = PropertyUtil.propertiesJsonStoreProcessing(datalist.getJson(), tempJson);
          }
        }

        dataList =
            dataListService.fromJson(AppUtil.processHashVariable(tempJson, null, null, null));
        dataList.setId(id);
      } catch (Exception ex) {
        map.addAttribute("dataListError", ex.toString());
      }
    } /* else {
      json = dataListService.toJson(dataList);
      }*/

    String jsonEncoded = null;
    try {
      if (json != null) {
        jsonEncoded = URLEncoder.encode(json, "UTF-8");
      }
    } catch (Exception ex) {
      LogUtil.error(this.getClass().getName(), ex, "parseFromJsonParameter Error!");
    }

    // set for view
    map.addAttribute("json", json);
    map.addAttribute("jsonEncoded", jsonEncoded);
    map.addAttribute("jsonParam", jsonParam);
    return dataList;
  }
  protected String getJogetFooter() {
    String html =
        "<script type=\"text/javascript\">\n"
            + "            HelpGuide.base = \""
            + request.getContextPath()
            + "\"\n"
            + "            HelpGuide.attachTo = \"#header\";\n"
            + "            HelpGuide.key = \"help.web.userview."
            + userview.getParamString("appId")
            + "."
            + userview.getParamString("userviewId")
            + "."
            + getBodyId()
            + "\";\n"
            + "            HelpGuide.show();\n"
            + "        </script>\n";

    html += AppUtil.getSystemAlert() + "\n";

    Map<String, Object> modelMap = new HashMap<String, Object>();
    AppDefinition appDef = AppUtil.getCurrentAppDefinition();
    modelMap.put("appId", userview.getParamString("appId"));
    modelMap.put("appVersion", appDef.getVersion().toString());
    modelMap.put("userviewId", userview.getParamString("userviewId"));
    html += UserviewUtil.renderJspAsString("ubuilder/adminBar.jsp", modelMap) + "\n\n";

    if ("true".equalsIgnoreCase(userview.getParamString("isPreview"))) {
      html +=
          "<!--[if IE]><div id=\"preview-label\" class=\"ie\">"
              + ResourceBundleUtil.getMessage("fbuilder.preview")
              + "</div><![endif]-->\n"
              + "        <!--[if !IE]><!--><div id=\"preview-label\">"
              + ResourceBundleUtil.getMessage("fbuilder.preview")
              + "</div><!--<![endif]-->        \n"
              + "        <div style=\"display:none\" id=\"preview-form\">\n"
              + "            <form id=\"preview\" action=\"\" method=\"post\">\n"
              + "                <input type=\"hidden\" name=\"json\" value=\""
              + StringEscapeUtils.escapeHtml(userview.getParamString("json"))
              + "\"/>\"/>\n"
              + "            </form>\n"
              + "        </div>\n";
    }

    return html;
  }
 @Override
 public String getPropertyOptions() {
   return AppUtil.readPluginResource(
       getClass().getName(),
       "/properties/form/selectBox.json",
       null,
       true,
       "message/form/SelectBox");
 }
  @RequestMapping(
      value = {
        "/console/app/(*:appId)/(~:appVersion)/datalist/builderPreview/(*:id)",
        "/client/app/(*:appId)/(*:appVersion)/datalist/(*:id)"
      })
  public String preview(
      ModelMap map,
      HttpServletRequest request,
      @RequestParam("appId") String appId,
      @RequestParam(value = "appVersion", required = false) String appVersion,
      @RequestParam("id") String id,
      @RequestParam(required = false) String json)
      throws Exception {
    String view = "dbuilder/view";

    // get current app to set into thread
    AppDefinition appDef = appService.getAppDefinition(appId, appVersion);

    try {
      // get data list
      DataList dataList = new DataList();
      if (json != null && !json.trim().isEmpty()) {

        String tempJson = json;
        if (tempJson.contains(SecurityUtil.ENVELOPE)
            || tempJson.contains(PropertyUtil.PASSWORD_PROTECTED_VALUE)) {
          DatalistDefinition datalistDef = datalistDefinitionDao.loadById(id, appDef);

          if (datalistDef != null) {
            tempJson = PropertyUtil.propertiesJsonStoreProcessing(datalistDef.getJson(), tempJson);
          }
        }

        dataList =
            dataListService.fromJson(AppUtil.processHashVariable(tempJson, null, null, null));
        map.addAttribute("json", json);
      } else {
        dataList = parseFromJsonParameter(map, dataList, id, request);
      }

      map.addAttribute("dataList", dataList);

    } catch (Exception ex) {
      StringWriter out = new StringWriter();
      ex.printStackTrace(new PrintWriter(out));
      String message = ex.toString();
      message += "\r\n<pre class=\"stacktrace\">" + out.getBuffer() + "</pre>";
      map.addAttribute("error", message);
    }

    // set map into model to be used in the JSP template
    map.addAttribute("properties", new HashMap(map));
    return view;
  }
Beispiel #12
0
  protected void storeToWorkflowVariable(
      WorkflowAssignment wfAssignment, Map properties, Map object) {
    Object[] wfVariableMapping = (Object[]) properties.get("wfVariableMapping");
    if (wfVariableMapping != null && wfVariableMapping.length > 0) {
      ApplicationContext ac = AppUtil.getApplicationContext();
      WorkflowManager workflowManager = (WorkflowManager) ac.getBean("workflowManager");

      for (Object o : wfVariableMapping) {
        Map mapping = (HashMap) o;
        String variable = mapping.get("variable").toString();
        String jsonObjectName = mapping.get("jsonObjectName").toString();

        String value = (String) getObjectFromMap(jsonObjectName, object);

        if (value != null) {
          workflowManager.activityVariable(wfAssignment.getActivityId(), variable, value);
        }
      }
    }
  }
Beispiel #13
0
 /**
  * Reads a resource from a plugin. java.util.Formatter text patterns supported.
  *
  * @param pluginName
  * @param resourceUrl
  * @param arguments
  * @param removeNewLines
  * @param translationFileName
  * @return null if the resource is not found or in the case of an exception
  * @see java.util.Formatter
  */
 public static String readPluginResource(
     String pluginName,
     String resourceUrl,
     Object[] arguments,
     boolean removeNewLines,
     String translationFileName) {
   String output = null;
   if (pluginName != null && resourceUrl != null) {
     PluginManager pluginManager = (PluginManager) appContext.getBean("pluginManager");
     output =
         pluginManager.readPluginResourceAsString(
             pluginName, resourceUrl, arguments, removeNewLines, translationFileName);
   }
   // replace app path
   if (output != null && !output.isEmpty()) {
     String appPath = "";
     AppDefinition appDef = AppUtil.getCurrentAppDefinition();
     if (appDef != null) {
       appPath = "/" + appDef.getAppId() + "/" + appDef.getVersion();
     }
     output = output.replaceAll("\\[APP_PATH\\]", appPath);
   }
   return output;
 }
  @RequestMapping("/client/app/(~:appId)/(~:version)/assignment/(*:activityId)/submit")
  public String clientAssignmentSubmit(
      HttpServletRequest request,
      ModelMap model,
      @RequestParam(required = false) String appId,
      @RequestParam(required = false) String version,
      @RequestParam("activityId") String activityId) {
    // check assignment
    WorkflowAssignment assignment = workflowManager.getAssignment(activityId);
    if (assignment == null) {
      return "client/app/assignmentUnavailable";
    }

    // get app
    AppDefinition appDef = null;
    if (appId != null && !appId.isEmpty()) {
      appDef = appService.getAppDefinition(appId, version);
    } else {
      appDef = appService.getAppDefinitionForWorkflowActivity(activityId);
    }

    // extract form values from request
    FormData formData = new FormData();
    formData = formService.retrieveFormDataFromRequest(formData, request);

    // set process instance ID as primary key
    String processId = assignment.getProcessId();

    // load form
    Long appVersion = (appDef != null) ? appDef.getVersion() : null;
    String formUrl =
        AppUtil.getRequestContextPath()
            + "/web/client/app/"
            + appId
            + "/"
            + appVersion
            + "/assignment/"
            + activityId
            + "/submit";
    PackageActivityForm activityForm =
        appService.viewAssignmentForm(appId, version, activityId, formData, formUrl);
    Form form = activityForm.getForm();

    // submit form
    FormData formResult = formService.executeFormActions(form, formData);

    if (formResult.getFormResult(AssignmentWithdrawButton.DEFAULT_ID) != null) {
      // withdraw assignment
      workflowManager.assignmentWithdraw(activityId);
      return "client/app/dialogClose";

    } else if (formResult.getFormResult(AssignmentCompleteButton.DEFAULT_ID) != null) {
      // complete assignment
      Map<String, String> variableMap = AppUtil.retrieveVariableDataFromRequest(request);
      formResult =
          appService.completeAssignmentForm(appId, version, activityId, formData, variableMap);

      Map<String, String> errors = formResult.getFormErrors();
      if (errors.isEmpty() && activityForm.isAutoContinue()) {
        // redirect to next activity if available
        WorkflowAssignment nextActivity = workflowManager.getAssignmentByProcess(processId);
        if (nextActivity != null) {
          String assignmentUrl =
              "/web/client/app/"
                  + appId
                  + "/"
                  + appVersion
                  + "/assignment/"
                  + nextActivity.getActivityId();
          return "redirect:" + assignmentUrl;
        }
      }
    }

    String html = null;

    // check for validation errors
    Map<String, String> errors = formResult.getFormErrors();
    int errorCount = 0;
    if (errors == null || errors.isEmpty()) {
      // render normal template
      html = formService.generateElementHtml(form, formResult);
    } else {
      // render error template
      html = formService.generateElementErrorHtml(form, formResult);
      errorCount = errors.size();
    }
    String formJson = formService.generateElementJson(form);

    model.addAttribute("assignment", assignment);
    model.addAttribute("form", form);
    model.addAttribute("formHtml", html);
    model.addAttribute("formJson", formJson);
    model.addAttribute("formResult", formResult);
    model.addAttribute("errorCount", errorCount);
    model.addAttribute("submitted", Boolean.TRUE);
    model.addAttribute("closeDialog", Boolean.TRUE);

    return "client/app/assignmentView";
  }
  public String getHtml() {
    Map<String, Object> data = new HashMap<String, Object>();
    data.put("params", userview.getParams());
    data.put("userview", userview);
    data.put("is_login_page", isLoginPage);
    if (isLoginPage) {
      data.put("login_form_footer", DirectoryUtil.getLoginFormFooter());

      if (request.getSession() != null) {
        Throwable exception =
            (Throwable) request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
        if (exception != null) {
          data.put("login_exception", exception.getMessage());
        }
      }
      data.put("login_error_classes", "form-errors alert alert-warning");
    }
    data.put("context_path", request.getContextPath());
    data.put("build_number", ResourceBundleUtil.getMessage("build.number"));
    String rightToLeft = WorkflowUtil.getSystemSetupValue("rightToLeft");
    data.put("right_to_left", "true".equalsIgnoreCase(rightToLeft));
    String locale = AppUtil.getAppLocale();
    data.put("locale", locale);
    data.put("embed", "true".equalsIgnoreCase(userview.getParamString("embed")));
    data.put("body_id", getBodyId());
    data.put("body_classes", getBodyClasses(rightToLeft, locale));
    data.put("base_link", request.getContextPath() + getBaseLink());
    data.put("home_page_link", request.getContextPath() + getHomePageLink());
    data.put("title", getTitle());
    data.put("hide_nav", false);
    data.put("nav_id", "navigation");
    data.put("nav_classes", "nav-collapse sidebar-nav");
    data.put("categories_container_id", "category-container");
    data.put("categories_container_classes", "nav nav-tabs nav-stacked main-menu");
    data.put("category_classes", "category");
    data.put("first_category_classes", "first");
    data.put("last_category_classes", "last");
    data.put("current_category_classes", "current-category active");
    data.put("combine_single_menu_category", false);
    data.put("menus_container_classes", "menu-container");
    data.put("menu_classes", "menu");
    data.put("first_menu_classes", "first");
    data.put("last_menu_classes", "last");
    data.put("current_menu_classes", "current active");
    data.put("main_container_id", "main");
    data.put("sidebar_id", "sidebar");
    data.put("content_id", "content");

    String username = WorkflowUtil.getCurrentUsername();
    boolean isLoggedIn = username != null && !WorkflowUserManager.ROLE_ANONYMOUS.equals(username);
    data.put("is_logged_in", isLoggedIn);
    if (isLoggedIn) {
      ExtDirectoryManager directoryManager =
          (ExtDirectoryManager) AppUtil.getApplicationContext().getBean("directoryManager");
      User user = directoryManager.getUserByUsername(username);
      data.put("username", username);
      data.put("user", user);
      data.put("logout_link", request.getContextPath() + "/j_spring_security_logout");
    } else {
      data.put("login_link", request.getContextPath() + getLoginLink());
    }

    data.put("content", getContent(data));

    String handleMenuResponse = handleMenuResponse();
    if (handleMenuResponse != null) {
      return handleMenuResponse;
    }

    data.put("metas", getMetas(data));
    data.put("joget_header", getJogetHeader());
    data.put("js_css_lib", getJsCssLib(data));
    data.put("fav_icon_link", getFavIconLink(data));
    data.put("js", getJs(data));
    data.put("css", getCss(data));
    data.put("head", getHead(data));
    if (!"true".equalsIgnoreCase(userview.getParamString("embed"))) {
      data.put("header", getHeader(data));
      if (isAuthorized) {
        data.put("menus", getMenus(data));
      }
      data.put("footer", getFooter(data));
    }
    data.put("joget_footer", getJogetFooter());
    data.put("content_container", getContentContainer(data));

    return getLayout(data);
  }
Beispiel #16
0
  public static String processHashVariable(
      String content,
      WorkflowAssignment wfAssignment,
      String escapeFormat,
      Map<String, String> replaceMap,
      AppDefinition appDef) {
    // check for hash # to avoid unnecessary processing
    if (!containsHashVariable(content)) {
      return content;
    }

    // parse content
    if (content != null) {
      Pattern pattern = Pattern.compile("\\#([^#^\"^ ])*\\.([^#^\"])*\\#");
      Matcher matcher = pattern.matcher(content);
      List<String> varList = new ArrayList<String>();
      while (matcher.find()) {
        varList.add(matcher.group());
      }

      try {
        if (!varList.isEmpty()) {
          PluginManager pluginManager = (PluginManager) appContext.getBean("pluginManager");
          PluginDefaultPropertiesDao pluginDefaultPropertiesDao =
              (PluginDefaultPropertiesDao) appContext.getBean("pluginDefaultPropertiesDao");
          Collection<Plugin> pluginList = pluginManager.list(HashVariablePlugin.class);
          Map<String, HashVariablePlugin> hashVariablePluginCache =
              new HashMap<String, HashVariablePlugin>();

          for (String var : varList) {
            String tempVar = var.replaceAll("#", "");

            for (Plugin p : pluginList) {
              HashVariablePlugin hashVariablePlugin = (HashVariablePlugin) p;
              if (tempVar.startsWith(hashVariablePlugin.getPrefix() + ".")) {
                tempVar = tempVar.replaceFirst(hashVariablePlugin.getPrefix() + ".", "");

                HashVariablePlugin cachedPlugin =
                    hashVariablePluginCache.get(hashVariablePlugin.getClassName());
                if (cachedPlugin == null) {
                  cachedPlugin =
                      (HashVariablePlugin)
                          pluginManager.getPlugin(hashVariablePlugin.getClassName());
                  // get default plugin properties

                  if (appDef == null) {
                    appDef = AppUtil.getCurrentAppDefinition();
                  }
                  PluginDefaultProperties pluginDefaultProperties =
                      pluginDefaultPropertiesDao.loadById(cachedPlugin.getClassName(), appDef);
                  if (pluginDefaultProperties != null
                      && pluginDefaultProperties.getPluginProperties() != null
                      && pluginDefaultProperties.getPluginProperties().trim().length() > 0) {
                    cachedPlugin.setProperties(
                        PropertyUtil.getPropertiesValueFromJson(
                            pluginDefaultProperties.getPluginProperties()));
                  }

                  // put appDef & wfAssignment to properties
                  cachedPlugin.setProperty("appDefinition", appDef);
                  cachedPlugin.setProperty("workflowAssignment", wfAssignment);
                  hashVariablePluginCache.put(hashVariablePlugin.getClassName(), cachedPlugin);
                }

                // process nested hash
                while (tempVar.contains("{") && tempVar.contains("}")) {
                  Pattern nestedPattern = Pattern.compile("\\{([^\\{^\\}])*\\}");
                  Matcher nestedMatcher = nestedPattern.matcher(tempVar);
                  while (nestedMatcher.find()) {
                    String nestedHash = nestedMatcher.group();
                    String nestedHashString = nestedHash.replace("{", "#");
                    nestedHashString = nestedHashString.replace("}", "#");

                    String processedNestedHashValue =
                        processHashVariable(
                            nestedHashString, wfAssignment, escapeFormat, replaceMap, appDef);
                    tempVar =
                        tempVar.replaceAll(
                            StringUtil.escapeString(nestedHash, StringUtil.TYPE_REGEX, null),
                            StringUtil.escapeString(
                                processedNestedHashValue, escapeFormat, replaceMap));
                  }
                }

                // get result from plugin
                String value = cachedPlugin.processHashVariable(tempVar);

                if (value != null && !StringUtil.TYPE_REGEX.equals(escapeFormat)) {
                  value = StringUtil.escapeRegex(value);
                }

                // escape special char in HashVariable
                var = cachedPlugin.escapeHashVariable(var);

                // replace
                if (value != null) {
                  content =
                      content.replaceAll(
                          var, StringUtil.escapeString(value, escapeFormat, replaceMap));
                }
              }
            }
          }
        }
      } catch (Exception ex) {
        LogUtil.error(AppUtil.class.getName(), ex, "");
      }
    }
    return content;
  }
public class UserviewThemeProcesser {

  Userview userview;
  UserviewV5Theme defaultTheme;
  UserviewV5Theme theme;
  HttpServletRequest request;
  String redirectUrl = null;
  String alertMessage = null;
  boolean isAuthorized = false;
  boolean isLoginPage = false;
  boolean isQuickEditEnabled = AppUtil.isQuickEditEnabled();

  public UserviewThemeProcesser(Userview userview, HttpServletRequest request) {
    this.userview = userview;
    this.request = request;

    isAuthorized =
        userview.getSetting().getPermission() == null
            || (userview.getSetting().getPermission() != null
                && userview.getSetting().getPermission().isAuthorize());
    if (!isAuthorized) {
      this.userview.setCurrent(null);
    }
  }

  public String getPreviewView() {
    if (userview.getSetting().getTheme() != null
        && !(userview.getSetting().getTheme() instanceof UserviewV5Theme)) {
      return "ubuilder/preview";
    }

    init();

    return "ubuilder/v5view";
  }

  public String getLoginView() {
    if (userview.getSetting().getTheme() != null
        && !(userview.getSetting().getTheme() instanceof UserviewV5Theme)) {
      return "ubuilder/login";
    }

    String loginRedirection = loginRedirection();
    if (loginRedirection != null) {
      return loginRedirection;
    }

    isLoginPage = true;
    init();

    return "ubuilder/v5view";
  }

  public String getView() {

    if (userview.getSetting().getTheme() != null
        && !(userview.getSetting().getTheme() instanceof UserviewV5Theme)) {
      return "ubuilder/view";
    }

    String mobileViewRedirection = mobileViewRedirection();
    if (mobileViewRedirection != null) {
      return mobileViewRedirection;
    }

    String homePageRedirection = homePageRedirection();
    if (homePageRedirection != null) {
      return homePageRedirection;
    }

    String loginPageRedirection = loginPageRedirection();
    if (loginPageRedirection != null) {
      return loginPageRedirection;
    }

    init();

    return "ubuilder/v5view";
  }

  public void init() {
    if (userview.getSetting().getTheme() != null) {
      theme = (UserviewV5Theme) userview.getSetting().getTheme();
    } else {
      theme = new DefaultV5EmptyTheme();
    }
  }

  public String getHtml() {
    Map<String, Object> data = new HashMap<String, Object>();
    data.put("params", userview.getParams());
    data.put("userview", userview);
    data.put("is_login_page", isLoginPage);
    if (isLoginPage) {
      data.put("login_form_footer", DirectoryUtil.getLoginFormFooter());

      if (request.getSession() != null) {
        Throwable exception =
            (Throwable) request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
        if (exception != null) {
          data.put("login_exception", exception.getMessage());
        }
      }
      data.put("login_error_classes", "form-errors alert alert-warning");
    }
    data.put("context_path", request.getContextPath());
    data.put("build_number", ResourceBundleUtil.getMessage("build.number"));
    String rightToLeft = WorkflowUtil.getSystemSetupValue("rightToLeft");
    data.put("right_to_left", "true".equalsIgnoreCase(rightToLeft));
    String locale = AppUtil.getAppLocale();
    data.put("locale", locale);
    data.put("embed", "true".equalsIgnoreCase(userview.getParamString("embed")));
    data.put("body_id", getBodyId());
    data.put("body_classes", getBodyClasses(rightToLeft, locale));
    data.put("base_link", request.getContextPath() + getBaseLink());
    data.put("home_page_link", request.getContextPath() + getHomePageLink());
    data.put("title", getTitle());
    data.put("hide_nav", false);
    data.put("nav_id", "navigation");
    data.put("nav_classes", "nav-collapse sidebar-nav");
    data.put("categories_container_id", "category-container");
    data.put("categories_container_classes", "nav nav-tabs nav-stacked main-menu");
    data.put("category_classes", "category");
    data.put("first_category_classes", "first");
    data.put("last_category_classes", "last");
    data.put("current_category_classes", "current-category active");
    data.put("combine_single_menu_category", false);
    data.put("menus_container_classes", "menu-container");
    data.put("menu_classes", "menu");
    data.put("first_menu_classes", "first");
    data.put("last_menu_classes", "last");
    data.put("current_menu_classes", "current active");
    data.put("main_container_id", "main");
    data.put("sidebar_id", "sidebar");
    data.put("content_id", "content");

    String username = WorkflowUtil.getCurrentUsername();
    boolean isLoggedIn = username != null && !WorkflowUserManager.ROLE_ANONYMOUS.equals(username);
    data.put("is_logged_in", isLoggedIn);
    if (isLoggedIn) {
      ExtDirectoryManager directoryManager =
          (ExtDirectoryManager) AppUtil.getApplicationContext().getBean("directoryManager");
      User user = directoryManager.getUserByUsername(username);
      data.put("username", username);
      data.put("user", user);
      data.put("logout_link", request.getContextPath() + "/j_spring_security_logout");
    } else {
      data.put("login_link", request.getContextPath() + getLoginLink());
    }

    data.put("content", getContent(data));

    String handleMenuResponse = handleMenuResponse();
    if (handleMenuResponse != null) {
      return handleMenuResponse;
    }

    data.put("metas", getMetas(data));
    data.put("joget_header", getJogetHeader());
    data.put("js_css_lib", getJsCssLib(data));
    data.put("fav_icon_link", getFavIconLink(data));
    data.put("js", getJs(data));
    data.put("css", getCss(data));
    data.put("head", getHead(data));
    if (!"true".equalsIgnoreCase(userview.getParamString("embed"))) {
      data.put("header", getHeader(data));
      if (isAuthorized) {
        data.put("menus", getMenus(data));
      }
      data.put("footer", getFooter(data));
    }
    data.put("joget_footer", getJogetFooter());
    data.put("content_container", getContentContainer(data));

    return getLayout(data);
  }

  public String getRedirectUrl() {
    return redirectUrl;
  }

  protected String mobileViewRedirection() {
    boolean mobileAgent = (!MobileUtil.isMobileDisabled() && MobileUtil.isMobileUserAgent(request));
    boolean disableMobileView =
        "true".equalsIgnoreCase(userview.getSetting().getPropertyString("mobileViewDisabled"));
    boolean desktopCookie = false;
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
      for (Cookie cookie : cookies) {
        if ("desktopSite".equals(cookie.getName())) {
          if ("true".equalsIgnoreCase(cookie.getValue())) {
            desktopCookie = true;
          }
          break;
        }
      }
    }

    if (mobileAgent && !disableMobileView && !desktopCookie) {
      String url =
          "/web/mobile/"
              + userview.getParamString("appId")
              + "/"
              + userview.getPropertyString("id")
              + "/"
              + userview.getParamString("key")
              + "/";
      if (!userview.getParamString("menuId").isEmpty()) {
        url += userview.getParamString("menuId");
      }
      return "redirect:" + url;
    }
    return null;
  }

  protected String homePageRedirection() {
    if (userview.getParamString("menuId").isEmpty()
        && !userview.getPropertyString("homeMenuId").isEmpty()) {
      return "redirect:"
          + getHomePageLink()
          + (request.getQueryString() == null
              ? ""
              : ("?" + StringUtil.decodeURL(request.getQueryString())));
    }
    return null;
  }

  protected String loginRedirection() {
    boolean isAnonymous = WorkflowUtil.isCurrentUserAnonymous();
    if (!isAnonymous) {
      String url = getBaseLink();
      String menuId = userview.getParamString("menuId");
      // check current redirect url is exist, else redirect to home
      boolean isExist = false;
      if (menuId != null && !menuId.isEmpty()) {
        for (UserviewCategory c : userview.getCategories()) {
          for (UserviewMenu m : c.getMenus()) {
            if (menuId.equals(m.getPropertyString("id"))
                || menuId.equals(m.getPropertyString("customId"))) {
              isExist = true;
              break;
            }
          }
          if (isExist) {
            break;
          }
        }
      }
      if (isExist) {
        if (!userview.getParamString("menuId").isEmpty()) {
          url += menuId;
        }
        if (request.getQueryString() != null) {
          url += "?" + request.getQueryString();
        }
      } else {
        url += userview.getProperty("homeMenuId");
      }

      return "redirect:" + url;
    }
    return null;
  }

  protected String loginPageRedirection() {
    boolean isAnonymous = WorkflowUtil.isCurrentUserAnonymous();
    boolean hasCurrentPage = userview.getCurrent() != null;
    if ((!isAuthorized || !hasCurrentPage) && isAnonymous) {
      return "redirect:"
          + getLoginLink()
          + (request.getQueryString() == null
              ? ""
              : ("?" + StringUtil.decodeURL(request.getQueryString())));
    }
    return null;
  }

  protected String getBodyId() {
    String bodyId = "";

    if (isLoginPage) {
      bodyId = "login";
    } else if (!isAuthorized) {
      bodyId = "unauthorize";
    } else if (userview.getCurrent() != null) {
      bodyId = userview.getCurrent().getPropertyString("customId");
      if (bodyId.isEmpty()) {
        bodyId = userview.getCurrent().getPropertyString("id");
      }
    } else {
      bodyId = "pageNotFound";
    }

    return bodyId;
  }

  protected String getBodyClasses(String rightToLeft, String locale) {
    String classes = "";
    classes += ("true".equalsIgnoreCase(userview.getParamString("embed"))) ? "embeded " : "";
    classes += ("true".equalsIgnoreCase(rightToLeft) || locale.startsWith("ar")) ? "rtl " : "";
    classes += locale;
    return classes;
  }

  protected String getJogetHeader() {
    String cp = request.getContextPath();
    String bn = ResourceBundleUtil.getMessage("build.number");
    String html =
        "<link rel=\"stylesheet\" type=\"text/css\" href=\""
            + cp
            + "/wro/common.css?build="
            + bn
            + "\" />\n"
            + "<link rel=\"stylesheet\" type=\"text/css\" href=\""
            + cp
            + "/wro/userview_v5.min.css?build="
            + bn
            + "\" />\n"
            + "<script type=\"text/javascript\" src=\""
            + cp
            + "/wro/common.js?build="
            + bn
            + "\"></script>\n"
            + "<script type=\"text/javascript\">\n";

    UserSecurity us = DirectoryUtil.getUserSecurity();
    if (!(us != null && us.getAllowSessionTimeout())) {
      html +=
          "$(document).ready(function(){\n"
              + "            $('body').append('<img id=\"image_alive\" style=\"display:none;\" width=\"1\" height=\"1\" src=\""
              + cp
              + "/images/v3/clear.gif?\" alt=\"\">');\n"
              + "            window.setInterval(\"keepMeAlive('image_alive')\", 200000);\n"
              + "        });\n"
              + "        function keepMeAlive(imgName)\n"
              + "        {  \n"
              + "             myImg = document.getElementById(imgName);   \n"
              + "             if (myImg)\n"
              + "                 myImg.src = myImg.src.replace(/\\?.*$/, '?' + Math.random());   \n"
              + "        }  ";
    }

    // fix IE browser
    html +=
        "if ($.browser.msie) {\n"
            + "            $(document).on(\"keydown\", function (e) {\n"
            + "                if (e.which === 8 && !$(e.target).is(\"input:not([readonly]), textarea:not([readonly])\")) {\n"
            + "                    e.preventDefault();\n"
            + "                }\n"
            + "            });\n"
            + "        }\n";

    // userview print feature
    html +=
        "function userviewPrint(){\n"
            + "            $('head').append('<link id=\"userview_print_css\" rel=\"stylesheet\" href=\""
            + cp
            + "/wro/userview_print.min.css\" type=\"text/css\" media=\"print\"/>');\n"
            + "            setTimeout(\"do_print()\", 1000); \n"
            + "        }\n"
            + "        function do_print(){\n"
            + "            window.print();\n"
            + "            $('#userview_print_css').remove();\n"
            + "        }\n";

    if ("true".equalsIgnoreCase(userview.getParamString("isPreview"))) {
      html +=
          "$(document).ready(function(){\n$('a').click(function(){\n"
              + "        var action = $(this).attr('href');\n"
              + "if (action !== \"\" && action !== undefined && action !== \"#\"){\n"
              + "        $('#preview').attr('action', action);\n"
              + "        $('#preview').submit();\n"
              + "}\n"
              + "        return false;\n"
              + "    });\n"
              + "\n});\n";
    }

    html +=
        "UI.base = \""
            + request.getContextPath()
            + "\";\n"
            + "        UI.userview_app_id = '"
            + userview.getParamString("appId")
            + "';\n"
            + "        UI.userview_id = '"
            + userview.getPropertyString("id")
            + "';\n";

    if (alertMessage != null && !alertMessage.isEmpty()) {
      html += "alert(\"" + alertMessage + "\");\n";
    }

    html += "</script>\n";

    html +=
        "    <script>\n"
            + "        ConnectionManager.tokenName = \""
            + SecurityUtil.getCsrfTokenName()
            + "\";\n"
            + "        ConnectionManager.tokenValue = \""
            + SecurityUtil.getCsrfTokenValue(request)
            + "\";\n"
            + "        JPopup.tokenName = \""
            + SecurityUtil.getCsrfTokenName()
            + "\";\n"
            + "        JPopup.tokenValue = \""
            + SecurityUtil.getCsrfTokenValue(request)
            + "\";\n"
            + "    </script>";

    return html;
  }

  protected String getJogetFooter() {
    String html =
        "<script type=\"text/javascript\">\n"
            + "            HelpGuide.base = \""
            + request.getContextPath()
            + "\"\n"
            + "            HelpGuide.attachTo = \"#header\";\n"
            + "            HelpGuide.key = \"help.web.userview."
            + userview.getParamString("appId")
            + "."
            + userview.getParamString("userviewId")
            + "."
            + getBodyId()
            + "\";\n"
            + "            HelpGuide.show();\n"
            + "        </script>\n";

    html += AppUtil.getSystemAlert() + "\n";

    Map<String, Object> modelMap = new HashMap<String, Object>();
    AppDefinition appDef = AppUtil.getCurrentAppDefinition();
    modelMap.put("appId", userview.getParamString("appId"));
    modelMap.put("appVersion", appDef.getVersion().toString());
    modelMap.put("userviewId", userview.getParamString("userviewId"));
    html += UserviewUtil.renderJspAsString("ubuilder/adminBar.jsp", modelMap) + "\n\n";

    if ("true".equalsIgnoreCase(userview.getParamString("isPreview"))) {
      html +=
          "<!--[if IE]><div id=\"preview-label\" class=\"ie\">"
              + ResourceBundleUtil.getMessage("fbuilder.preview")
              + "</div><![endif]-->\n"
              + "        <!--[if !IE]><!--><div id=\"preview-label\">"
              + ResourceBundleUtil.getMessage("fbuilder.preview")
              + "</div><!--<![endif]-->        \n"
              + "        <div style=\"display:none\" id=\"preview-form\">\n"
              + "            <form id=\"preview\" action=\"\" method=\"post\">\n"
              + "                <input type=\"hidden\" name=\"json\" value=\""
              + StringEscapeUtils.escapeHtml(userview.getParamString("json"))
              + "\"/>\"/>\n"
              + "            </form>\n"
              + "        </div>\n";
    }

    return html;
  }

  protected String getTitle() {
    String title = userview.getPropertyString("name");
    if (userview.getCurrent() != null) {
      title += "&nbsp;&gt;&nbsp;" + userview.getCurrent().getPropertyString("label");
    }

    return StringUtil.stripAllHtmlTag(title);
  }

  protected String getBaseLink() {
    String key = userview.getParamString("key");
    if (key.isEmpty()) {
      key = Userview.USERVIEW_KEY_EMPTY_VALUE;
    }
    return "/web/"
        + ("true".equalsIgnoreCase(userview.getParamString("embed")) ? "embed/" : "")
        + "userview/"
        + userview.getParamString("appId")
        + "/"
        + userview.getPropertyString("id")
        + "/"
        + key
        + "/";
  }

  protected String getHomePageLink() {
    return getBaseLink() + userview.getPropertyString("homeMenuId");
  }

  protected String getLoginLink() {
    String key = userview.getParamString("key");
    if (key.isEmpty()) {
      key = Userview.USERVIEW_KEY_EMPTY_VALUE;
    }
    return "/web/"
        + ("true".equalsIgnoreCase(userview.getParamString("embed")) ? "embed/" : "")
        + "ulogin/"
        + userview.getParamString("appId")
        + "/"
        + userview.getPropertyString("id")
        + "/"
        + key
        + "/"
        + userview.getParamString("menuId");
  }

  protected String getMetas(Map<String, Object> data) {
    String content = theme.getMetas(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getMetas(data);
    }
  }

  protected String getCss(Map<String, Object> data) {
    String content = theme.getCss(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getCss(data);
    }
  }

  protected String getFavIconLink(Map<String, Object> data) {
    String content = theme.getFavIconLink(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getFavIconLink(data);
    }
  }

  protected String getJsCssLib(Map<String, Object> data) {
    String content = theme.getJsCssLib(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getJsCssLib(data);
    }
  }

  protected String getJs(Map<String, Object> data) {
    String content = theme.getJs(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getJs(data);
    }
  }

  protected String getHead(Map<String, Object> data) {
    String content = theme.getHead(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getHead(data);
    }
  }

  protected String getHeader(Map<String, Object> data) {
    String content = theme.getHeader(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getHeader(data);
    }
  }

  protected String getFooter(Map<String, Object> data) {
    String content = theme.getFooter(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getFooter(data);
    }
  }

  protected String getMenus(Map<String, Object> data) {
    String content = "";
    String menu = theme.getMenus(data);
    if (menu == null) {
      menu = getDefaultTheme().getMenus(data);
    }
    if (isQuickEditEnabled) {
      String label =
          ResourceBundleUtil.getMessage("adminBar.label.menu")
              + ": "
              + userview.getPropertyString("name");
      String url =
          request.getContextPath()
              + "/web/console/app/"
              + userview.getParamString("appId")
              + "/"
              + userview.getParamString("appVersion")
              + "/userview/builder/"
              + userview.getPropertyString("id");
      content += "<div class=\"quickEdit\" style=\"display: none\">\n";
      content +=
          "    <a href=\""
              + url
              + "\" target=\"_blank\"><i class=\"icon-edit\"></i> "
              + label
              + "</a>\n";
      content += "</div>\n";
    }
    content += menu;
    return content;
  }

  protected String getLayout(Map<String, Object> data) {
    String content = theme.getLayout(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getLayout(data);
    }
  }

  protected String getContentContainer(Map<String, Object> data) {
    String content = theme.getContentContainer(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getContentContainer(data);
    }
  }

  protected String getLoginForm(Map<String, Object> data) {
    String content = theme.getLoginForm(data);
    if (content != null) {
      return content;
    } else {
      return getDefaultTheme().getLoginForm(data);
    }
  }

  protected String getContent(Map<String, Object> data) {
    String content = "";
    try {
      if (isLoginPage) {
        return getLoginForm(data);
      } else if (!isAuthorized) {
        return "<h3>" + ResourceBundleUtil.getMessage("ubuilder.noAuthorize") + "</h3>";
      } else if (userview.getCurrent() != null) {
        if (isQuickEditEnabled) {
          String label =
              ResourceBundleUtil.getMessage("adminBar.label.page")
                  + ": "
                  + userview.getCurrent().getPropertyString("label");
          String url =
              request.getContextPath()
                  + "/web/console/app/"
                  + userview.getParamString("appId")
                  + "/"
                  + userview.getParamString("appVersion")
                  + "/userview/builder/"
                  + userview.getPropertyString("id")
                  + "?menuId="
                  + userview.getCurrent().getPropertyString("id");
          content += "<div class=\"quickEdit\" style=\"display: none\">\n";
          content +=
              "    <a href=\""
                  + url
                  + "\" target=\"_blank\"><i class=\"icon-edit\"></i> "
                  + label
                  + "</a>\n";
          content += "</div>\n";
        }

        content += UserviewUtil.getUserviewMenuHtml(userview.getCurrent());
      } else {
        String pageNotFound = theme.handlePageNotFound(data);
        if (pageNotFound != null) {
          return pageNotFound;
        } else {
          return getDefaultTheme().handlePageNotFound(data);
        }
      }
    } catch (Exception e) {
      String errorHandle = theme.handleContentError(e, data);
      if (errorHandle != null) {
        return errorHandle;
      } else {
        return getDefaultTheme().handleContentError(e, data);
      }
    }

    return content;
  }

  protected String handleMenuResponse() {
    if (userview.getCurrent() != null) {
      String menuAlertMessage =
          userview.getCurrent().getPropertyString(UserviewMenu.ALERT_MESSAGE_PROPERTY);
      String menuRedirectUrl =
          userview.getCurrent().getPropertyString(UserviewMenu.REDIRECT_URL_PROPERTY);
      String redirectParent =
          userview.getCurrent().getPropertyString(UserviewMenu.REDIRECT_PARENT_PROPERTY);

      if ((menuAlertMessage != null && !menuAlertMessage.isEmpty())
          || (redirectParent != null && "true".equalsIgnoreCase(redirectParent))) {
        if (menuRedirectUrl != null && !menuRedirectUrl.isEmpty()) {
          Map<String, String> data = new HashMap<String, String>();
          data.put("alertMessage", menuAlertMessage);
          data.put("redirectUrl", menuRedirectUrl);
          data.put("redirectParent", redirectParent);
          return UserviewUtil.getTemplate(
              getDefaultTheme(), data, "/templates/userview/redirect.ftl");
        } else {
          alertMessage = menuAlertMessage;
        }
      } else if (menuRedirectUrl != null && !menuRedirectUrl.isEmpty()) {
        if (!menuRedirectUrl.toLowerCase().startsWith("http")
            && !menuRedirectUrl.toLowerCase().startsWith("/")
            && !menuRedirectUrl.startsWith(request.getContextPath())) {
          redirectUrl = "/web/";
          if ("true".equalsIgnoreCase(userview.getParamString("embed"))) {
            redirectUrl += "embed/";
          }
          redirectUrl += "userview/" + userview.getParamString("appId") + "/";
          redirectUrl += userview.getPropertyString("id") + "/";
          redirectUrl += userview.getParamString("key") + "/" + menuRedirectUrl;
        } else if (menuRedirectUrl.startsWith(request.getContextPath())) {
          redirectUrl = menuRedirectUrl.replaceFirst(request.getContextPath(), "");
        } else {
          redirectUrl = menuRedirectUrl;
        }
      }
    }
    return null;
  }

  protected UserviewV5Theme getDefaultTheme() {
    if (defaultTheme == null) {
      defaultTheme = new DefaultV5EmptyTheme();
    }
    return defaultTheme;
  }
}
  @RequestMapping("/client/app/(*:appId)/(~:version)/process/(*:processDefId)/start")
  public String clientProcessStart(
      HttpServletRequest request,
      ModelMap model,
      @RequestParam("appId") String appId,
      @RequestParam(required = false) String version,
      @RequestParam(required = false) String recordId,
      @RequestParam String processDefId) {

    // clean process def
    processDefId = WorkflowUtil.getProcessDefIdWithoutVersion(processDefId);

    // set app and process details
    AppDefinition appDef = appService.getAppDefinition(appId, version);
    WorkflowProcess processDef =
        appService.getWorkflowProcessForApp(appId, appDef.getVersion().toString(), processDefId);
    String processDefIdWithVersion = processDef.getId();
    model.addAttribute("appId", appId);
    model.addAttribute("appVersion", appDef.getVersion());
    model.addAttribute("appDefinition", appDef);
    model.addAttribute("process", processDef);

    // check for permission
    if (!workflowManager.isUserInWhiteList(processDef.getId())) {
      return "client/app/processUnauthorized";
    }

    // extract form values from request
    FormData formData = new FormData();
    formData.setPrimaryKeyValue(recordId);
    formData = formService.retrieveFormDataFromRequest(formData, request);

    // get workflow variables
    Map<String, String> variableMap = AppUtil.retrieveVariableDataFromRequest(request);
    String formUrl =
        AppUtil.getRequestContextPath()
            + "/web/client/app/"
            + appId
            + "/"
            + appDef.getVersion()
            + "/process/"
            + processDefId
            + "/start";
    if (recordId != null) {
      formUrl += "?recordId=" + recordId;
    }
    PackageActivityForm startFormDef =
        appService.viewStartProcessForm(
            appId, appDef.getVersion().toString(), processDefId, formData, formUrl);
    WorkflowProcessResult result =
        appService.submitFormToStartProcess(
            appId, version, processDefId, formData, variableMap, recordId, formUrl);
    if (startFormDef != null
        && (startFormDef.getForm() != null
            || PackageActivityForm.ACTIVITY_FORM_TYPE_EXTERNAL.equals(startFormDef.getType()))) {
      if (result == null) {
        // validation error, get form
        Form startForm = startFormDef.getForm();

        // generate form HTML
        String formHtml = formService.retrieveFormErrorHtml(startForm, formData);
        String formJson = formService.generateElementJson(startForm);

        // show form
        model.addAttribute("form", startForm);
        model.addAttribute("formJson", formJson);
        model.addAttribute("formHtml", formHtml);
        model.addAttribute("activityForm", startFormDef);
        return "client/app/processFormStart";
      }
    } else {
      // start process - TODO: handle process linking
      result =
          workflowManager.processStart(
              processDefIdWithVersion, null, variableMap, null, recordId, false);
    }

    // set result
    if (result != null) {
      WorkflowProcess process = result.getProcess();
      model.addAttribute("process", process);

      // redirect to next activity if available
      Collection<WorkflowActivity> activities = result.getActivities();
      if (activities != null && !activities.isEmpty()) {
        WorkflowActivity nextActivity = activities.iterator().next();
        String assignmentUrl =
            "/web/client/app/"
                + appId
                + "/"
                + appDef.getVersion()
                + "/assignment/"
                + nextActivity.getId()
                + "?"
                + request.getQueryString();
        return "redirect:" + assignmentUrl;
      }
    }

    return "client/app/processStarted";
  }
  @RequestMapping("/form/embed")
  public String embedForm(
      ModelMap model,
      HttpServletRequest request,
      HttpServletResponse response,
      @RequestParam("_submitButtonLabel") String buttonLabel,
      @RequestParam("_json") String json,
      @RequestParam("_callback") String callback,
      @RequestParam("_setting") String callbackSetting,
      @RequestParam(required = false) String id,
      @RequestParam(value = "_a", required = false) String action)
      throws JSONException, UnsupportedEncodingException {
    FormData formData = new FormData();
    if (id != null && !id.isEmpty()) {
      formData.setPrimaryKeyValue(id);
    }
    Form form = formService.loadFormFromJson(json, formData);

    AppDefinition appDef = AppUtil.getCurrentAppDefinition();
    String appId = "";
    String appVersion = "";
    if (appDef != null) {
      appId = appDef.getAppId();
      appVersion = appDef.getVersion().toString();
    }
    String nonce = request.getParameter("_nonce");
    if (form == null
        || !SecurityUtil.verifyNonce(
            nonce,
            new String[] {"EmbedForm", appId, appVersion, form.getPropertyString("id"), nonce})) {
      response.setStatus(HttpServletResponse.SC_FORBIDDEN);
      return null;
    }

    if (callbackSetting == null || (callbackSetting != null && callbackSetting.isEmpty())) {
      callbackSetting = "{}";
    }

    form.setProperty(
        "url",
        "?_nonce="
            + URLEncoder.encode(nonce, "UTF-8")
            + "&_a=submit&_callback="
            + callback
            + "&_setting="
            + StringEscapeUtils.escapeHtml(callbackSetting)
            + "&_submitButtonLabel="
            + StringEscapeUtils.escapeHtml(buttonLabel));

    if (form != null) {
      // if id field not exist, automatically add an id hidden field
      Element idElement = FormUtil.findElement(FormUtil.PROPERTY_ID, form, formData);
      if (idElement == null) {
        Collection<Element> formElements = form.getChildren();
        idElement = new HiddenField();
        idElement.setProperty(FormUtil.PROPERTY_ID, FormUtil.PROPERTY_ID);
        idElement.setParent(form);
        formElements.add(idElement);
      }

      // create new section for buttons
      Section section = new Section();
      section.setProperty(FormUtil.PROPERTY_ID, "section-actions");
      Collection<Element> sectionChildren = new ArrayList<Element>();
      section.setChildren(sectionChildren);
      Collection<Element> formChildren = form.getChildren(formData);
      if (formChildren == null) {
        formChildren = new ArrayList<Element>();
      }
      formChildren.add(section);

      // add new horizontal column to section
      Column column = new Column();
      column.setProperty("horizontal", "true");
      Collection<Element> columnChildren = new ArrayList<Element>();
      column.setChildren(columnChildren);
      sectionChildren.add(column);

      Element hiddenField = (Element) pluginManager.getPlugin(HiddenField.class.getName());
      hiddenField.setProperty(FormUtil.PROPERTY_ID, "_json");
      hiddenField.setProperty(FormUtil.PROPERTY_VALUE, json);
      columnChildren.add((Element) hiddenField);

      Element submitButton = (Element) pluginManager.getPlugin(SubmitButton.class.getName());
      submitButton.setProperty(FormUtil.PROPERTY_ID, "submit");
      submitButton.setProperty("label", buttonLabel);
      columnChildren.add((Element) submitButton);
    }

    // generate form HTML
    String formHtml = null;

    if ("submit".equals(action)) {
      formData = formService.retrieveFormDataFromRequest(formData, request);
      formData = formService.executeFormActions(form, formData);

      // check for validation errors
      Map<String, String> errors = formData.getFormErrors();
      int errorCount = 0;
      if (!formData.getStay() && (errors == null || errors.isEmpty())) {
        // render normal template
        formHtml = formService.generateElementHtml(form, formData);

        // convert submitted
        JSONObject jsonResult = new JSONObject();

        // get binder of main form
        FormStoreBinder mainBinder = form.getStoreBinder();
        FormRowSet rows = formData.getStoreBinderData(mainBinder);

        for (FormRow row : rows) {
          for (Object o : row.keySet()) {
            jsonResult.accumulate(o.toString(), row.get(o));
          }
          Map<String, String> tempFilePathMap = row.getTempFilePathMap();
          if (tempFilePathMap != null && !tempFilePathMap.isEmpty()) {
            jsonResult.put(FormUtil.PROPERTY_TEMP_FILE_PATH, tempFilePathMap);
          }
        }

        model.addAttribute("jsonResult", StringEscapeUtils.escapeJavaScript(jsonResult.toString()));
      } else {
        // render error template
        formHtml = formService.generateElementErrorHtml(form, formData);
        errorCount = errors.size();
      }

      model.addAttribute("setting", callbackSetting);
      model.addAttribute("callback", callback);
      model.addAttribute("submitted", Boolean.TRUE);
      model.addAttribute("errorCount", errorCount);
      model.addAttribute("stay", formData.getStay());
    } else {
      formHtml = formService.retrieveFormHtml(form, formData);
    }

    model.addAttribute("formHtml", formHtml);

    if (request.getParameter("_mapp") != null) {
      response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
      response.setHeader("Access-Control-Allow-Credentials", "true");
      response.setHeader("Content-type", "application/xml");

      return "mapp/embedForm";
    } else {
      return "fbuilder/embedForm";
    }
  }
  @RequestMapping("/client/app/(*:appId)/(~:version)/process/(*:processDefId)")
  public String clientProcessView(
      HttpServletRequest request,
      ModelMap model,
      @RequestParam("appId") String appId,
      @RequestParam(required = false) String version,
      @RequestParam String processDefId,
      @RequestParam(required = false) String recordId,
      @RequestParam(required = false) String start) {

    // clean process def
    processDefId = WorkflowUtil.getProcessDefIdWithoutVersion(processDefId);

    AppDefinition appDef = appService.getAppDefinition(appId, version);
    WorkflowProcess processDef =
        appService.getWorkflowProcessForApp(appId, appDef.getVersion().toString(), processDefId);

    // check for permission
    if (!workflowManager.isUserInWhiteList(processDef.getId())) {
      return "client/app/processUnauthorized";
    }

    // set app and process details
    model.addAttribute("appId", appId);
    model.addAttribute("appVersion", appDef.getVersion());
    model.addAttribute("appDefinition", appDef);
    model.addAttribute("process", processDef);
    model.addAttribute("queryString", request.getQueryString());

    // check for start mapped form
    FormData formData = new FormData();
    formData.setPrimaryKeyValue(recordId);
    String formUrl =
        "/web/client/app/"
            + appId
            + "/"
            + appDef.getVersion()
            + "/process/"
            + processDefId
            + "/start";
    if (recordId != null) {
      formUrl += "?recordId=" + recordId;
    }
    String formUrlWithContextPath = AppUtil.getRequestContextPath() + formUrl;
    PackageActivityForm startFormDef =
        appService.viewStartProcessForm(
            appId, appDef.getVersion().toString(), processDefId, formData, formUrlWithContextPath);
    if (startFormDef != null && startFormDef.getForm() != null) {
      Form startForm = startFormDef.getForm();

      // generate form HTML
      String formHtml = formService.retrieveFormHtml(startForm, formData);
      String formJson = formService.generateElementJson(startForm);

      // show form
      model.addAttribute("form", startForm);
      model.addAttribute("formJson", formJson);
      model.addAttribute("formHtml", formHtml);
      return "client/app/processFormStart";
    } else {
      if (Boolean.valueOf(start).booleanValue()) {
        // redirect to start URL
        return "redirect:" + formUrl;
      } else {
        // empty start page
        return "client/app/processStart";
      }
    }
  }