public BeanDefinition parse(Element element, ParserContext parserContext) {

    final XmlReaderContext readerContext = parserContext.getReaderContext();
    final ClassLoader beanClassLoader =
        readerContext.getBeanClassLoader() != null
            ? readerContext.getBeanClassLoader()
            : Thread.currentThread().getContextClassLoader();

    String[] basePackages =
        StringUtils.commaDelimitedListToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE));

    String dataSourceId = element.getAttribute(DATA_SOURCE_ATTRIBUTE);
    if (!StringUtils.hasText(dataSourceId)) {
      throw new BeanDefinitionParsingException(
          new Problem(
              "Attribute ["
                  + DATA_SOURCE_ATTRIBUTE
                  + "] of tag <gorm:sessionFactory> must be specified!",
              new Location(readerContext.getResource())));
    }

    // Actually scan for bean definitions and register them.
    BeanDefinitionRegistry targetRegistry = parserContext.getRegistry();

    // setup the GrailsApplication instance
    parseGrailsApplication(element, parserContext, readerContext, beanClassLoader, basePackages);

    GenericBeanDefinition postProccessingBeanDef = new GenericBeanDefinition();
    postProccessingBeanDef.setBeanClass(GORMEnhancingBeanPostProcessor.class);

    targetRegistry.registerBeanDefinition("gormEnhancingPostProcessor", postProccessingBeanDef);

    return parseSessionFactory(element, dataSourceId, targetRegistry, parserContext);
  }
	/**
	 * Create a List of default strategy objects for the given strategy interface.
	 * <p>The default implementation uses the "DispatcherPortlet.properties" file
	 * (in the same package as the DispatcherPortlet class) to determine the class names.
	 * It instantiates the strategy objects and satisifies ApplicationContextAware
	 * if necessary.
	 * @param context the current Portlet ApplicationContext
	 * @param strategyInterface the strategy interface
	 * @return the List of corresponding strategy objects
	 */
	@SuppressWarnings("unchecked")
	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<T>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherPortlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				}
				catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherPortlet's default strategy class [" + className +
									"] for interface [" + key + "]", ex);
				}
				catch (LinkageError err) {
					throw new BeanInitializationException(
							"Error loading DispatcherPortlet's default strategy class [" + className +
									"] for interface [" + key + "]: problem with class file or dependent class", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<T>();
		}
	}
 @Override
 public void init() {
   String rolesPropertyValue = getContext().getProperty(ROLES);
   if (rolesPropertyValue != null) {
     this.roles = StringUtils.commaDelimitedListToStringArray(rolesPropertyValue);
   }
 }
Пример #4
0
 /**
  * Sets the job input path.
  *
  * @param inputPath job input path.
  */
 public void setInputPath(String... inputPath) {
   // handle , strings here instead of the namespace to allow SpEL to kick in (if needed)
   if (inputPath != null && inputPath.length == 1) {
     inputPath = StringUtils.commaDelimitedListToStringArray(inputPath[0]);
   }
   this.inputPaths = Arrays.asList(inputPath);
 }
 private void addNoRollbackRuleAttributesTo(
     List<RollbackRuleAttribute> rollbackRules, String noRollbackForValue) {
   String[] exceptionTypeNames = StringUtils.commaDelimitedListToStringArray(noRollbackForValue);
   for (String typeName : exceptionTypeNames) {
     rollbackRules.add(new NoRollbackRuleAttribute(StringUtils.trimWhitespace(typeName)));
   }
 }
Пример #6
0
  /**
   * 返回给定部门的部门编号
   *
   * @param parentDept 给定部门
   */
  public String getSerialNo(final Dept dept) {
    Assert.notNull(dept, "The given Dept must not be null.");
    String serialNo = null;
    if (dept.getParentDept() != null) { // 如果有上级部门
      List serialNos =
          getDao()
              .query(
                  "select d.serialNo from Dept d "
                      + "where d.parentDept = ? order by d.serialNo desc",
                  dept.getParentDept());
      if (serialNos == null || serialNos.isEmpty()) { // 如果同级部门
        serialNo = buildFirstSerialNo(dept.getParentDept());
      } else { // 有同级级部门
        String maxSerialNo = (String) serialNos.get(0); // 同级部门最大编号
        // 找出同级部门最大编号的最后两位
        final String[] splited =
            org.springframework.util.StringUtils.commaDelimitedListToStringArray(maxSerialNo);
        if (splited == null || splited.length == 0) { // 同级部门没有编号
          serialNo = buildFirstSerialNo(dept.getParentDept());
        } else { // 计算当前部门编号
          Integer serial = StringUtil.getNumFromSerial(splited[splited.length - 1]);
          serialNo =
              dept.getParentDept().getSerialNo() + "," + StringUtil.zeroPadding((serial + 1), 2);
        }
      }
    } else { // 如果没有上级部门
      serialNo = this.getTopDeptSerialNo();
      dept.setSerialNo(serialNo);
    }

    logger.debug("Create serial No." + serialNo);
    return serialNo;
  }
 public long[] getHeartbeat() {
   String rawValue = getFirstNativeHeader(STOMP_HEARTBEAT_HEADER);
   if (!StringUtils.hasText(rawValue)) {
     return Arrays.copyOf(DEFAULT_HEARTBEAT, 2);
   }
   String[] rawValues = StringUtils.commaDelimitedListToStringArray(rawValue);
   return new long[] {Long.valueOf(rawValues[0]), Long.valueOf(rawValues[1])};
 }
 private void applySpringProfiles(
     ConfigurableEnvironment environment, ServletContext servletContext) {
   if (environment.containsProperty("spring_profiles")) {
     String profiles = environment.getProperty("spring_profiles");
     servletContext.log("Setting active profiles: " + profiles);
     environment.setActiveProfiles(StringUtils.commaDelimitedListToStringArray(profiles));
   }
 }
