/** Tests the workflow method. */
  @Test
  public void testSimpleParameters() throws IOException, ServletException {
    Action action = new Action();

    Map<String, String[]> values = new HashMap<String, String[]>();
    values.put("user.addresses['home'].city", array("Boulder"));
    values.put("user.age", array("32"));
    values.put("user.inches", array("tall"));
    values.put("user.age@dateFormat", array("MM/dd/yyyy"));
    values.put(
        "user.name",
        array("")); // This should be stripped out and the ExpressionEvaluator never called for it

    final HttpServletRequest request = EasyMock.createStrictMock(HttpServletRequest.class);
    EasyMock.expect(request.getParameterMap()).andReturn(values);
    EasyMock.replay(request);

    ExpressionEvaluator expressionEvaluator = EasyMock.createNiceMock(ExpressionEvaluator.class);
    expressionEvaluator.setValue(
        eq("user.addresses['home'].city"),
        same(action),
        aryEq(array("Boulder")),
        eq(new HashMap<String, String>()));
    expressionEvaluator.setValue(
        eq("user.age"), same(action), aryEq(array("32")), eq(map("dateFormat", "MM/dd/yyyy")));
    expressionEvaluator.setValue(
        eq("user.inches"), same(action), aryEq(array("tall")), eq(new HashMap<String, String>()));
    expectLastCall().andThrow(new ConversionException());
    EasyMock.replay(expressionEvaluator);

    ActionInvocation invocation = EasyMock.createStrictMock(ActionInvocation.class);
    EasyMock.expect(invocation.action()).andReturn(action);
    EasyMock.replay(invocation);

    ActionInvocationStore actionInvocationStore =
        EasyMock.createStrictMock(ActionInvocationStore.class);
    EasyMock.expect(actionInvocationStore.getCurrent()).andReturn(invocation);
    EasyMock.replay(actionInvocationStore);

    MessageStore messageStore = EasyMock.createStrictMock(MessageStore.class);
    messageStore.addConversionError(
        eq("user.inches"),
        eq("org.example.domain.Action"),
        eq(new HashMap<String, String>()),
        eq("tall"));
    EasyMock.replay(messageStore);

    WorkflowChain chain = EasyMock.createStrictMock(WorkflowChain.class);
    chain.continueWorkflow();
    EasyMock.replay(chain);

    DefaultParameterWorkflow workflow =
        new DefaultParameterWorkflow(
            request, actionInvocationStore, messageStore, expressionEvaluator);
    workflow.perform(chain);

    EasyMock.verify(
        request, expressionEvaluator, invocation, actionInvocationStore, messageStore, chain);
  }
Exemplo n.º 2
0
  /**
   * Determines the key. If the attribute contains a <code>keyExpr</code>, it is used against the
   * object to get the key. Otherwise, the object is just converted to a String.
   *
   * @param itemsValue The current value from the items collection/array/map used to determine the
   *     key.
   * @param key The key from a items Map or null if items is not a Map.
   * @param valueExpr The valueExpr attribute.
   * @return The key and never null. If the Object is null, this returns an empty String.
   */
  private Object makeValue(Object itemsValue, Object key, String valueExpr) {
    if (itemsValue == null) {
      return "";
    }

    if (valueExpr != null) {
      Object value = expressionEvaluator.getValue(valueExpr, itemsValue);
      if (value != null) {
        return value;
      }
    }

    if (key != null) {
      return key;
    }

    return itemsValue;
  }
