Java - Jakarta EE Web Application

Jakarta EE Web Application - Java


This is an application written in Java to implement a web application with “Sprite” objects, users with various permissions and a REST API. The web application implements Jakarta Enterprise Edition as well as JavaServer Faces.

The Java web app provides functionality to manipulate “Sprite” objects using JavaServer Faces (JSF) and includes a converter class for converting colors to strings and vice versa. It incorporates data validation to ensure the integrity of Sprite manipulations. The app also offers a Restful HTTP interface for performing Create, Read, Update, and Delete operations on Sprites, with proper response codes and preserving existing values during updates. User administration includes authentication and access restrictions based on user groups, granting access to specific parts of the application. Additionally, the app includes automated unit tests using JUnit, with a focus on testing Sprite movement functionality.

A video demonstrating the output and the code is shown below:


Alternate Link

A Sample of the Source Code is below, view the full codebase on GitHub

AppUser Entity
Sprite Entity
REST API
Exported from Notepad++
1 /* 2 Authors: abde 3 File: Appuser.java 4 Description: Definition of the AppUser Entity 5 */ 6 package cst.entities; 7 8 import java.io.Serializable; 9 import java.util.HashMap; 10 import javax.enterprise.inject.Instance; 11 import javax.enterprise.inject.spi.CDI; 12 import javax.persistence.Basic; 13 import javax.persistence.Column; 14 import javax.persistence.Entity; 15 import javax.persistence.Id; 16 import javax.persistence.NamedQueries; 17 import javax.persistence.NamedQuery; 18 import javax.persistence.Table; 19 import javax.security.enterprise.identitystore.DatabaseIdentityStoreDefinition; 20 import javax.security.enterprise.identitystore.PasswordHash; 21 import javax.security.enterprise.identitystore.Pbkdf2PasswordHash; 22 import javax.validation.constraints.NotNull; 23 import javax.validation.constraints.Size; 24 import javax.xml.bind.annotation.XmlRootElement; 25 26 /** 27 * AppUser entity class 28 * @author abde 29 */ 30 @Entity 31 @Table(name = "APPUSER") 32 @XmlRootElement 33 // change depending on database definition 34 @NamedQueries({ 35 @NamedQuery(name = "Appuser.findAll", query = "SELECT a FROM Appuser a"), 36 @NamedQuery(name = "Appuser.findById", query = "SELECT a FROM Appuser a WHERE a.id = :id"), 37 // @NamedQuery(name = "Appuser.findById", query = "SELECT a FROM Appuser a WHERE a.id = :userid"), 38 @NamedQuery(name = "Appuser.findByGroupname", query = "SELECT a FROM Appuser a WHERE a.groupname = :groupname"), 39 @NamedQuery(name = "Appuser.findByPassword", query = "SELECT a FROM Appuser a WHERE a.password = :password")}) 40 public class Appuser implements Serializable { 41 42 private static final long serialVersionUID = 1L; 43 44 @Id 45 @Basic(optional = false) 46 @NotNull 47 @Size(min = 1, max = 255) 48 // change depending on database definition 49 @Column(name = "ID") 50 // @Column(name = "USERID") 51 private String id; 52 53 @Size(max = 255) 54 @Column(name = "GROUPNAME") 55 private String groupname; 56 57 @Size(max = 255) 58 @Column(name = "PASSWORD") 59 private String password; 60 61 /** 62 * Default Constructor 63 */ 64 public Appuser() { 65 } 66 67 /** 68 * Overloaded constructor to set id 69 * @param id The id being set 70 */ 71 public Appuser(String id) { 72 this.id = id; 73 } 74 75 /** 76 * Return user id 77 * @return the user id 78 */ 79 public String getId() { 80 return id; 81 } 82 83 /** 84 * Set the user id 85 * @param id new user id 86 */ 87 public void setId(String id) { 88 this.id = id; 89 } 90 91 /** 92 * Return the user group name 93 * @return user group name 94 */ 95 public String getGroupname() { 96 return groupname; 97 } 98 99 /** 100 * Set the user group name 101 * @param groupname new user group name 102 */ 103 public void setGroupname(String groupname) { 104 this.groupname = groupname; 105 } 106 107 /** 108 * Get the user password, returns null, do not display user passwords 109 * @return null 110 */ 111 public String getPassword() { 112 return null; 113 } 114 115 /** 116 * Sets the user password 117 * @param password new user password 118 */ 119 public void setPassword(String password) { 120 if ((password == null || password == "") && (this.password != null || this.password != "")) { 121 return; 122 } 123 124 // initialize a PasswordHash object which will generate password hashes 125 Instance<? extends PasswordHash> instance = CDI.current().select(Pbkdf2PasswordHash.class); 126 PasswordHash passwordHash = instance.get(); 127 passwordHash.initialize(new HashMap<String, String>()); // todo: are the defaults good enough? 128 129 // now we can generate a password entry for a given password 130 String passwordEntry = password; //pretend the user has chosen a password mySecretPassword 131 passwordEntry = passwordHash.generate(passwordEntry.toCharArray()); 132 //at this point, passwordEntry refers to a salted/hashed password entry corresponding to mySecretPassword 133 134 this.password = passwordEntry; 135 } 136 137 /** 138 * Sets an id hash code 139 * @return id hash code 140 */ 141 @Override 142 public int hashCode() { 143 int hash = 0; 144 hash += (id != null ? id.hashCode() : 0); 145 return hash; 146 } 147 148 /** 149 * Checks if two users are equal 150 * @param object user to compare to 151 * @return true or false whether users are equal 152 */ 153 @Override 154 public boolean equals(Object object) { 155 // TODO: Warning - this method won't work in the case the id fields are not set 156 if (!(object instanceof Appuser)) { 157 return false; 158 } 159 Appuser other = (Appuser) object; 160 if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { 161 return false; 162 } 163 return true; 164 } 165 166 /** 167 * Returns a string of the user id 168 * @return string of user info 169 */ 170 @Override 171 public String toString() { 172 return "Appuser[ id=" + id + " ]"; 173 } 174 175 } 176
Exported from Notepad++
1 /* 2 Authors: abde 3 File: Sprite.java 4 Description: Defines our "sprite" entities 5 */ 6 package cst.entities; 7 8 import utility.ColorAdapter; 9 import utility.JsonColorSerializer; 10 import utility.JsonColorDeserializer; 11 import java.awt.Color; 12 import java.awt.Graphics; 13 import java.io.Serializable; 14 import java.util.Random; 15 import javax.json.bind.annotation.JsonbTypeDeserializer; 16 import javax.json.bind.annotation.JsonbTypeSerializer; 17 import javax.persistence.Column; 18 import javax.persistence.Entity; 19 import javax.persistence.GeneratedValue; 20 import javax.persistence.GenerationType; 21 import javax.persistence.Id; 22 import javax.xml.bind.annotation.XmlAccessType; 23 import javax.xml.bind.annotation.XmlAccessorType; 24 import javax.xml.bind.annotation.XmlElement; 25 import javax.xml.bind.annotation.XmlRootElement; 26 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 27 28 /** 29 * Sprite entity class 30 * @author abde 31 */ 32 @Entity 33 @XmlRootElement 34 @XmlAccessorType(XmlAccessType.FIELD) 35 public class Sprite implements Serializable { 36 37 private static final long serialVersionUID = 1L; 38 39 public final static Random random = new Random(); 40 41 public final static int SIZE = 10; 42 public final static int MAX_SPEED = 5; 43 @Id 44 @GeneratedValue(strategy = GenerationType.AUTO) 45 private Long id; 46 47 public Long getId() { 48 return id; 49 } 50 51 public void setId(Long id) { 52 this.id = id; 53 } 54 @Column 55 private Integer panelWidth; 56 @Column 57 private Integer panelHeight; 58 @Column 59 private Integer x; 60 @Column 61 private Integer y; 62 @Column 63 private Integer dx; 64 @Column 65 private Integer dy; 66 67 @XmlElement 68 @XmlJavaTypeAdapter(ColorAdapter.class) 69 @JsonbTypeDeserializer(JsonColorDeserializer.class) 70 @JsonbTypeSerializer(JsonColorSerializer.class) 71 @Column 72 private Color color = Color.BLUE; 73 74 /** 75 * Default Constructor 76 */ 77 public Sprite() { 78 } 79 80 /** 81 * Overloaded constructor to set panel height and width 82 * @param height the panel height 83 * @param width the panel width 84 */ 85 public Sprite(int height, int width) { 86 this.panelWidth = width; 87 this.panelHeight = height; 88 x = random.nextInt(width); 89 y = random.nextInt(height); 90 dx = random.nextInt(2 * MAX_SPEED) - MAX_SPEED; 91 dy = random.nextInt(2 * MAX_SPEED) - MAX_SPEED; 92 } 93 94 /** 95 * Overloaded constructor to set panel height, panel width and color 96 * @param height the panel height 97 * @param width the panel width 98 * @param color the color 99 */ 100 public Sprite(int height, int width, Color color) { 101 this(height, width); 102 this.color = color; 103 } 104 105 /** 106 * Get the panel width 107 * @return the panel width 108 */ 109 public Integer getPanelWidth() { 110 return panelWidth; 111 } 112 113 /** 114 * Set the panel width 115 * @param panelWidth new panel width 116 */ 117 public void setPanelWidth(Integer panelWidth) { 118 this.panelWidth = panelWidth; 119 } 120 121 /** 122 * Get the panel height 123 * @return the panel height 124 */ 125 public Integer getPanelHeight() { 126 return panelHeight; 127 } 128 129 /** 130 * Set the panel height 131 * @param panelHeight new panel height 132 */ 133 public void setPanelHeight(Integer panelHeight) { 134 this.panelHeight = panelHeight; 135 } 136 137 /** 138 * Get the x position 139 * @return the x position 140 */ 141 public Integer getX() { 142 return x; 143 } 144 145 /** 146 * Set the x position 147 * @param x new x position 148 */ 149 public void setX(Integer x) { 150 this.x = x; 151 } 152 153 /** 154 * Get the y position 155 * @return the y position 156 */ 157 public Integer getY() { 158 return y; 159 } 160 161 /** 162 * Set the y position 163 * @param y new y position 164 */ 165 public void setY(Integer y) { 166 this.y = y; 167 } 168 169 /** 170 * Get the dx or horizontal speed 171 * @return the dx speed 172 */ 173 public Integer getDx() { 174 return dx; 175 } 176 177 /** 178 * Set the dx or horizontal speed 179 * @param dx new dx speed 180 */ 181 public void setDx(Integer dx) { 182 this.dx = dx; 183 } 184 185 /** 186 * Get the dy or vertical speed 187 * @return the dy speed 188 */ 189 public Integer getDy() { 190 return dy; 191 } 192 193 /** 194 * Set the dy or vertical speed 195 * @param dy new dy speed 196 */ 197 public void setDy(Integer dy) { 198 this.dy = dy; 199 } 200 201 /** 202 * Get the color 203 * @return the color 204 */ 205 public Color getColor() { 206 return color; 207 } 208 209 /** 210 * Set the color 211 * @param color new color 212 */ 213 public void setColor(Color color) { 214 this.color = color; 215 } 216 217 /** 218 * Set the graphics 219 * @param g the graphics object 220 */ 221 public void draw(Graphics g) { 222 g.setColor(color); 223 g.fillOval(x, y, SIZE, SIZE); 224 } 225 226 /** 227 * Move the sprite based on position, speed, and panel dimensions 228 */ 229 public void move() { 230 231 // check for bounce and make the ball bounce if necessary 232 // 233 if (x < 0 && dx < 0) { 234 //bounce off the left wall 235 x = 0; 236 dx = -dx; 237 } 238 if (y < 0 && dy < 0) { 239 //bounce off the top wall 240 y = 0; 241 dy = -dy; 242 } 243 if (x > panelWidth - SIZE && dx > 0) { 244 //bounce off the right wall 245 x = panelWidth - SIZE; 246 dx = -dx; 247 } 248 if (y > panelHeight - SIZE && dy > 0) { 249 //bounce off the bottom wall 250 y = panelHeight - SIZE; 251 dy = -dy; 252 } 253 254 //make the ball move 255 x += dx; 256 y += dy; 257 } 258 259 /** 260 * Get the id hash code 261 * @return id hash code 262 */ 263 @Override 264 public int hashCode() { 265 int hash = 0; 266 hash += (id != null ? id.hashCode() : 0); 267 return hash; 268 } 269 270 /** 271 * Compare if two sprites are equal 272 * @param object the sprite to compare it to 273 * @return true or false if they are equal 274 */ 275 @Override 276 public boolean equals(Object object) { 277 // TODO: Warning - this method won't work in the case the id fields are not set 278 if (!(object instanceof Sprite)) { 279 return false; 280 } 281 Sprite other = (Sprite) object; 282 if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { 283 return false; 284 } 285 return true; 286 } 287 288 /** 289 * Returns a string of the sprite id 290 * @return string of sprite info 291 */ 292 @Override 293 public String toString() { 294 return "Sprite[ id=" + id + " ]"; 295 } 296 297 } 298
Exported from Notepad++
1 /* 2 Authors: abde 3 File: SpriteFacadeREST.java 4 Description: Routes and handles all the http REST requests implementing AbstractFacade interface 5 */ 6 7 package service; 8 9 import cst.entities.Sprite; 10 import java.awt.Color; 11 import java.util.ArrayList; 12 import java.util.HashSet; 13 import java.util.List; 14 import java.util.Objects; 15 import javax.persistence.EntityManager; 16 import javax.persistence.PersistenceContext; 17 import javax.ws.rs.core.Response; 18 import cst.entities.AbstractFacade; 19 import javax.annotation.security.DeclareRoles; 20 import javax.annotation.security.RolesAllowed; 21 22 /** 23 * Defines our RESTful API endpoints 24 * @author abde 25 */ 26 @javax.ejb.Stateless 27 @javax.ws.rs.Path("sprites") 28 @DeclareRoles({"Admin", "RestGroup"}) 29 public class SpriteFacadeREST extends AbstractFacade<Sprite> { 30 31 @PersistenceContext(unitName = "SpriteUsersPU") 32 private EntityManager em; 33 34 public SpriteFacadeREST() { 35 super(Sprite.class); 36 } 37 38 /** 39 * POST on root resource Without an id - Creates a new sprite without an id 40 * provided With an id - Checks there is a sprite to update, non-existent id 41 * returns error 42 * 43 * @param entity Sprite entity provided sprite values 44 * @return response code with requested information 45 */ 46 @javax.ws.rs.POST 47 @javax.ws.rs.Consumes({javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON}) 48 @RolesAllowed({"Admin", "RestGroup"}) 49 public Response createUpdate(Sprite entity) { 50 // check if id exists 51 Long id = entity.getId(); 52 if (id == null) { 53 // verify the attributes 54 String verification = validateSprite(entity, false, null); 55 if (verification.compareTo("") == 0) { 56 // create new sprite 57 super.create(entity); 58 return Response.status(Response.Status.CREATED).entity("New sprite created").build(); 59 } else { 60 // invalid attribute(s) 61 return Response.status(Response.Status.NOT_ACCEPTABLE).entity(verification).build(); 62 } 63 } else { 64 // check if id exists 65 Sprite sprite = findId(id); 66 if (sprite == null) { 67 // error if no sprite with this ID exists 68 return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Sprite ID cannot be manually set").build(); 69 } else { 70 // verify the attributes 71 String verification = validateSprite(entity, true, sprite); 72 if (verification.compareTo("") == 0) { 73 // update existing sprite 74 updateSprite(entity, sprite); 75 return Response.ok("Sprite with id " + id + " updated").build(); 76 } else { 77 // invalid attribute(s) 78 return Response.status(Response.Status.NOT_ACCEPTABLE).entity(verification).build(); 79 } 80 } 81 } 82 } 83 84 /** 85 * PUT on root resource Unsupported - return error 86 * 87 * @param entity Sprite entity provided sprite values 88 * @return response code with requested information 89 */ 90 @javax.ws.rs.PUT 91 @javax.ws.rs.Consumes({javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON}) 92 @RolesAllowed({"Admin", "RestGroup"}) 93 public Response invCreate(Sprite entity) { 94 return Response.status(Response.Status.NOT_IMPLEMENTED).entity("Can not PUT on the root resource").build(); 95 } 96 97 /** 98 * PUT request with an id Replaces a sprite with the matching id 99 * 100 * @param id provided sprite id 101 * @param entity sprite entity provided sprite values 102 * @return response code with requested information 103 */ 104 @javax.ws.rs.PUT 105 @javax.ws.rs.Path("{id}") 106 @javax.ws.rs.Consumes({javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON}) 107 @RolesAllowed({"Admin", "RestGroup"}) 108 public Response replace(@javax.ws.rs.PathParam("id") Long id, Sprite entity) { 109 // make sure IDs are not contradictory 110 if (entity.getId() != null && !Objects.equals(entity.getId(), id)){ 111 return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Body ID " + entity.getId() + " must be null or match provided ID " + id).build(); 112 } 113 114 // check if id exists 115 Sprite sprite = findId(id); 116 if (sprite == null) { 117 // error if no sprite with this ID exists 118 return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Sprite with ID " + id + " cannot be found").build(); 119 } else { 120 // verify the attributes 121 String verification = validateSprite(entity, false, null); 122 if (verification.compareTo("") == 0) { 123 // replace the sprite 124 entity.setId(id); 125 super.edit(entity); 126 return Response.status(Response.Status.OK).entity("Sprite with id " + id + " replaced").build(); 127 } else { 128 // invalid attribute(s) 129 return Response.status(Response.Status.NOT_ACCEPTABLE).entity(verification).build(); 130 } 131 } 132 } 133 134 /** 135 * POST request with an id Updates a sprite with the matching id with the 136 * non-null values 137 * 138 * @param id provided sprite id 139 * @param entity sprite entity provided sprite values 140 * @return response code with requested information 141 */ 142 @javax.ws.rs.POST 143 @javax.ws.rs.Path("{id}") 144 @javax.ws.rs.Consumes({javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON}) 145 @RolesAllowed({"Admin", "RestGroup"}) 146 public Response update(@javax.ws.rs.PathParam("id") Long id, Sprite entity) { 147 // make sure IDs are not contradictory 148 if (entity.getId() != null && !Objects.equals(entity.getId(), id)){ 149 return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Body ID " + entity.getId() + " must be null or match provided ID " + id).build(); 150 } 151 152 // check if id exists 153 Sprite sprite = findId(id); 154 if (sprite == null) { 155 // error if no sprite with this ID exists 156 return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Sprite with ID " + id + " cannot be found").build(); 157 } else { 158 // verify the attributes 159 String verification = validateSprite(entity, true, sprite); 160 if (verification.compareTo("") == 0) { 161 // update existing sprite 162 updateSprite(entity, sprite); 163 return Response.ok("Sprite with id " + id + " updated").build(); 164 } else { 165 // invalid attribute(s) 166 return Response.status(Response.Status.NOT_ACCEPTABLE).entity(verification).build(); 167 } 168 } 169 } 170 171 /** 172 * DELETE with an id Delete the selected sprite if it exists 173 * 174 * @param id provided sprite id 175 * @return response code with requested information 176 */ 177 @javax.ws.rs.DELETE 178 @javax.ws.rs.Path("{id}") 179 @RolesAllowed({"Admin", "RestGroup"}) 180 public Response remove(@javax.ws.rs.PathParam("id") Long id) { 181 // check if id exists 182 Sprite sprite = findId(id); 183 if (sprite == null) { 184 return Response.status(Response.Status.NOT_ACCEPTABLE).entity("Sprite with ID " + id + " cannot be found").build(); 185 } else { 186 super.remove(super.find(id)); 187 return Response.status(Response.Status.OK).entity("Sprite with id " + id + " removed").build(); 188 } 189 } 190 191 /** 192 * GET with an id Returns found sprite if any 193 * 194 * @param id provided sprite id 195 * @return response code with requested information 196 */ 197 @javax.ws.rs.GET 198 @javax.ws.rs.Path("{id}") 199 @javax.ws.rs.Produces({javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON}) 200 @RolesAllowed({"Admin", "RestGroup"}) 201 public Response find(@javax.ws.rs.PathParam("id") Long id) { 202 // check if id exists 203 Sprite sprite = findId(id); 204 if (sprite == null) { 205 return Response.status(Response.Status.NO_CONTENT).entity("Sprite with ID " + id + " does not exist").build(); 206 } else { 207 return Response.status(Response.Status.OK).entity(sprite).build(); 208 } 209 } 210 211 /** 212 * GET root resource Returns all sprites if any 213 * 214 * @return response code with requested information 215 */ 216 @javax.ws.rs.GET 217 @javax.ws.rs.Produces({javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON}) 218 @RolesAllowed({"Admin", "RestGroup"}) 219 public Response getAll() { 220 List<Sprite> sprites = super.findAll(); 221 if (sprites.isEmpty()) { 222 return Response.status(Response.Status.NO_CONTENT).entity("No sprites exist").build(); 223 } else { 224 return Response.status(Response.Status.OK).entity(sprites).build(); 225 } 226 } 227 228 /** 229 * GET with id range Returns the sprites with applicable ids if any 230 * 231 * @param from beginning id range 232 * @param to end id range 233 * @return response code with requested information 234 */ 235 @javax.ws.rs.GET 236 @javax.ws.rs.Path("{from}/{to}") 237 @javax.ws.rs.Produces({javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON}) 238 @RolesAllowed({"Admin", "RestGroup"}) 239 public Response findRange(@javax.ws.rs.PathParam("from") Integer from, @javax.ws.rs.PathParam("to") Integer to) { 240 //return super.findRange(new int[]{from, to}); 241 List<Sprite> sprites = super.findRange(new int[]{from, to}); 242 if (sprites.isEmpty()) { 243 return Response.status(Response.Status.NO_CONTENT).entity("No sprites exist").build(); 244 } else { 245 return Response.status(Response.Status.OK).entity(sprites).build(); 246 } 247 } 248 249 /** 250 * GET with count Returns the how many sprites there are 251 * 252 * @return response code with requested information 253 */ 254 @javax.ws.rs.GET 255 @javax.ws.rs.Path("count") 256 @javax.ws.rs.Produces({javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON, 257 javax.ws.rs.core.MediaType.TEXT_PLAIN}) 258 @RolesAllowed({"Admin", "RestGroup"}) 259 public Response countREST() { 260 return Response.status(Response.Status.OK).entity(super.count()).build(); 261 } 262 263 /** 264 * Returns an entity manager 265 * 266 * @return entity manager 267 */ 268 @Override 269 protected EntityManager getEntityManager() { 270 return em; 271 // return Response.ok(em).build(); 272 } 273 274 /** 275 * Validates the sprites attributes and returns a string of errors if any 276 * 277 * @param sprite the sprite to validate 278 * @param Boolean whether we are validating for an update or a replace 279 * @param ogSprite sprite being updated for extra validation 280 * @return string of errors if any 281 */ 282 private String validateSprite(Sprite sprite, Boolean update, Sprite ogSprite) { 283 String response = ""; 284 int maxSpeed = Sprite.MAX_SPEED; 285 int size = Sprite.SIZE; 286 List<String> invalidVals = new ArrayList<>(); 287 288 if (((update && sprite.getPanelWidth() != null) || !update) && (sprite.getPanelWidth() == null || sprite.getPanelWidth() <= size)) { 289 invalidVals.add(String.format("PanelWidth (must be whole number greater than sprite size of %d)", size)); 290 } 291 292 if (((update && sprite.getPanelHeight() != null) || !update) && (sprite.getPanelHeight() == null || sprite.getPanelHeight() <= size)) { 293 invalidVals.add(String.format("PanelHeight (must be whole number greater than sprite size of %d)", size)); 294 } 295 296 if ((!update) && (sprite.getX() == null || sprite.getX() < 0 || sprite.getX() > (sprite.getPanelWidth() - size))) { 297 invalidVals.add(String.format("X (must be %d or under, less than PanelWidth (%d) minus size of sprite (%d))", 298 (sprite.getPanelHeight() - size),sprite.getPanelHeight(), size)); 299 } 300 301 if ((!update) && (sprite.getY() == null || sprite.getY() < 0 || sprite.getY() > (sprite.getPanelHeight() - size))) { 302 invalidVals.add(String.format("Y (must be %d or under, less than PanelHeight (%d) minus size of sprite (%d))", 303 (sprite.getPanelHeight() - size), sprite.getPanelHeight(), size)); 304 } 305 306 // validate x and y coordinates for updates 307 if (update){ 308 Integer panelWidth = sprite.getPanelWidth(); 309 Integer x = sprite.getX(); 310 if (panelWidth == null){ 311 panelWidth = ogSprite.getPanelWidth(); 312 } 313 if (x == null){ 314 x = ogSprite.getX(); 315 } 316 if (x < 0 || x > (panelWidth - size)) { 317 invalidVals.add(String.format("X (must be %d or under, less than PanelWidth (%d) minus size of sprite (%d))", 318 (panelWidth - size), panelWidth, size)); 319 } 320 321 Integer panelHeight = sprite.getPanelHeight(); 322 Integer y = sprite.getY(); 323 if (panelHeight == null){ 324 panelHeight = ogSprite.getPanelHeight(); 325 } 326 if (y == null){ 327 y = ogSprite.getY(); 328 } 329 if (y < 0 || y > (panelHeight - size)) { 330 invalidVals.add(String.format("Y (must be %d or under, less than PanelHeight (%d) minus size of sprite (%d))", (panelHeight - size), panelHeight, size)); 331 } 332 } 333 334 335 if (((update && sprite.getDx() != null) || !update) && (sprite.getDx() == null || 336 sprite.getDx() < -1 * (maxSpeed) || sprite.getDx() > maxSpeed)) { 337 invalidVals.add(String.format("dX (must be whole number between -%d to %d)", maxSpeed, maxSpeed)); 338 } 339 340 if (((update && sprite.getDy() != null) || !update) && (sprite.getDy() == null || 341 sprite.getDy() < -1 * (maxSpeed) || sprite.getDy() > maxSpeed)) { 342 invalidVals.add(String.format("dY (must be whole number between -%d to %d)", maxSpeed, maxSpeed)); 343 } 344 345 for (int i = 0; i < invalidVals.size(); i++) { 346 response += invalidVals.get(i); 347 if (i < invalidVals.size()) { 348 response += ", "; 349 } 350 } 351 352 return response; 353 } 354 355 /** 356 * Updates a sprite with received non-null values 357 * 358 * @param entity the updated values 359 * @param sprite the original sprite 360 */ 361 private void updateSprite(Sprite entity, Sprite sprite) { 362 Color color = entity.getColor(); 363 364 if (color != null) { 365 sprite.setColor(color); 366 } 367 368 if (entity.getX() != null) { 369 sprite.setX(entity.getX()); 370 } 371 372 if (entity.getY() != null) { 373 sprite.setY(entity.getY()); 374 } 375 376 if (entity.getDx() != null) { 377 sprite.setDx(entity.getDx()); 378 } 379 380 if (entity.getDy() != null) { 381 sprite.setDy(entity.getDy()); 382 } 383 384 if (entity.getPanelWidth() != null) { 385 sprite.setPanelWidth(entity.getPanelWidth()); 386 } 387 388 if (entity.getPanelHeight() != null) { 389 sprite.setPanelHeight(entity.getPanelHeight()); 390 } 391 392 super.edit(sprite); 393 } 394 395 /** 396 * Find the sprite with a specified id or null 397 * 398 * @param id provided sprite id 399 * @return the sprite with the selected id or null 400 */ 401 private Sprite findId(Long id) { 402 List<Sprite> sprites = super.findAll(); 403 Sprite found = null; 404 for (Sprite sprite : sprites) { 405 if (Objects.equals(sprite.getId(), id)) { 406 found = sprite; 407 return found; 408 } 409 } 410 return found; 411 } 412 413 } 414