Пример #9
0
 /**
  * Specify implicit collection fields, as a Map consisting of {@code Class} instances mapped to
  * comma separated collection field names.
  *
  * @see XStream#addImplicitCollection(Class, String)
  */
 public void setImplicitCollections(Map<Class<?>, String> implicitCollections) {
   for (Map.Entry<Class<?>, String> entry : implicitCollections.entrySet()) {
     String[] collectionFields = StringUtils.commaDelimitedListToStringArray(entry.getValue());
     for (String collectionField : collectionFields) {
       getXStream().addImplicitCollection(entry.getKey(), collectionField);
     }
   }
 }
Пример #10
0
 /**
  * Specify omitted fields, as a Map consisting of {@code Class} instances mapped to comma
  * separated field names.
  *
  * @see XStream#omitField(Class, String)
  */
 public void setOmittedFields(Map<Class<?>, String> omittedFields) {
   for (Map.Entry<Class<?>, String> entry : omittedFields.entrySet()) {
     String[] fields = StringUtils.commaDelimitedListToStringArray(entry.getValue());
     for (String field : fields) {
       getXStream().omitField(entry.getKey(), field);
     }
   }
 }
 private Set<String> asResolvedSet(String value, String fallback) {
   List<String> list =
       Arrays.asList(
           StringUtils.commaDelimitedListToStringArray(
               value != null ? this.environment.resolvePlaceholders(value) : fallback));
   Collections.reverse(list);
   return new LinkedHashSet<String>(list);
 }
Пример #12
0
	/**
	 * Get the heartbeat header.
	 */
	public long[] getHeartbeat() {
		String rawValue = getFirst(HEARTBEAT);
		if (!StringUtils.hasText(rawValue)) {
			return null;
		}
		String[] rawValues = StringUtils.commaDelimitedListToStringArray(rawValue);
		return new long[] {Long.valueOf(rawValues[0]), Long.valueOf(rawValues[1])};
	}
Пример #13
0
  @CacheEvict(value = "users", allEntries = true)
  public List<UserInvitation> inviteUsers(
      UserInvitationCreateRequest form, BindingResult result, AuthorizedUser authorizedUser)
      throws MessagingException {
    String[] recipients = StringUtils.commaDelimitedListToStringArray(form.getInvitees());

    LocalDateTime now = LocalDateTime.now();

    List<UserInvitation> invitations = new ArrayList<>();
    for (String recipient : recipients) {
      UserInvitation invitation = new UserInvitation();
      invitation.setEmail(recipient);
      invitation.setMessage(form.getMessage());
      invitation.setExpiredAt(now.plusHours(72));
      invitation.setCreatedAt(now);
      invitation.setCreatedBy(authorizedUser.toString());
      invitation.setUpdatedAt(now);
      invitation.setUpdatedBy(authorizedUser.toString());
      invitation = userInvitationRepository.saveAndFlush(invitation);
      invitations.add(invitation);
    }

    Blog blog = blogService.readBlogById(Blog.DEFAULT_ID);
    for (UserInvitation invitation : invitations) {
      String websiteTitle = blog.getTitle(LocaleContextHolder.getLocale().getLanguage());
      String signupLink =
          ServletUriComponentsBuilder.fromCurrentContextPath()
              .path("/_admin/signup")
              .queryParam("token", invitation.getToken())
              .buildAndExpand()
              .toString();

      final Context ctx = new Context(LocaleContextHolder.getLocale());
      ctx.setVariable("websiteTitle", websiteTitle);
      ctx.setVariable("authorizedUser", authorizedUser);
      ctx.setVariable("signupLink", signupLink);
      ctx.setVariable("invitation", invitation);

      final MimeMessage mimeMessage = mailSender.createMimeMessage();
      final MimeMessageHelper message =
          new MimeMessageHelper(mimeMessage, true, "UTF-8"); // true = multipart
      message.setSubject(
          MessageFormat.format(
              messageSourceAccessor.getMessage(
                  "InvitationMessageTitle", LocaleContextHolder.getLocale()),
              authorizedUser.toString(),
              websiteTitle));
      message.setFrom(authorizedUser.getEmail());
      message.setTo(invitation.getEmail());

      final String htmlContent = templateEngine.process("user-invite", ctx);
      message.setText(htmlContent, true); // true = isHtml

      mailSender.send(mimeMessage);
    }

    return invitations;
  }
Пример #14
0
 public static Remembered fromCookie(Cookie c) {
   try {
     String[] values = StringUtils.commaDelimitedListToStringArray(c.getValue());
     return new Remembered(
         values[0], values[1], new SimpleDateFormat(EXPIRY_FORMAT).parse(values[2]));
   } catch (ParseException ex) {
     return null;
   }
 }
 /**
  * Set the mappings of bean keys to a comma-separated list of method names. The method names are
  * <b>ignored</b> when creating the management interface.
  *
  * <p>The property key should match the bean key and the property value should match the list of
  * method names. When searching for method names to ignore for a bean, Spring will check these
  * mappings first.
  */
 public void setIgnoredMethodMappings(Properties mappings) {
   this.ignoredMethodsMappings = new HashMap();
   for (Enumeration en = mappings.keys(); en.hasMoreElements(); ) {
     String beanKey = (String) en.nextElement();
     String[] methodNames =
         StringUtils.commaDelimitedListToStringArray(mappings.getProperty(beanKey));
     this.ignoredMethodsMappings.put(beanKey, new HashSet(Arrays.asList(methodNames)));
   }
 }
