static {
   if (ClassUtils.niceForName("org.richfaces.component.UISuggestionBox") != null) {
     VERSION_SPECIFIC_WIDGET_BUILDER = new RichFaces3Support();
   } else {
     VERSION_SPECIFIC_WIDGET_BUILDER = new RichFaces4Support();
   }
 }
  public UIComponent buildWidget(
      String elementName, Map<String, String> attributes, UIMetawidget metawidget) {

    // Not for Tomahawk?

    if (TRUE.equals(attributes.get(HIDDEN))) {
      return null;
    }

    if (attributes.containsKey(FACES_LOOKUP) || attributes.containsKey(LOOKUP)) {
      return null;
    }

    Application application = FacesContext.getCurrentInstance().getApplication();
    String type = WidgetBuilderUtils.getActualClassOrType(attributes);

    if (type == null) {
      return null;
    }

    Class<?> clazz = ClassUtils.niceForName(type);

    if (clazz == null) {
      return null;
    }

    // HtmlInputFileUpload

    if (UploadedFile.class.isAssignableFrom(clazz)) {
      return application.createComponent("org.apache.myfaces.HtmlInputFileUpload");
    }

    // Not for Tomahawk

    return null;
  }
  @Override
  public StaticJavaWidget buildWidget(
      String elementName, Map<String, String> attributes, StaticJavaMetawidget metawidget) {
    // Drill down

    if (ENTITY.equals(elementName)) {
      return null;
    }

    // Suppress

    if (TRUE.equals(attributes.get(HIDDEN))) {
      return new StaticJavaStub();
    }

    String type = WidgetBuilderUtils.getActualClassOrType(attributes);
    Class<?> clazz = ClassUtils.niceForName(type);
    String name = attributes.get(NAME);

    // String

    if (String.class.equals(clazz)) {
      StaticJavaStub toReturn = new StaticJavaStub();
      toReturn
          .getChildren()
          .add(
              new JavaStatement(
                  "String " + name + " = this.search.get" + StringUtils.capitalize(name) + "()"));
      JavaStatement ifNotEmpty =
          new JavaStatement("if (" + name + " != null && !\"\".equals(" + name + "))");
      ifNotEmpty
          .getChildren()
          .add(
              new JavaStatement(
                  "predicatesList.add(builder.like(root.<String>get(\""
                      + name
                      + "\"), '%' + "
                      + name
                      + " + '%'))"));
      toReturn.getChildren().add(ifNotEmpty);
      return toReturn;
    }

    // int

    if (int.class.equals(clazz)) {
      StaticJavaStub toReturn = new StaticJavaStub();
      toReturn
          .getChildren()
          .add(
              new JavaStatement(
                  "int " + name + " = this.search.get" + StringUtils.capitalize(name) + "()"));
      JavaStatement ifNotEmpty = new JavaStatement("if (" + name + " != 0)");
      ifNotEmpty
          .getChildren()
          .add(
              new JavaStatement(
                  "predicatesList.add(builder.equal(root.get(\"" + name + "\")," + name + "))"));
      toReturn.getChildren().add(ifNotEmpty);
      return toReturn;
    }

    // Lookup

    if (attributes.containsKey(FACES_LOOKUP)) {
      StaticJavaStub toReturn = new StaticJavaStub();
      JavaStatement getValue =
          new JavaStatement(
              ClassUtils.getSimpleName(type)
                  + " "
                  + name
                  + " = this.search.get"
                  + StringUtils.capitalize(name)
                  + "()");
      getValue.putImport(type);
      toReturn.getChildren().add(getValue);
      JavaStatement ifNotEmpty =
          new JavaStatement("if (" + name + " != null && " + name + ".getId() != null)");
      ifNotEmpty
          .getChildren()
          .add(
              new JavaStatement(
                  "predicatesList.add(builder.equal(root.get(\"" + name + "\")," + name + "))"));
      toReturn.getChildren().add(ifNotEmpty);
      return toReturn;
    }

    // We tried searching against N_TO_MANY relationships, but had the following problems:
    //
    // 1. Difficult to make JPA Criteria Builder search for 'a Set having all of the following
    // items'. For 'a Set
    // having the following item' can do:
    // predicatesList.add(root.join("customers").in(this.search.getCustomer()));
    // 2. Cumbersome to have a new class for this.search that only has a single Customer, as opposed
    // to a Set
    // 3. Difficult to make JSF's h:selectOne* bind to a Set
    // 4. Difficult to make JSF's h:selectMany* appear as a single item dropdown
    //
    // So we've left it out for now

    return new StaticJavaStub();
  }
  public Converter getConverter(ValueHolder valueHolder, Map<String, String> attributes) {

    // Use existing Converter (if any)

    Converter converter = valueHolder.getConverter();

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

    // Create from id

    FacesContext context = FacesContext.getCurrentInstance();
    String converterId = attributes.get(FACES_CONVERTER);

    if (converterId != null) {

      converter = context.getApplication().createConverter(converterId);

    } else if (valueHolder instanceof UISelectOne || valueHolder instanceof UISelectMany) {

      // Create from parameterized type (eg. a Date converter for List<Date>)

      String parameterizedType = WidgetBuilderUtils.getComponentType(attributes);

      if (parameterizedType != null) {
        Class<?> parameterizedClass = ClassUtils.niceForName(parameterizedType);

        // The parameterized type might be null, or might not be concrete
        // enough to be instantiatable (eg. List<? extends Foo>)

        if (parameterizedClass != null) {
          converter = context.getApplication().createConverter(parameterizedClass);
        }
      }

    } else {

      // Create implicit converters
      //
      // JSF does not appear to implicitly hook up DateTimeConverters without either an
      // explicit f:convertDateTime tag or a registered java.util.Date converter. Adding one
      // fixes both POSTback and display of read-only dates (otherwise JSF uses Date.toString)
      //
      // JSF *does* appear to implicitly hook up NumberConverters.

      String type = attributes.get(TYPE);

      if (type != null) {

        Class<?> clazz = ClassUtils.niceForName(type);

        if (clazz != null) {

          if (clazz.isAssignableFrom(Date.class)) {
            converter = getDateTimeConverter(converter);
          }
        }
      }
    }

    // Support for DateTimeConverter

    if (attributes.containsKey(DATE_STYLE)) {
      converter = getDateTimeConverter(converter);
      ((DateTimeConverter) converter).setDateStyle(attributes.get(DATE_STYLE));
    }

    if (attributes.containsKey(DATETIME_PATTERN)) {
      converter = getDateTimeConverter(converter);
      ((DateTimeConverter) converter).setPattern(attributes.get(DATETIME_PATTERN));
    }

    if (attributes.containsKey(TIME_STYLE)) {
      converter = getDateTimeConverter(converter);
      ((DateTimeConverter) converter).setTimeStyle(attributes.get(TIME_STYLE));
    }

    if (attributes.containsKey(TIME_ZONE)) {
      converter = getDateTimeConverter(converter);
      ((DateTimeConverter) converter).setTimeZone(TimeZone.getTimeZone(attributes.get(TIME_ZONE)));
    }

    if (attributes.containsKey(DATETIME_TYPE)) {
      converter = getDateTimeConverter(converter);
      ((DateTimeConverter) converter).setType(attributes.get(DATETIME_TYPE));
    }

    // Support for NumberConverter

    if (attributes.containsKey(CURRENCY_CODE)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter).setCurrencyCode(attributes.get(CURRENCY_CODE));
    }

    if (attributes.containsKey(CURRENCY_SYMBOL)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter).setCurrencySymbol(attributes.get(CURRENCY_SYMBOL));
    }

    if (attributes.containsKey(NUMBER_USES_GROUPING_SEPARATORS)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter)
          .setGroupingUsed(Boolean.parseBoolean(attributes.get(NUMBER_USES_GROUPING_SEPARATORS)));
    }

    if (attributes.containsKey(MINIMUM_INTEGER_DIGITS)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter)
          .setMinIntegerDigits(Integer.parseInt(attributes.get(MINIMUM_INTEGER_DIGITS)));
    }

    if (attributes.containsKey(MAXIMUM_INTEGER_DIGITS)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter)
          .setMaxIntegerDigits(Integer.parseInt(attributes.get(MAXIMUM_INTEGER_DIGITS)));
    }

    if (attributes.containsKey(MINIMUM_FRACTIONAL_DIGITS)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter)
          .setMinFractionDigits(Integer.parseInt(attributes.get(MINIMUM_FRACTIONAL_DIGITS)));
    }

    if (attributes.containsKey(MAXIMUM_FRACTIONAL_DIGITS)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter)
          .setMaxFractionDigits(Integer.parseInt(attributes.get(MAXIMUM_FRACTIONAL_DIGITS)));
    }

    if (attributes.containsKey(NUMBER_PATTERN)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter).setPattern(attributes.get(NUMBER_PATTERN));
    }

    if (attributes.containsKey(NUMBER_TYPE)) {
      converter = getNumberConverter(converter);
      ((NumberConverter) converter).setType(attributes.get(NUMBER_TYPE));
    }

    // Locale (applies to both DateTimeConverter and NumberConverter)

    if (attributes.containsKey(LOCALE)) {
      if (converter instanceof NumberConverter) {
        ((NumberConverter) converter).setLocale(new Locale(attributes.get(LOCALE)));
      } else {
        converter = getDateTimeConverter(converter);
        ((DateTimeConverter) converter).setLocale(new Locale(attributes.get(LOCALE)));
      }
    }

    // Return it

    return converter;
  }