class RouteSpecification extends AbstractSpecification<Itinerary> implements ValueObject<RouteSpecification> {

  @ManyToOne()
  @JoinColumn(name = "spec_origin_id")
  public Location origin;

  @ManyToOne()
  @JoinColumn(name = "spec_destination_id")
  public Location destination;

  @Column(name = "spec_arrival_deadline", nullable = false)
  public Instant arrivalDeadline;

  /**
   * @param origin origin location - can't be the same as the destination
   * @param destination destination location - can't be the same as the origin
   * @param arrivalDeadline arrival deadline
   */
  public RouteSpecification(final Location origin, final Location destination, final Instant arrivalDeadline) {
    Validate.notNull(origin, "Origin is required");
    Validate.notNull(destination, "Destination is required");
    Validate.notNull(arrivalDeadline, "Arrival deadline is required");
    Validate.isTrue(!origin.sameIdentityAs(destination), "Origin and destination can't be the same: " + origin);

    this.origin = origin;
    this.destination = destination;
    this.arrivalDeadline = arrivalDeadline;
  }

  /**
   * @return Specified origin location.
   */
  public Location origin() {
    return origin;
  }

  /**
   * @return Specfied destination location.
   */
  public Location destination() {
    return destination;
  }

  /**
   * @return Arrival deadline.
   */
  public Instant arrivalDeadline() {
    return arrivalDeadline;
  }

  @Override
  public boolean isSatisfiedBy(final Itinerary itinerary) {
    return itinerary != null &&
           origin().sameIdentityAs(itinerary.initialDepartureLocation()) &&
           destination().sameIdentityAs(itinerary.finalArrivalLocation()) &&
           arrivalDeadline().isAfter(itinerary.finalArrivalDate());
  }

  @Override
  public boolean sameValueAs(final RouteSpecification other) {
    return other != null && new EqualsBuilder().
      append(this.origin, other.origin).
      append(this.destination, other.destination).
      append(this.arrivalDeadline, other.arrivalDeadline).
      isEquals();
  }

  @Override
  public boolean equals(final Object o) {<FILL_FUNCTION_BODY>}

  @Override
  public int hashCode() {
    return new HashCodeBuilder().
      append(this.origin).
      append(this.destination).
      append(this.arrivalDeadline).
      toHashCode();
  }

  RouteSpecification() {
    // Needed by Hibernate
  }
  
}

    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    final RouteSpecification that = (RouteSpecification) o;

    return sameValueAs(that);
  
<methods>public non-sealed void <init>() ,public Specification<se.citerus.dddsample.domain.model.cargo.Itinerary> and(Specification<se.citerus.dddsample.domain.model.cargo.Itinerary>) ,public abstract boolean isSatisfiedBy(se.citerus.dddsample.domain.model.cargo.Itinerary) ,public Specification<se.citerus.dddsample.domain.model.cargo.Itinerary> not(Specification<se.citerus.dddsample.domain.model.cargo.Itinerary>) ,public Specification<se.citerus.dddsample.domain.model.cargo.Itinerary> or(Specification<se.citerus.dddsample.domain.model.cargo.Itinerary>) <variables>