Пример #16
0
 @Override
 protected void respond(AjaxRequestTarget target) {
   Request request = RequestCycle.get().getRequest();
   String items = request.getParameter("items");
   @SuppressWarnings("unchecked")
   List<T> modelList = (List<T>) SortableList.this.getDefaultModelObject();
   modelList.clear();
   for (String markupId : StringUtils.commaDelimitedListToStringArray(items)) {
     if (org.apache.commons.lang.StringUtils.isNotBlank(markupId))
       modelList.add(itemByMarkupId.get(markupId));
   }
 }
 @Override
 public Set<String> deserialize(JsonParser jp, DeserializationContext ctxt)
     throws IOException, JsonProcessingException {
   JsonToken token = jp.getCurrentToken();
   if (token.isScalarValue()) {
     String list = jp.getText();
     list = list.replaceAll("\\s+", ",");
     return new LinkedHashSet<String>(
         Arrays.asList(StringUtils.commaDelimitedListToStringArray(list)));
   }
   return jp.readValueAs(new TypeReference<Set<String>>() {});
 }
  /**
   * Constructor taking a string of CSV file extensions
   *
   * @param configuredFileSuffixes
   */
  public ProjectScanningBeansConfigLocator(String configuredFileSuffixes) {
    configuredFilePatterns = new ConcurrentSkipListSet<String>();
    configuredFileExtensions = new ConcurrentSkipListSet<String>();

    for (String filePattern : StringUtils.commaDelimitedListToStringArray(configuredFileSuffixes)) {
      filePattern = filePattern.trim();
      int ix = filePattern.lastIndexOf('.');
      if (ix != -1) {
        configuredFileExtensions.add(filePattern.substring(ix + 1));
      } else {
        configuredFileExtensions.add(filePattern);
      }
      configuredFilePatterns.add(ALLOWED_FILE_PATTERN + filePattern);
    }
  }
 private List<RedisNode> createSentinels(Sentinel sentinel) {
   List<RedisNode> sentinels = new ArrayList<RedisNode>();
   String nodes = sentinel.getNodes();
   for (String node : StringUtils.commaDelimitedListToStringArray(nodes)) {
     try {
       String[] parts = StringUtils.split(node, ":");
       Assert.state(parts.length == 2, "Must be defined as 'host:port'");
       sentinels.add(new RedisNode(parts[0], Integer.valueOf(parts[1])));
     } catch (RuntimeException ex) {
       throw new IllegalStateException(
           "Invalid redis sentinel " + "property '" + node + "'", ex);
     }
   }
   return sentinels;
 }
 /**
  * Initialize a Velocity resource loader for the given VelocityEngine: either a standard Velocity
  * FileResourceLoader or a SpringResourceLoader.
  *
  * <p>Called by {@code createVelocityEngine()}.
  *
  * @param velocityEngine the VelocityEngine to configure
  * @param resourceLoaderPath the path to load Velocity resources from
  * @see org.apache.velocity.runtime.resource.loader.FileResourceLoader
  * @see SpringResourceLoader
  * @see #initSpringResourceLoader
  * @see #createVelocityEngine()
  */
 protected void initVelocityResourceLoader(
     VelocityEngine velocityEngine, String resourceLoaderPath) {
   if (isPreferFileSystemAccess()) {
     // Try to load via the file system, fall back to SpringResourceLoader
     // (for hot detection of template changes, if possible).
     try {
       StringBuilder resolvedPath = new StringBuilder();
       String[] paths = StringUtils.commaDelimitedListToStringArray(resourceLoaderPath);
       for (int i = 0; i < paths.length; i++) {
         String path = paths[i];
         Resource resource = getResourceLoader().getResource(path);
         File file = resource.getFile(); // will fail if not resolvable in the file system
         if (logger.isDebugEnabled()) {
           logger.debug(
               "Resource loader path ["
                   + path
                   + "] resolved to file ["
                   + file.getAbsolutePath()
                   + "]");
         }
         resolvedPath.append(file.getAbsolutePath());
         if (i < paths.length - 1) {
           resolvedPath.append(',');
         }
       }
       velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "file");
       velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
       velocityEngine.setProperty(
           RuntimeConstants.FILE_RESOURCE_LOADER_PATH, resolvedPath.toString());
     } catch (IOException ex) {
       if (logger.isDebugEnabled()) {
         logger.debug(
             "Cannot resolve resource loader path ["
                 + resourceLoaderPath
                 + "] to [java.io.File]: using SpringResourceLoader",
             ex);
       }
       initSpringResourceLoader(velocityEngine, resourceLoaderPath);
     }
   } else {
     // Always load via SpringResourceLoader
     // (without hot detection of template changes).
     if (logger.isDebugEnabled()) {
       logger.debug("File system access not preferred: using SpringResourceLoader");
     }
     initSpringResourceLoader(velocityEngine, resourceLoaderPath);
   }
 }
Пример #21
0
  private Set<GrantedAuthority> parseAuthoritiesString(String authorizationsString) {
    final Set<GrantedAuthority> requiredAuthorities = new HashSet<GrantedAuthority>();
    final String[] authorities = StringUtils.commaDelimitedListToStringArray(authorizationsString);

    for (String authority : authorities) {
      // Remove the role's whitespace characters without depending on JDK 1.4+
      // Includes space, tab, new line, carriage return and form feed.
      String role = StringUtils.replace(authority, " ", "");
      role = StringUtils.replace(role, "\t", "");
      role = StringUtils.replace(role, "\r", "");
      role = StringUtils.replace(role, "\n", "");
      role = StringUtils.replace(role, "\f", "");

      requiredAuthorities.add(new GrantedAuthorityImpl(role));
    }

    return requiredAuthorities;
  }
Пример #22
0
  /**
   * 根据上级部门和当前部门的前一个编号,获得当前部门编号的数字表示 , 用于重置所有部门编号:<br>
   * 首先根据上级部门编号,计算同级部门的第一个编号,以后便再此基础上 +1即可。
   */
  private Integer getSerial(Dept dept, final Integer preSerial) {
    Integer serial = null;
    if (preSerial == null) {
      String serialNo = getSerialNo(dept);
      if (StringUtils.isNotBlank(serialNo)) {
        String[] splits =
            org.springframework.util.StringUtils.commaDelimitedListToStringArray(serialNo);
        if (splits != null && splits.length > 0) {
          serial = StringUtil.getNumFromSerial(splits[splits.length - 1]);
        } else {
          serial = 0;
        }
      }
    } else {
      serial = preSerial + 1;
    }

    return serial;
  }
