Standard Libraries

import default
import semmle.code.java.frameworks.spring.SpringXMLElement
import semmle.code.java.frameworks.spring.SpringBean
import semmle.code.java.frameworks.spring.SpringAbstractRef
import semmle.code.java.frameworks.spring.SpringList
import semmle.code.java.frameworks.spring.SpringValue

/** Represents a <property> element in Spring XML files*/
class SpringProperty extends SpringXMLElement {
  SpringProperty() {
    this.getName() = "property"
  }

  string toString() {
    result =  this.getPropertyName()
  }

  /** returns the value of the name attribute*/
  string getPropertyName() {
    result = this.getAttributeValue("name")
  }

  /** true if the property has a ref attribute*/
  predicate hasPropertyRefString() {
    this.hasAttribute("ref")
  }
  /** returns the value of the ref attribute*/
  string getPropertyRefString() {
    result = this.getAttributeValue("ref")
  }
  /** returns the bean referred to by the ref attribute or a nested <ref> element*/
  SpringBean getPropertyRefBean() {
    if this.hasPropertyRefString()
    then result.getBeanIdentifier() = this.getPropertyRefString()
    else exists(SpringAbstractRef ref |
        ref = this.getASpringChild() and
        result = ref.getBean())
  }

  /** true if the property has a value attribute*/
  predicate hasPropertyValueString() {
    this.hasAttribute("value")
  }
  /** returns the value of the value attribute*/
  string getPropertyValueString() {
    result = this.getAttributeValue("value")
  }
  /** returns the value of the value attribute, or a nested <value> element, whichever
      is present*/
  string getPropertyValue() {
    if this.hasPropertyValueString()
    then result = this.getPropertyValueString()
    else exists (SpringValue val |
        val = this.getASpringChild() and
        result = val.getContentString())
  }

  /** true if the property is similar to another property. Currently only checks
    * the property name and for references to beans*/
  predicate isSimilar(SpringXMLElement element) {
    exists (SpringProperty other | other = element and
    this.getPropertyName() = other.getPropertyName() and 
    (  this.getPropertyRefBean() = other.getPropertyRefBean() or
      exists (SpringBean thisBean, SpringBean otherBean | 
        thisBean = this.getASpringChild() and
        otherBean = other.getASpringChild() and
        thisBean.isSimilar(otherBean)
      ) 
    )
    )
  }

  Method getSetterMethod() {
    hasMethod(this.getEnclosingBean().getClass(), result, _) and
    result.getName().toLowerCase() = "set" + this.getPropertyName().toLowerCase()
  }

  Method getSetterMethod(SpringBean context) {
    this.getEnclosingBean() = context.getBeanParent*() and
    hasMethod(context.getClass(), result, _) and
    result.getName().toLowerCase() = "set" + this.getPropertyName().toLowerCase()
	}
}