package com.aemreunal.domain; /* * *********************** * * Copyright (c) 2015 * * * * This code belongs to: * * * * @author Ahmet Emre Ünal * * S001974 * * * * aemreunal@gmail.com * * emre.unal@ozu.edu.tr * * * * aemreunal.com * * *********************** * */ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import java.io.Serializable; import java.util.Date; import java.util.LinkedHashSet; import java.util.Set; import javax.persistence.*; import javax.validation.constraints.Size; import org.springframework.hateoas.ResourceSupport; import org.springframework.web.bind.annotation.ResponseBody; import com.aemreunal.helper.json.JsonArrayBuilder; import com.aemreunal.helper.json.JsonBuilderFactory; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonSerialize; // To not mark getters & setters as unused, as they're being used by Spring & Hibernate @SuppressWarnings("UnusedDeclaration") @Entity @Table(name = "beacons") @ResponseBody @JsonIgnoreProperties(value = { "project", "region", "connections", "locationInfoTextFileName" }) public class Beacon extends ResourceSupport implements Serializable, Comparable { // UUID hex string (including dashes) is 36 characters long public static final int UUID_MAX_LENGTH = 36; public static final int DISPLAY_NAME_MAX_LENGTH = 50; public static final int DESCRIPTION_MAX_LENGTH = 200; /* *------------------------------------------------------------ * BEGIN: Beacon 'ID' attribute */ @Id @Column(name = "beacon_id") @GeneratedValue(strategy = GenerationType.AUTO) @Access(AccessType.PROPERTY) private Long beaconId; /* * END: Beacon 'ID' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'UUID' attribute */ @Column(name = "uuid", nullable = false, length = UUID_MAX_LENGTH) @Size(min = UUID_MAX_LENGTH, max = UUID_MAX_LENGTH) @Access(AccessType.PROPERTY) private String uuid = ""; /* * END: Beacon 'UUID' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'Major' attribute */ @Column(name = "major", nullable = false) @Access(AccessType.PROPERTY) private Integer major = -1; /* * END: Beacon 'Major' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'Minor' attribute */ @Column(name = "minor", nullable = false) @Access(AccessType.PROPERTY) private Integer minor = -1; /* * END: Beacon 'Minor' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'description' attribute */ @Column(name = "description", nullable = false, length = DESCRIPTION_MAX_LENGTH) @Size(max = DESCRIPTION_MAX_LENGTH) @Access(AccessType.PROPERTY) private String description = ""; /* * END: Beacon 'description' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'display name' attribute * * A 'display name' is a user-friendly text that can be displayed on a client as * the name of this beacon/location. For example, the beacon description may be * "beacon 5, under northwest light switch", which isn't a user-friendly way to * describe a location. This text can be "Room 353", which can be displayed to a * user to describe the area this beacon represents. */ @Column(name = "display_name", nullable = false, length = DISPLAY_NAME_MAX_LENGTH) @Size(max = DISPLAY_NAME_MAX_LENGTH) @Access(AccessType.PROPERTY) private String displayName = ""; /* * END: Beacon 'display name' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'region' attribute */ @ManyToOne(targetEntity = Region.class, fetch = FetchType.LAZY, optional = true) // JoinTable & Lazy fetch-> 5.1.7: http://docs.jboss.org/hibernate/core/4.3/manual/en-US/html_single/ @JoinTable(name = "regions_to_beacons", joinColumns = @JoinColumn(name = "beacon_id"), inverseJoinColumns = @JoinColumn(name = "region_id")) @Access(AccessType.PROPERTY) private Region region; /* * END: Beacon 'region' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'X coordinate' attribute */ @Column(name = "x_coordinate", nullable = false) @Access(AccessType.PROPERTY) private Integer xCoordinate; /* * END: Beacon 'X coordinate' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'Y coordinate' attribute */ @Column(name = "y_coordinate", nullable = false) @Access(AccessType.PROPERTY) private Integer yCoordinate; /* * END: Beacon 'Y coordinate' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'scenario' attribute */ @ManyToOne(targetEntity = Scenario.class, fetch = FetchType.LAZY, optional = false) @JoinTable(name = "scenarios_to_beacons", joinColumns = @JoinColumn(name = "beacon_id"), inverseJoinColumns = @JoinColumn(name = "scenario_id")) @Access(AccessType.PROPERTY) private Scenario scenario; /* * END: Beacon 'scenario' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'designated' attribute */ @Column(name = "designated", nullable = false) @Access(AccessType.PROPERTY) private Boolean designated = false; /* * END: Beacon 'designated' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'location info' attribute * * The length is UUID_MAX_LENGTH, because text file names are set as UUIDs. */ @Column(name = "location_info_text_file_name", length = UUID_MAX_LENGTH) @Size(min = UUID_MAX_LENGTH, max = UUID_MAX_LENGTH) @Access(AccessType.PROPERTY) private String locationInfoTextFileName = null; /* * END: Beacon 'location info' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'connections' attribute */ @ManyToMany(targetEntity = Connection.class, fetch = FetchType.LAZY) @JoinTable(name = "beacons_to_connections", joinColumns = @JoinColumn(name = "beacon_id"), inverseJoinColumns = @JoinColumn(name = "connection_id")) @OrderBy("connectionId") @Access(AccessType.PROPERTY) private Set<Connection> connections = new LinkedHashSet<Connection>(); /* * END: Beacon 'connections' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Beacon 'creationDate' attribute */ @Column(name = "creation_date", nullable = false) @Access(AccessType.PROPERTY) private Date creationDate = null; /* * END: Beacon 'creationDate' attribute *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Constructors */ public Beacon() { // Empty constructor for Spring & Hibernate } /* * END: Constructors *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Helpers */ public void addConnection(Connection connection) { this.getConnections().add(connection); } public void removeConnection(Connection connection) { this.getConnections().remove(connection); } @JsonSerialize public boolean hasLocationInfo() { return getLocationInfoTextFileName() != null; } // Weird stuff: when this method is named something like 'getConnectionsJson', // 'getConnectionsList', 'getConnectionsAsList', Jackson tries to use it and // causes a LazyInit exception. @JsonIgnore public JSONArray getConnsAsJson() { JsonArrayBuilder connArray = JsonBuilderFactory.array(); for (Connection connection : getConnections()) { connArray.add(connection.getBeaconIdsAsJson()); } return connArray.build(); } public JSONObject getQueryResponse() { return JsonBuilderFactory.object() .add("beaconId", getBeaconId()) .add("uuid", getUuid()) .add("major", getMajor()) .add("minor", getMinor()) .add("designated", getDesignated()) .add("xCoordinate", getxCoordinate()) .add("yCoordinate", getyCoordinate()) .add("hasLocationInfo", hasLocationInfo()) .add("displayName", getDisplayName()) .build(); } /* * END: Helpers *------------------------------------------------------------ */ /* *------------------------------------------------------------ * BEGIN: Getters & Setters */ public Long getBeaconId() { return beaconId; } public void setBeaconId(Long beaconId) { this.beaconId = beaconId; } public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid.toUpperCase(); } public Integer getMajor() { return major; } public void setMajor(Integer major) { this.major = major; } public Integer getMinor() { return minor; } public void setMinor(Integer minor) { this.minor = minor; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } public Region getRegion() { return region; } public void setRegion(Region region) { this.region = region; } public Integer getxCoordinate() { return xCoordinate; } public void setxCoordinate(Integer xCoordinate) { this.xCoordinate = xCoordinate; } public Integer getyCoordinate() { return yCoordinate; } public void setyCoordinate(Integer yCoordinate) { this.yCoordinate = yCoordinate; } public Scenario getScenario() { return scenario; } public void setScenario(Scenario scenario) { this.scenario = scenario; } public Boolean getDesignated() { return designated; } public Boolean isDesignated() { return designated; } public void setDesignated(Boolean designated) { this.designated = designated; } public String getLocationInfoTextFileName() { return locationInfoTextFileName; } public void setLocationInfoTextFileName(String locationInfoTextFileName) { this.locationInfoTextFileName = locationInfoTextFileName; } public Set<Connection> getConnections() { return connections; } public void setConnections(Set<Connection> connections) { this.connections = connections; } public Date getCreationDate() { return creationDate; } public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } /* * END: Getters & Setters *------------------------------------------------------------ */ @PrePersist private void setInitialProperties() { // Set beacon creation date if (creationDate == null) { setCreationDate(new Date()); } } @Override public String toString() { return "[Beacon: " + getBeaconId() + ", Region: " + getRegion().getRegionId() + ", Project: " + getRegion().getProject().getProjectId() + "]"; } @Override public boolean equals(Object obj) { if (obj instanceof Beacon) { return ((Beacon) obj).getBeaconId().equals(this.getBeaconId()); } return false; } @Override public int compareTo(Object o) { if (o instanceof Beacon) { return this.getBeaconId().compareTo(((Beacon) o).getBeaconId()); } return 0; } }