Пример #23
0
 private Resource getResource(
     ServletContext servletContext,
     ConfigurableWebApplicationContext applicationContext,
     String locations) {
   Resource resource = null;
   String[] configFileLocations =
       locations == null
           ? DEFAULT_PROFILE_CONFIG_FILE_LOCATIONS
           : StringUtils.commaDelimitedListToStringArray(locations);
   for (String location : configFileLocations) {
     location = applicationContext.getEnvironment().resolvePlaceholders(location);
     servletContext.log("Testing for YAML resources at: " + location);
     resource = applicationContext.getResource(location);
     if (resource != null && resource.exists()) {
       break;
     }
   }
   return resource;
 }
  protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
    logger.debug("抽取webresdb中的记录.........");
    RdbmsEntryHolder rsh = new RdbmsEntryHolder();
    // 设置受保护业务
    rsh.setMethodName(rs.getString("protect").trim());
    //    	设置角色
    rsh.setRoles(rs.getString("roles").trim());
    // 属于哪个项目类别
    rsh.setOwner(rs.getString("owner").trim());
    // 设置描述
    rsh.setRemark(rs.getString("remark").trim());

    ConfigAttributeDefinition cad = new ConfigAttributeDefinition();

    String[] tokens = StringUtils.commaDelimitedListToStringArray(rs.getString("roles").trim());
    for (int i = 0; i < tokens.length; ++i) cad.addConfigAttribute(new SecurityConfig(tokens[i]));

    // 设置角色集合
    rsh.setCad(cad);

    return rsh;
  }
 public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
   String factoryClassName = factoryClass.getName();
   try {
     List<String> result = new ArrayList<String>();
     Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
     while (urls.hasMoreElements()) {
       URL url = urls.nextElement();
       Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
       String factoryClassNames = properties.getProperty(factoryClassName);
       result.addAll(
           Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
     }
     return result;
   } catch (IOException ex) {
     throw new IllegalArgumentException(
         "Unable to load ["
             + factoryClass.getName()
             + "] factories from location ["
             + FACTORIES_RESOURCE_LOCATION
             + "]",
         ex);
   }
 }
 @Override
 public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
   if (source == null) {
     return null;
   }
   String string = (String) source;
   String[] fields = StringUtils.commaDelimitedListToStringArray(string);
   Collection<Object> target =
       CollectionFactory.createCollection(targetType.getType(), fields.length);
   if (targetType.getElementTypeDescriptor() == null) {
     for (String field : fields) {
       target.add(field.trim());
     }
   } else {
     for (String field : fields) {
       Object targetElement =
           this.conversionService.convert(
               field.trim(), sourceType, targetType.getElementTypeDescriptor());
       target.add(targetElement);
     }
   }
   return target;
 }
  /**
   * Convert the value to the required type (if necessary from a String), for the specified
   * property.
   *
   * @param propertyName name of the property
   * @param oldValue the previous value, if available (may be <code>null</code>)
   * @param newValue the proposed new value
   * @param requiredType the type we must convert to (or <code>null</code> if not known, for example
   *     in case of a collection element)
   * @param typeDescriptor the descriptor for the target property or field
   * @return the new value, possibly the result of type conversion
   * @throws IllegalArgumentException if type conversion failed
   */
  @SuppressWarnings("unchecked")
  public <T> T convertIfNecessary(
      String propertyName,
      Object oldValue,
      Object newValue,
      Class<T> requiredType,
      TypeDescriptor typeDescriptor)
      throws IllegalArgumentException {

    Object convertedValue = newValue;

    // Custom editor for this type?
    PropertyEditor editor =
        this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);

    // No custom editor but custom ConversionService specified?
    ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
    if (editor == null && conversionService != null && convertedValue != null) {
      TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(convertedValue);
      TypeDescriptor targetTypeDesc = typeDescriptor.forElementType(requiredType);
      if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
        return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
      }
    }

    // Value not of required type?
    if (editor != null
        || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
      if (requiredType != null
          && Collection.class.isAssignableFrom(requiredType)
          && convertedValue instanceof String
          && typeDescriptor.getMethodParameter() != null) {
        Class elemType =
            GenericCollectionTypeResolver.getCollectionParameterType(
                typeDescriptor.getMethodParameter());
        if (elemType != null && Enum.class.isAssignableFrom(elemType)) {
          convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
        }
      }
      if (editor == null) {
        editor = findDefaultEditor(requiredType, typeDescriptor);
      }
      convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
    }

    if (requiredType != null) {
      // Try to apply some standard type conversion rules if appropriate.

      if (convertedValue != null) {
        if (requiredType.isArray()) {
          // Array required -> apply appropriate conversion of elements.
          if (convertedValue instanceof String
              && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
            convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
          }
          return (T)
              convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
        } else if (convertedValue instanceof Collection) {
          // Convert elements to target type, if determined.
          convertedValue =
              convertToTypedCollection(
                  (Collection) convertedValue, propertyName, requiredType, typeDescriptor);
        } else if (convertedValue instanceof Map) {
          // Convert keys and values to respective target type, if determined.
          convertedValue =
              convertToTypedMap((Map) convertedValue, propertyName, requiredType, typeDescriptor);
        }
        if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
          convertedValue = Array.get(convertedValue, 0);
        }
        if (String.class.equals(requiredType)
            && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
          // We can stringify any primitive value...
          return (T) convertedValue.toString();
        } else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
          if (!requiredType.isInterface() && !requiredType.isEnum()) {
            try {
              Constructor strCtor = requiredType.getConstructor(String.class);
              return (T) BeanUtils.instantiateClass(strCtor, convertedValue);
            } catch (NoSuchMethodException ex) {
              // proceed with field lookup
              if (logger.isTraceEnabled()) {
                logger.trace(
                    "No String constructor found on type [" + requiredType.getName() + "]", ex);
              }
            } catch (Exception ex) {
              if (logger.isDebugEnabled()) {
                logger.debug(
                    "Construction via String failed for type [" + requiredType.getName() + "]", ex);
              }
            }
          }
          String trimmedValue = ((String) convertedValue).trim();
          if (requiredType.isEnum() && "".equals(trimmedValue)) {
            // It's an empty enum identifier: reset the enum value to null.
            return null;
          }

          convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
        }
      }

      if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
        // Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
        StringBuilder msg = new StringBuilder();
        msg.append("Cannot convert value of type [")
            .append(ClassUtils.getDescriptiveType(newValue));
        msg.append("] to required type [")
            .append(ClassUtils.getQualifiedName(requiredType))
            .append("]");
        if (propertyName != null) {
          msg.append(" for property '").append(propertyName).append("'");
        }
        if (editor != null) {
          msg.append(": PropertyEditor [")
              .append(editor.getClass().getName())
              .append("] returned inappropriate value");
          throw new IllegalArgumentException(msg.toString());
        } else {
          msg.append(": no matching editors or conversion strategy found");
          throw new IllegalStateException(msg.toString());
        }
      }
    }

    return (T) convertedValue;
  }
  @Override
  @SuppressWarnings("unchecked")
  protected SessionFactory buildSessionFactory() throws Exception {
    // Create Configuration instance.
    Configuration config = newConfiguration();

    DataSource dataSource = getDataSource();
    if (dataSource != null) {
      // Make given DataSource available for SessionFactory configuration.
      configTimeDataSourceHolder.set(dataSource);
    }
    if (this.jtaTransactionManager != null) {
      // Make Spring-provided JTA TransactionManager available.
      configTimeTransactionManagerHolder.set(this.jtaTransactionManager);
    }
    if (this.cacheRegionFactory != null) {
      // Make Spring-provided Hibernate RegionFactory available.
      configTimeRegionFactoryHolder.set(this.cacheRegionFactory);
    }
    if (this.lobHandler != null) {
      // Make given LobHandler available for SessionFactory configuration.
      // Do early because because mapping resource might refer to custom types.
      configTimeLobHandlerHolder.set(this.lobHandler);
    }

    // Analogous to Hibernate EntityManager's Ejb3Configuration:
    // Hibernate doesn't allow setting the bean ClassLoader explicitly,
    // so we need to expose it as thread context ClassLoader accordingly.
    Thread currentThread = Thread.currentThread();
    ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
    boolean overrideClassLoader =
        (this.beanClassLoader != null && !this.beanClassLoader.equals(threadContextClassLoader));
    if (overrideClassLoader) {
      currentThread.setContextClassLoader(this.beanClassLoader);
    }

    try {
      if (isExposeTransactionAwareSessionFactory()) {
        // Set Hibernate 3.1+ CurrentSessionContext implementation,
        // providing the Spring-managed Session as current Session.
        // Can be overridden by a custom value for the corresponding Hibernate property.
        config.setProperty(
            Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
      }

      if (this.jtaTransactionManager != null) {
        // Set Spring-provided JTA TransactionManager as Hibernate property.
        config.setProperty(Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName());
        config.setProperty(
            Environment.TRANSACTION_MANAGER_STRATEGY,
            LocalTransactionManagerLookup.class.getName());
      } else {
        // Makes the Hibernate Session aware of the presence of a Spring-managed transaction.
        // Also sets connection release mode to ON_CLOSE by default.
        config.setProperty(
            Environment.TRANSACTION_STRATEGY, SpringTransactionFactory.class.getName());
      }

      if (this.entityInterceptor != null) {
        // Set given entity interceptor at SessionFactory level.
        config.setInterceptor(this.entityInterceptor);
      }

      if (this.namingStrategy != null) {
        // Pass given naming strategy to Hibernate Configuration.
        config.setNamingStrategy(this.namingStrategy);
      }

      if (this.typeDefinitions != null) {
        // Register specified Hibernate type definitions.
        Mappings mappings = config.createMappings();
        for (TypeDefinitionBean typeDef : this.typeDefinitions) {
          mappings.addTypeDef(
              typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());
        }
      }

      if (this.filterDefinitions != null) {
        // Register specified Hibernate FilterDefinitions.
        for (FilterDefinition filterDef : this.filterDefinitions) {
          config.addFilterDefinition(filterDef);
        }
      }

      if (this.configLocations != null) {
        for (Resource resource : this.configLocations) {
          // Load Hibernate configuration from given location.
          config.configure(resource.getURL());
        }
      }

      if (this.hibernateProperties != null) {
        // Add given Hibernate properties to Configuration.
        config.addProperties(this.hibernateProperties);
      }

      if (dataSource != null) {
        Class<?> providerClass = LocalDataSourceConnectionProvider.class;
        if (isUseTransactionAwareDataSource()
            || dataSource instanceof TransactionAwareDataSourceProxy) {
          providerClass = TransactionAwareDataSourceConnectionProvider.class;
        } else if (config.getProperty(Environment.TRANSACTION_MANAGER_STRATEGY) != null) {
          providerClass = LocalJtaDataSourceConnectionProvider.class;
        }
        // Set Spring-provided DataSource as Hibernate ConnectionProvider.
        config.setProperty(Environment.CONNECTION_PROVIDER, providerClass.getName());
      }

      if (this.cacheRegionFactory != null) {
        // Expose Spring-provided Hibernate RegionFactory.
        config.setProperty(
            Environment.CACHE_REGION_FACTORY, LocalRegionFactoryProxy.class.getName());
      }

      if (this.mappingResources != null) {
        // Register given Hibernate mapping definitions, contained in resource files.
        for (String mapping : this.mappingResources) {
          Resource resource = new ClassPathResource(mapping.trim(), this.beanClassLoader);
          config.addInputStream(resource.getInputStream());
        }
      }

      if (this.mappingLocations != null) {
        // Register given Hibernate mapping definitions, contained in resource files.
        for (Resource resource : this.mappingLocations) {
          config.addInputStream(resource.getInputStream());
        }
      }

      if (this.cacheableMappingLocations != null) {
        // Register given cacheable Hibernate mapping definitions, read from the file system.
        for (Resource resource : this.cacheableMappingLocations) {
          config.addCacheableFile(resource.getFile());
        }
      }

      if (this.mappingJarLocations != null) {
        // Register given Hibernate mapping definitions, contained in jar files.
        for (Resource resource : this.mappingJarLocations) {
          config.addJar(resource.getFile());
        }
      }

      if (this.mappingDirectoryLocations != null) {
        // Register all Hibernate mapping definitions in the given directories.
        for (Resource resource : this.mappingDirectoryLocations) {
          File file = resource.getFile();
          if (!file.isDirectory()) {
            throw new IllegalArgumentException(
                "Mapping directory location [" + resource + "] does not denote a directory");
          }
          config.addDirectory(file);
        }
      }

      // Tell Hibernate to eagerly compile the mappings that we registered,
      // for availability of the mapping information in further processing.
      postProcessMappings(config);
      config.buildMappings();

      if (this.entityCacheStrategies != null) {
        // Register cache strategies for mapped entities.
        for (Enumeration<?> classNames = this.entityCacheStrategies.propertyNames();
            classNames.hasMoreElements(); ) {
          String className = (String) classNames.nextElement();
          String[] strategyAndRegion =
              StringUtils.commaDelimitedListToStringArray(
                  this.entityCacheStrategies.getProperty(className));
          if (strategyAndRegion.length > 1) {
            config.setCacheConcurrencyStrategy(
                className, strategyAndRegion[0], strategyAndRegion[1]);
          } else if (strategyAndRegion.length > 0) {
            config.setCacheConcurrencyStrategy(className, strategyAndRegion[0]);
          }
        }
      }

      if (this.collectionCacheStrategies != null) {
        // Register cache strategies for mapped collections.
        for (Enumeration<?> collRoles = this.collectionCacheStrategies.propertyNames();
            collRoles.hasMoreElements(); ) {
          String collRole = (String) collRoles.nextElement();
          String[] strategyAndRegion =
              StringUtils.commaDelimitedListToStringArray(
                  this.collectionCacheStrategies.getProperty(collRole));
          if (strategyAndRegion.length > 1) {
            config.setCollectionCacheConcurrencyStrategy(
                collRole, strategyAndRegion[0], strategyAndRegion[1]);
          } else if (strategyAndRegion.length > 0) {
            config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]);
          }
        }
      }

      if (this.eventListeners != null) {
        // Register specified Hibernate event listeners.
        for (Map.Entry<String, Object> entry : this.eventListeners.entrySet()) {
          String listenerType = entry.getKey();
          Object listenerObject = entry.getValue();
          if (listenerObject instanceof Collection) {
            Collection<Object> listeners = (Collection<Object>) listenerObject;
            EventListeners listenerRegistry = config.getEventListeners();
            Object[] listenerArray =
                (Object[])
                    Array.newInstance(
                        listenerRegistry.getListenerClassFor(listenerType), listeners.size());
            listenerArray = listeners.toArray(listenerArray);
            config.setListeners(listenerType, listenerArray);
          } else {
            config.setListener(listenerType, listenerObject);
          }
        }
      }

      // Perform custom post-processing in subclasses.
      postProcessConfiguration(config);

      // Build SessionFactory instance.
      logger.info("Building new Hibernate SessionFactory");
      this.configuration = config;
      return newSessionFactory(config);
    } finally {
      if (dataSource != null) {
        configTimeDataSourceHolder.remove();
      }
      if (this.jtaTransactionManager != null) {
        configTimeTransactionManagerHolder.remove();
      }
      if (this.cacheRegionFactory != null) {
        configTimeRegionFactoryHolder.remove();
      }
      if (this.lobHandler != null) {
        configTimeLobHandlerHolder.remove();
      }
      if (overrideClassLoader) {
        // Reset original thread context ClassLoader.
        currentThread.setContextClassLoader(threadContextClassLoader);
      }
    }
  }
  private ManagedMap<String, Object> buildVariablesMap(
      final Element element, final ParserContext parserContext, List<Element> variableElements) {
    @SuppressWarnings("serial")
    ManagedMap<String, Object> variableMap =
        new ManagedMap<String, Object>() {

          @Override
          public Object put(String key, Object value) {
            if (this.containsKey(key)) {
              parserContext.getReaderContext().error("Duplicated variable: " + key, element);
            }
            return super.put(key, value);
          }
        };

    for (Element childElement : variableElements) {
      String variableName = childElement.getAttribute("name");
      String variableValue = childElement.getAttribute("value");
      String variableRef = childElement.getAttribute("ref");
      if (!(StringUtils.hasText(variableValue) ^ StringUtils.hasText(variableRef))) {
        parserContext
            .getReaderContext()
            .error(
                "Exactly one of the 'ref' attribute or 'value' attribute, "
                    + " is required for element "
                    + IntegrationNamespaceUtils.createElementDescription(element)
                    + ".",
                element);
      }
      if (StringUtils.hasText(variableValue)) {
        variableMap.put(variableName, variableValue);
      } else {
        variableMap.put(variableName, new RuntimeBeanReference(variableRef));
      }
    }

    String variables = element.getAttribute("variables");
    if (StringUtils.hasText(variables)) {
      String[] variablePairs = StringUtils.commaDelimitedListToStringArray(variables);
      for (String variablePair : variablePairs) {
        String[] variableValue = variablePair.split("=");
        if (variableValue.length != 2) {
          parserContext
              .getReaderContext()
              .error(
                  "Variable declarations in the 'variable' attribute must have the "
                      + "form 'var=value'; found : '"
                      + variablePair
                      + "'",
                  element);
        }
        String variable = variableValue[0].trim();
        String value = variableValue[1];
        if (variable.endsWith("-ref")) {
          variable = variable.substring(0, variable.indexOf("-ref"));
          variableMap.put(variable, new RuntimeBeanReference(value));
        } else {
          variableMap.put(variable, value);
        }
      }
    }

    return variableMap;
  }