Exemplo n.º 3
0
  /**
   * Handles the items and value. Here's the skinny:
   *
   * <ul>
   *   <li>If items is null, just inserts an empty Map in the attributes under <code>options</code>
   *   <li>If items is a Collection, loops over it and creates options. The selected state of the
   *       options are based on whether or not the value is a Collection or an array or null or just
   *       a plain Object. In the collection/array case, if the current items value is in the
   *       collection the option is selected. In the plain object case, if the current items value
   *       is equal it is selected. Otherwise, it isn't selected. Also, this handles the text and
   *       key using the expression attributes or the current items value.
   *   <li>If items is a Map, loops over it and creates options. The selected state of the options
   *       are based on whether or not the value is a Collection or an array or null or just a plain
   *       Object. In the collection/array case, if the current items value is in the collection the
   *       option is selected. In the plain object case, if the current items value is equal it is
   *       selected. Otherwise, it isn't selected. Also, this handles the text and key using the key
   *       from the items Map, the expression attributes or the current items value.
   * </ul>
   */
  @Override
  protected Map<String, Object> makeParameters() {
    Map<String, Object> parameters = super.makeParameters();
    Map<String, Option> options = new LinkedHashMap<String, Option>();

    // Handle the header option
    String headerValue = (String) attributes.remove("headerValue");
    String headerL10n = (String) attributes.remove("headerL10n");
    if (headerValue != null) {
      String message = "";
      if (headerL10n != null) {
        String bundleName = determineBundleName(attributes);
        if (bundleName == null) {
          throw new IllegalStateException(
              "Unable to locate the localized text for a header "
                  + "option in the select box named ["
                  + attributes.get("name")
                  + "]. If you "
                  + "don't have an action class for the URL, you must define the bundle used "
                  + "to localize the select using the bundle attribute.");
        }

        message = messageProvider.getMessage(bundleName, headerL10n);
      }

      options.put(headerValue, new Option(message, false));
    }

    // Grab the value
    Object beanValue =
        currentAction() != null
            ? expressionEvaluator.getValue((String) attributes.get("name"), currentAction())
            : null;

    // Next, let's handle the items here. I'll create a Map that contains a simple inner class
    // that determines if the option is selected or not. This will allow me to get the text
    // as well
    String valueExpr = (String) attributes.remove("valueExpr");
    String textExpr = (String) attributes.remove("textExpr");
    String l10nExpr = (String) attributes.remove("l10nExpr");
    Object items = attributes.remove("items");
    if (items != null) {
      if (items instanceof Collection) {
        Collection c = (Collection) items;
        for (Object o : c) {
          Object value = makeValue(o, null, valueExpr);
          options.put(
              value.toString(), makeOption(o, value, beanValue, attributes, textExpr, l10nExpr));
        }
      } else if (items instanceof Map) {
        Map<?, ?> m = (Map<?, ?>) items;
        for (Map.Entry entry : m.entrySet()) {
          Object value = makeValue(entry.getValue(), entry.getKey(), valueExpr);
          Option option =
              makeOption(entry.getValue(), value, beanValue, attributes, textExpr, l10nExpr);
          options.put(value.toString(), option);
        }
      } else if (items.getClass().isArray()) {
        int length = Array.getLength(items);
        for (int i = 0; i < length; i++) {
          Object itemsValue = Array.get(items, i);
          Object value = makeValue(itemsValue, null, valueExpr);
          Option option = makeOption(itemsValue, value, beanValue, attributes, textExpr, l10nExpr);
          options.put(value.toString(), option);
        }
      }
    }

    parameters.put("options", options);
    return parameters;
  }
Exemplo n.º 4
0
  /**
   * Makes an option. If the attributes contains a <code>l10nExpr</code>, it is used with the Object
   * to get a message from the {@link org.jcatapult.l10n.MessageProvider}. If that doesn't exist and
   * a <code>textExpr</code> does, it is used to get the text for the option from the object.
   * Otherwise, the object is converted to a String for the text. Also, if the object exists in the
   * given Collection the option is set to selected.
   *
   * @param itemsValue The current value from the items collection/array/map.
   * @param value The value of the option. This could have been from the items Map or the valueExpr
   *     evaluation.
   * @param beanValue The value from the bean, used to determine selected state.
   * @param attributes used to get the text for the option.
   * @param textExpr The textExpr attribute.
   * @param l10nExpr The l10nExpr attribute.
   * @return The option and never null.
   */
  private Option makeOption(
      Object itemsValue,
      Object value,
      Object beanValue,
      Map<String, Object> attributes,
      String textExpr,
      String l10nExpr) {
    if (itemsValue == null) {
      return new Option("", false);
    }

    String text = null;
    if (l10nExpr != null) {
      String bundleName = determineBundleName(attributes);
      if (bundleName == null) {
        throw new IllegalStateException(
            "Unable to locate the localized text for an option "
                + "in the select input for the field named ["
                + attributes.get("name")
                + "]. If "
                + "you don't have an action class for the URL, you must define the bundle used "
                + "to localize the select using the bundle attribute.");
      }

      Object l10nKey = expressionEvaluator.getValue(l10nExpr, itemsValue);
      if (l10nKey != null) {
        text = messageProvider.getMessage(bundleName, l10nKey.toString());
      }
    }

    if (text == null) {
      if (textExpr != null) {
        text = expressionEvaluator.getValue(textExpr, itemsValue).toString();
      }
    }

    if (text == null) {
      text = itemsValue.toString();
    }

    if (beanValue == null) {
      return new Option(text, false);
    }

    if (beanValue instanceof Collection) {
      return new Option(text, ((Collection) beanValue).contains(value));
    }

    if (beanValue.getClass().isArray()) {
      int length = Array.getLength(beanValue);
      for (int i = 0; i < length; i++) {
        Object arrayValue = Array.get(beanValue, i);
        if (arrayValue != null && arrayValue.equals(value)) {
          return new Option(text, true);
        }
      }
    }

    // FreeMarker wraps all maps into Map<String, Object> and does it incorrectly at that.
    // This is a hack to ensure that when keys are compared, it works for Maps. Most of the time
    // the class of the value from the bean and the value for the ListInput will be the same,
    // such as Integer.
    boolean equal;
    if (value != null) {
      if (beanValue.getClass().isInstance(value)) {
        equal = beanValue.equals(value);
      } else {
        equal = beanValue.toString().equals(value.toString());
      }
    } else {
      if (beanValue.getClass().isInstance(itemsValue)) {
        equal = beanValue.equals(itemsValue);
      } else {
        equal = beanValue.toString().equals(itemsValue.toString());
      }
    }

    return new Option(text, equal);
  }