Пример #30
0
/**
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @author Rick Evans
 * @author Jeremy Grelle
 */
public class OptionTagTests extends AbstractHtmlElementTagTests {

  private static final String ARRAY_SOURCE = "abc,123,def";

  private static final String[] ARRAY = StringUtils.commaDelimitedListToStringArray(ARRAY_SOURCE);

  private OptionTag tag;

  private SelectTag parentTag;

  @Override
  @SuppressWarnings("serial")
  protected void onSetUp() {
    this.tag =
        new OptionTag() {
          @Override
          protected TagWriter createTagWriter() {
            return new TagWriter(getWriter());
          }
        };
    this.parentTag =
        new SelectTag() {
          @Override
          public String getName() {
            // Should not be used other than to delegate to
            // RequestDataValueDataProcessor
            return "testName";
          }
        };
    this.tag.setParent(this.parentTag);
    this.tag.setPageContext(getPageContext());
  }

  public void testCanBeDisabledEvenWhenSelected() throws Exception {
    String selectName = "testBean.name";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));
    this.tag.setValue("bar");
    this.tag.setLabel("Bar");
    this.tag.setDisabled("true");
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", "bar");
    assertContainsAttribute(output, "disabled", "disabled");
    assertBlockTagContains(output, "Bar");
  }

  public void testRenderNotSelected() throws Exception {
    String selectName = "testBean.name";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));
    this.tag.setValue("bar");
    this.tag.setLabel("Bar");
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", "bar");
    assertBlockTagContains(output, "Bar");
  }

  public void testRenderWithDynamicAttributes() throws Exception {
    String dynamicAttribute1 = "attr1";
    String dynamicAttribute2 = "attr2";

    String selectName = "testBean.name";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));
    this.tag.setValue("bar");
    this.tag.setLabel("Bar");
    this.tag.setDynamicAttribute(null, dynamicAttribute1, dynamicAttribute1);
    this.tag.setDynamicAttribute(null, dynamicAttribute2, dynamicAttribute2);

    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", "bar");
    assertContainsAttribute(output, dynamicAttribute1, dynamicAttribute1);
    assertContainsAttribute(output, dynamicAttribute2, dynamicAttribute2);
    assertBlockTagContains(output, "Bar");
  }

  public void testRenderSelected() throws Exception {
    String selectName = "testBean.name";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));
    this.tag.setId("myOption");
    this.tag.setValue("foo");
    this.tag.setLabel("Foo");
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "id", "myOption");
    assertContainsAttribute(output, "value", "foo");
    assertContainsAttribute(output, "selected", "selected");
    assertBlockTagContains(output, "Foo");
  }

  public void testWithNoLabel() throws Exception {
    String selectName = "testBean.name";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));
    this.tag.setValue("bar");
    this.tag.setCssClass("myClass");
    this.tag.setOnclick("CLICK");
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", "bar");
    assertContainsAttribute(output, "class", "myClass");
    assertContainsAttribute(output, "onclick", "CLICK");
    assertBlockTagContains(output, "bar");
  }

  public void testWithoutContext() throws Exception {
    this.tag.setParent(null);
    this.tag.setValue("foo");
    this.tag.setLabel("Foo");
    try {
      tag.doStartTag();
      fail("Must not be able to use <option> tag without exposed context.");
    } catch (IllegalStateException ex) {
      // expected
    }
  }

  public void testWithEnum() throws Exception {
    String selectName = "testBean.favouriteColour";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));

    String value = Colour.GREEN.getCode().toString();
    String label = Colour.GREEN.getLabel();

    this.tag.setValue(value);
    this.tag.setLabel(label);

    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", value);
    assertContainsAttribute(output, "selected", "selected");
    assertBlockTagContains(output, label);
  }

  public void testWithEnumNotSelected() throws Exception {
    String selectName = "testBean.favouriteColour";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));

    String value = Colour.BLUE.getCode().toString();
    String label = Colour.BLUE.getLabel();

    this.tag.setValue(value);
    this.tag.setLabel(label);

    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", value);
    assertAttributeNotPresent(output, "selected");
    assertBlockTagContains(output, label);
  }

  public void testWithPropertyEditor() throws Exception {
    String selectName = "testBean.stringArray";
    BindStatus bindStatus =
        new BindStatus(getRequestContext(), selectName, false) {
          @Override
          public PropertyEditor getEditor() {
            return new StringArrayPropertyEditor();
          }
        };
    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);

    this.tag.setValue(ARRAY_SOURCE);
    this.tag.setLabel("someArray");

    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", ARRAY_SOURCE);
    assertContainsAttribute(output, "selected", "selected");
    assertBlockTagContains(output, "someArray");
  }

  public void testWithPropertyEditorStringComparison() throws Exception {
    final PropertyEditor testBeanEditor = new TestBeanPropertyEditor();
    testBeanEditor.setValue(new TestBean("Sally"));
    String selectName = "testBean.spouse";
    BindStatus bindStatus =
        new BindStatus(getRequestContext(), selectName, false) {
          @Override
          public PropertyEditor getEditor() {
            return testBeanEditor;
          }
        };
    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);

    this.tag.setValue("Sally");

    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();
    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", "Sally");
    assertContainsAttribute(output, "selected", "selected");
    assertBlockTagContains(output, "Sally");
  }

  public void testWithCustomObjectSelected() throws Exception {
    String selectName = "testBean.someNumber";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));
    this.tag.setValue("${myNumber}");
    this.tag.setLabel("GBP ${myNumber}");
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", "12.34");
    assertContainsAttribute(output, "selected", "selected");
    assertBlockTagContains(output, "GBP 12.34");
  }

  public void testWithCustomObjectNotSelected() throws Exception {
    String selectName = "testBean.someNumber";
    getPageContext()
        .setAttribute(
            SelectTag.LIST_VALUE_PAGE_ATTRIBUTE,
            new BindStatus(getRequestContext(), selectName, false));
    this.tag.setValue("${myOtherNumber}");
    this.tag.setLabel("GBP ${myOtherNumber}");
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();

    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", "12.35");
    assertAttributeNotPresent(output, "selected");
    assertBlockTagContains(output, "GBP 12.35");
  }

  public void testWithCustomObjectAndEditorSelected() throws Exception {
    final PropertyEditor floatEditor = new SimpleFloatEditor();
    floatEditor.setValue(new Float("12.34"));
    String selectName = "testBean.someNumber";
    BindStatus bindStatus =
        new BindStatus(getRequestContext(), selectName, false) {
          @Override
          public PropertyEditor getEditor() {
            return floatEditor;
          }
        };
    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);

    this.tag.setValue("${myNumber}");
    this.tag.setLabel("${myNumber}");

    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();
    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "selected", "selected");
    assertBlockTagContains(output, "12.34f");
  }

  public void testWithCustomObjectAndEditorNotSelected() throws Exception {
    final PropertyEditor floatEditor = new SimpleFloatEditor();
    String selectName = "testBean.someNumber";
    BindStatus bindStatus =
        new BindStatus(getRequestContext(), selectName, false) {
          @Override
          public PropertyEditor getEditor() {
            return floatEditor;
          }
        };
    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);

    this.tag.setValue("${myOtherNumber}");
    this.tag.setLabel("${myOtherNumber}");

    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();
    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertAttributeNotPresent(output, "selected");
    assertBlockTagContains(output, "12.35f");
  }

  public void testAsBodyTag() throws Exception {
    String selectName = "testBean.name";
    BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false);
    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);

    String bodyContent = "some content";

    this.tag.setValue("foo");
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    this.tag.setBodyContent(new MockBodyContent(bodyContent, getWriter()));
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();
    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "selected", "selected");
    assertBlockTagContains(output, bodyContent);
  }

  public void testAsBodyTagSelected() throws Exception {
    String selectName = "testBean.name";
    BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false);
    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);

    String bodyContent = "some content";

    this.tag.setValue("Rob Harrop");
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    this.tag.setBodyContent(new MockBodyContent(bodyContent, getWriter()));
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();
    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertBlockTagContains(output, bodyContent);
  }

  public void testAsBodyTagCollapsed() throws Exception {
    String selectName = "testBean.name";
    BindStatus bindStatus = new BindStatus(getRequestContext(), selectName, false);
    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);

    String bodyContent = "some content";

    this.tag.setValue(bodyContent);
    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);
    this.tag.setBodyContent(new MockBodyContent(bodyContent, getWriter()));
    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);

    String output = getOutput();
    assertOptionTagOpened(output);
    assertOptionTagClosed(output);
    assertContainsAttribute(output, "value", bodyContent);
    assertBlockTagContains(output, bodyContent);
  }

  public void testAsBodyTagWithEditor() throws Exception {
    String selectName = "testBean.stringArray";
    BindStatus bindStatus =
        new BindStatus(getRequestContext(), selectName, false) {
          @Override
          public PropertyEditor getEditor() {
            return new RulesVariantEditor();
          }
        };
    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);

    RulesVariant rulesVariant = new RulesVariant("someRules", "someVariant");
    getPageContext().getRequest().setAttribute("rule", rulesVariant);

    this.tag.setValue("${rule}");

    int result = this.tag.doStartTag();
    assertEquals(BodyTag.EVAL_BODY_BUFFERED, result);

    assertEquals(rulesVariant, getPageContext().getAttribute("value"));
    assertEquals(rulesVariant.toId(), getPageContext().getAttribute("displayValue"));

    result = this.tag.doEndTag();
    assertEquals(Tag.EVAL_PAGE, result);
  }

  public void testMultiBind() throws Exception {
    BeanPropertyBindingResult result = new BeanPropertyBindingResult(new TestBean(), "testBean");
    result
        .getPropertyAccessor()
        .registerCustomEditor(TestBean.class, "friends", new FriendEditor());
    exposeBindingResult(result);

    BindStatus bindStatus = new BindStatus(getRequestContext(), "testBean.friends", false);

    getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, bindStatus);
    this.tag.setValue(new TestBean("foo"));
    this.tag.doStartTag();
    this.tag.doEndTag();

    assertEquals("<option value=\"foo\">foo</option>", getOutput());
  }

  public void testOptionTagNotNestedWithinSelectTag() throws Exception {
    try {
      tag.setParent(null);
      tag.setValue("foo");
      tag.doStartTag();
      fail("Must throw an IllegalStateException when not nested within a <select/> tag.");
    } catch (IllegalStateException ex) {
      // expected
    }
  }

  private void assertOptionTagOpened(String output) {
    assertTrue(output.startsWith("<option"));
  }

  private void assertOptionTagClosed(String output) {
    assertTrue(output.endsWith("</option>"));
  }

  @Override
  protected void extendRequest(MockHttpServletRequest request) {
    TestBean bean = new TestBean();
    bean.setName("foo");
    bean.setFavouriteColour(Colour.GREEN);
    bean.setStringArray(ARRAY);
    bean.setSpouse(new TestBean("Sally"));
    bean.setSomeNumber(new Float("12.34"));

    List friends = new ArrayList();
    friends.add(new TestBean("bar"));
    friends.add(new TestBean("penc"));
    bean.setFriends(friends);

    request.setAttribute("testBean", bean);
    request.setAttribute("myNumber", new Float(12.34));
    request.setAttribute("myOtherNumber", new Float(12.35));
  }

  private static class TestBeanPropertyEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
      setValue(new TestBean(text + "k", 123));
    }

    @Override
    public String getAsText() {
      return ((TestBean) getValue()).getName();
    }
  }

  @SuppressWarnings("serial")
  public static class RulesVariant implements Serializable {

    private String rules;

    private String variant;

    public RulesVariant(String rules, String variant) {
      this.setRules(rules);
      this.setVariant(variant);
    }

    private void setRules(String rules) {
      this.rules = rules;
    }

    public String getRules() {
      return rules;
    }

    private void setVariant(String variant) {
      this.variant = variant;
    }

    public String getVariant() {
      return variant;
    }

    public String toId() {
      if (this.variant != null) {
        return this.rules + "-" + this.variant;
      } else {
        return rules;
      }
    }

    public static RulesVariant fromId(String id) {
      String[] s = id.split("-", 2);
      String rules = s[0];
      String variant = s.length > 1 ? s[1] : null;
      return new RulesVariant(rules, variant);
    }

    public boolean equals(Object obj) {
      if (obj instanceof RulesVariant) {
        RulesVariant other = (RulesVariant) obj;
        return this.toId().equals(other.toId());
      }
      return false;
    }

    public int hashCode() {
      return this.toId().hashCode();
    }
  }

  public class RulesVariantEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
      setValue(RulesVariant.fromId(text));
    }

    @Override
    public String getAsText() {
      RulesVariant rulesVariant = (RulesVariant) getValue();
      return rulesVariant.toId();
    }
  }

  private static class FriendEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
      setValue(new TestBean(text));
    }

    @Override
    public String getAsText() {
      return ((TestBean) getValue()).getName();
    }
  }
}