added flag for add new pet

This commit is contained in:
XTiNCT 2026-02-08 14:00:35 +05:30
parent c518db81a2
commit b17b470db9
10 changed files with 376 additions and 375 deletions

View file

@ -7,42 +7,39 @@ import java.lang.annotation.Target;
/**
* Custom annotation to mark methods protected by feature toggle
*
*
* Usage:
* @FeatureToggle(key = "add-new-pet")
* public String processNewPetForm(...) {
* // method implementation
* }
*
*
* @FeatureToggle(key = "add-new-pet") public String processNewPetForm(...) { // method
* implementation }
*
* With context extraction:
* @FeatureToggle(key = "owner-search", contextParam = "name")
* public String processFindForm(@RequestParam("name") String name, ...) {
* // method implementation
* }
* @FeatureToggle(key = "owner-search", contextParam = "name") public String
* processFindForm(@RequestParam("name") String name, ...) { // method implementation }
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FeatureToggle {
/**
* The feature flag key to check
*/
String key();
/**
* Optional: name of the parameter to use as context
* If specified, the value of this parameter will be used for whitelist/blacklist/percentage evaluation
*/
String contextParam() default "";
/**
* Optional: custom message to show when feature is disabled
*/
String disabledMessage() default "This feature is currently disabled";
/**
* Optional: redirect path when feature is disabled
* If empty, will show error message
*/
String disabledRedirect() default "";
/**
* The feature flag key to check
*/
String key();
/**
* Optional: name of the parameter to use as context If specified, the value of this
* parameter will be used for whitelist/blacklist/percentage evaluation
*/
String contextParam() default "";
/**
* Optional: custom message to show when feature is disabled
*/
String disabledMessage() default "This feature is currently disabled";
/**
* Optional: redirect path when feature is disabled If empty, will show error message
*/
String disabledRedirect() default "";
}

View file

@ -20,149 +20,145 @@ import org.springframework.samples.petclinic.featureflag.dto.*;
@RestController
@RequestMapping("/feature-flags")
public class FeatureFlagController {
private final FeatureFlagService featureFlagService;
public FeatureFlagController(FeatureFlagService featureFlagService) {
this.featureFlagService = featureFlagService;
}
private final FeatureFlagService featureFlagService;
/**
* GET /api/feature-flags
* Get all feature flags
*/
@GetMapping
public ResponseEntity<List<FeatureFlagResponse>> getAllFlags() {
List<FeatureFlagResponse> flags = featureFlagService.getAllFlags()
.stream()
.map(FeatureFlagResponse::fromEntity)
.collect(Collectors.toList());
return ResponseEntity.ok(flags);
}
public FeatureFlagController(FeatureFlagService featureFlagService) {
this.featureFlagService = featureFlagService;
}
/**
* GET /api/feature-flags/{id}
* Get a specific feature flag by ID
*/
@GetMapping("/{id}")
public ResponseEntity<FeatureFlagResponse> getFlagById(@PathVariable Long id) {
return featureFlagService.getFlagById(id)
.map(FeatureFlagResponse::fromEntity)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
/**
* GET /api/feature-flags Get all feature flags
*/
@GetMapping
public ResponseEntity<List<FeatureFlagResponse>> getAllFlags() {
List<FeatureFlagResponse> flags = featureFlagService.getAllFlags()
.stream()
.map(FeatureFlagResponse::fromEntity)
.collect(Collectors.toList());
return ResponseEntity.ok(flags);
}
/**
* GET /api/feature-flags/key/{flagKey}
* Get a specific feature flag by key
*/
@GetMapping("/key/{flagKey}")
public ResponseEntity<FeatureFlagResponse> getFlagByKey(@PathVariable String flagKey) {
return featureFlagService.getFlagByKey(flagKey)
.map(FeatureFlagResponse::fromEntity)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
/**
* GET /api/feature-flags/{id} Get a specific feature flag by ID
*/
@GetMapping("/{id}")
public ResponseEntity<FeatureFlagResponse> getFlagById(@PathVariable Long id) {
return featureFlagService.getFlagById(id)
.map(FeatureFlagResponse::fromEntity)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
/**
* POST /api/feature-flags
* Create a new feature flag
*/
@PostMapping
public ResponseEntity<?> createFlag(@RequestBody FeatureFlagRequest request) {
try {
FeatureFlag flag = request.toEntity();
FeatureFlag created = featureFlagService.createFlag(flag);
return ResponseEntity.status(HttpStatus.CREATED)
.body(FeatureFlagResponse.fromEntity(created));
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
}
/**
* GET /api/feature-flags/key/{flagKey} Get a specific feature flag by key
*/
@GetMapping("/key/{flagKey}")
public ResponseEntity<FeatureFlagResponse> getFlagByKey(@PathVariable String flagKey) {
return featureFlagService.getFlagByKey(flagKey)
.map(FeatureFlagResponse::fromEntity)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
/**
* PUT /api/feature-flags/{id}
* Update an existing feature flag
*/
@PutMapping("/{id}")
public ResponseEntity<?> updateFlag(@PathVariable Long id, @RequestBody FeatureFlagRequest request) {
try {
FeatureFlag flag = request.toEntity();
FeatureFlag updated = featureFlagService.updateFlag(id, flag);
return ResponseEntity.ok(FeatureFlagResponse.fromEntity(updated));
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
}
/**
* POST /api/feature-flags Create a new feature flag
*/
@PostMapping
public ResponseEntity<?> createFlag(@RequestBody FeatureFlagRequest request) {
try {
FeatureFlag flag = request.toEntity();
FeatureFlag created = featureFlagService.createFlag(flag);
return ResponseEntity.status(HttpStatus.CREATED).body(FeatureFlagResponse.fromEntity(created));
}
catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
}
/**
* DELETE /api/feature-flags/{id}
* Delete a feature flag
*/
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteFlag(@PathVariable Long id) {
try {
featureFlagService.deleteFlag(id);
return ResponseEntity.noContent().build();
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
}
/**
* PUT /api/feature-flags/{id} Update an existing feature flag
*/
@PutMapping("/{id}")
public ResponseEntity<?> updateFlag(@PathVariable Long id, @RequestBody FeatureFlagRequest request) {
try {
FeatureFlag flag = request.toEntity();
FeatureFlag updated = featureFlagService.updateFlag(id, flag);
return ResponseEntity.ok(FeatureFlagResponse.fromEntity(updated));
}
catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
}
/**
* POST /api/feature-flags/{flagKey}/toggle
* Toggle a feature flag on/off
*/
@PostMapping("/{flagKey}/toggle")
public ResponseEntity<?> toggleFlag(@PathVariable String flagKey) {
try {
FeatureFlag toggled = featureFlagService.toggleFlag(flagKey);
return ResponseEntity.ok(FeatureFlagResponse.fromEntity(toggled));
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
}
/**
* DELETE /api/feature-flags/{id} Delete a feature flag
*/
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteFlag(@PathVariable Long id) {
try {
featureFlagService.deleteFlag(id);
return ResponseEntity.noContent().build();
}
catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
}
/**
* POST /api/feature-flags/check
* Check if a feature is enabled for a given context
*/
@PostMapping("/check")
public ResponseEntity<FeatureCheckResponse> checkFeature(@RequestBody FeatureCheckRequest request) {
boolean enabled = featureFlagService.isFeatureEnabled(request.getFlagKey(), request.getContext());
FeatureCheckResponse response = new FeatureCheckResponse(
request.getFlagKey(),
enabled,
request.getContext());
return ResponseEntity.ok(response);
}
/**
* POST /api/feature-flags/{flagKey}/toggle Toggle a feature flag on/off
*/
@PostMapping("/{flagKey}/toggle")
public ResponseEntity<?> toggleFlag(@PathVariable String flagKey) {
try {
FeatureFlag toggled = featureFlagService.toggleFlag(flagKey);
return ResponseEntity.ok(FeatureFlagResponse.fromEntity(toggled));
}
catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
}
/**
* GET /api/feature-flags/check/{flagKey}
* Check if a feature is enabled (simple check without context)
*/
@GetMapping("/check/{flagKey}")
public ResponseEntity<FeatureCheckResponse> checkFeatureSimple(@PathVariable String flagKey) {
boolean enabled = featureFlagService.isFeatureEnabled(flagKey);
FeatureCheckResponse response = new FeatureCheckResponse(flagKey, enabled, null);
return ResponseEntity.ok(response);
}
/**
* POST /api/feature-flags/check Check if a feature is enabled for a given context
*/
@PostMapping("/check")
public ResponseEntity<FeatureCheckResponse> checkFeature(@RequestBody FeatureCheckRequest request) {
boolean enabled = featureFlagService.isFeatureEnabled(request.getFlagKey(), request.getContext());
FeatureCheckResponse response = new FeatureCheckResponse(request.getFlagKey(), enabled, request.getContext());
return ResponseEntity.ok(response);
}
/**
* Error response class
*/
public static class ErrorResponse {
private String error;
/**
* GET /api/feature-flags/check/{flagKey} Check if a feature is enabled (simple check
* without context)
*/
@GetMapping("/check/{flagKey}")
public ResponseEntity<FeatureCheckResponse> checkFeatureSimple(@PathVariable String flagKey) {
boolean enabled = featureFlagService.isFeatureEnabled(flagKey);
FeatureCheckResponse response = new FeatureCheckResponse(flagKey, enabled, null);
return ResponseEntity.ok(response);
}
public ErrorResponse(String error) {
this.error = error;
}
/**
* Error response class
*/
public static class ErrorResponse {
public String getError() {
return error;
}
private String error;
public ErrorResponse(String error) {
this.error = error;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}
public void setError(String error) {
this.error = error;
}
}
}

View file

@ -2,24 +2,24 @@ package org.springframework.samples.petclinic.featureflag.dto;
public class FeatureCheckRequest {
private String flagKey;
private String flagKey;
private String context;
private String context;
public String getFlagKey() {
return flagKey;
}
public String getFlagKey() {
return flagKey;
}
public void setFlagKey(String flagKey) {
this.flagKey = flagKey;
}
public void setFlagKey(String flagKey) {
this.flagKey = flagKey;
}
public String getContext() {
return context;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public void setContext(String context) {
this.context = context;
}
}

View file

@ -1,39 +1,41 @@
package org.springframework.samples.petclinic.featureflag.dto;
public class FeatureCheckResponse {
private String flagKey;
private Boolean enabled;
private String flagKey;
private String context;
private Boolean enabled;
public FeatureCheckResponse(String flagKey, Boolean enabled, String context) {
this.flagKey = flagKey;
this.enabled = enabled;
this.context = context;
}
private String context;
public String getFlagKey() {
return flagKey;
}
public FeatureCheckResponse(String flagKey, Boolean enabled, String context) {
this.flagKey = flagKey;
this.enabled = enabled;
this.context = context;
}
public void setFlagKey(String flagKey) {
this.flagKey = flagKey;
}
public String getFlagKey() {
return flagKey;
}
public Boolean getEnabled() {
return enabled;
}
public void setFlagKey(String flagKey) {
this.flagKey = flagKey;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Boolean getEnabled() {
return enabled;
}
public String getContext() {
return context;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public void setContext(String context) {
this.context = context;
}
}

View file

@ -7,89 +7,90 @@ import org.springframework.samples.petclinic.featureflag.entity.FlagType;
public class FeatureFlagRequest {
private String flagKey;
private String flagKey;
private String description;
private String description;
private FlagType flagType;
private FlagType flagType;
private Boolean enabled;
private Boolean enabled;
private Integer percentage;
private Integer percentage;
private Set<String> whitelist;
private Set<String> whitelist;
private Set<String> blacklist;
private Set<String> blacklist;
// Getters and Setters
public String getFlagKey() {
return flagKey;
}
// Getters and Setters
public String getFlagKey() {
return flagKey;
}
public void setFlagKey(String flagKey) {
this.flagKey = flagKey;
}
public void setFlagKey(String flagKey) {
this.flagKey = flagKey;
}
public String getDescription() {
return description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void setDescription(String description) {
this.description = description;
}
public FlagType getFlagType() {
return flagType;
}
public FlagType getFlagType() {
return flagType;
}
public void setFlagType(FlagType flagType) {
this.flagType = flagType;
}
public void setFlagType(FlagType flagType) {
this.flagType = flagType;
}
public Boolean getEnabled() {
return enabled;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Integer getPercentage() {
return percentage;
}
public Integer getPercentage() {
return percentage;
}
public void setPercentage(Integer percentage) {
this.percentage = percentage;
}
public void setPercentage(Integer percentage) {
this.percentage = percentage;
}
public Set<String> getWhitelist() {
return whitelist;
}
public Set<String> getWhitelist() {
return whitelist;
}
public void setWhitelist(Set<String> whitelist) {
this.whitelist = whitelist;
}
public void setWhitelist(Set<String> whitelist) {
this.whitelist = whitelist;
}
public Set<String> getBlacklist() {
return blacklist;
}
public Set<String> getBlacklist() {
return blacklist;
}
public void setBlacklist(Set<String> blacklist) {
this.blacklist = blacklist;
}
public void setBlacklist(Set<String> blacklist) {
this.blacklist = blacklist;
}
/**
* Convert DTO to Entity
*/
public FeatureFlag toEntity() {
FeatureFlag flag = new FeatureFlag();
flag.setFlagKey(this.flagKey);
flag.setDescription(this.description);
flag.setFlagType(this.flagType != null ? this.flagType : FlagType.SIMPLE);
flag.setEnabled(this.enabled != null ? this.enabled : false);
flag.setPercentage(this.percentage);
flag.setWhitelist(this.whitelist != null ? this.whitelist : Set.of());
flag.setBlacklist(this.blacklist != null ? this.blacklist : Set.of());
return flag;
}
/**
* Convert DTO to Entity
*/
public FeatureFlag toEntity() {
FeatureFlag flag = new FeatureFlag();
flag.setFlagKey(this.flagKey);
flag.setDescription(this.description);
flag.setFlagType(this.flagType != null ? this.flagType : FlagType.SIMPLE);
flag.setEnabled(this.enabled != null ? this.enabled : false);
flag.setPercentage(this.percentage);
flag.setWhitelist(this.whitelist != null ? this.whitelist : Set.of());
flag.setBlacklist(this.blacklist != null ? this.blacklist : Set.of());
return flag;
}
}

View file

@ -7,121 +7,120 @@ import org.springframework.samples.petclinic.featureflag.entity.FlagType;
public class FeatureFlagResponse {
private Long id;
private Long id;
private String flagKey;
private String flagKey;
private String description;
private String description;
private FlagType flagType;
private FlagType flagType;
private Boolean enabled;
private Boolean enabled;
private Integer percentage;
private Integer percentage;
private Set<String> whitelist;
private Set<String> whitelist;
private Set<String> blacklist;
private Set<String> blacklist;
private String createdAt;
private String createdAt;
private String updatedAt;
private String updatedAt;
public static FeatureFlagResponse fromEntity(FeatureFlag flag) {
FeatureFlagResponse response = new FeatureFlagResponse();
response.setId(flag.getId());
response.setFlagKey(flag.getFlagKey());
response.setDescription(flag.getDescription());
response.setFlagType(flag.getFlagType());
response.setEnabled(flag.isEnabled());
response.setPercentage(flag.getPercentage());
response.setWhitelist(flag.getWhitelist());
response.setBlacklist(flag.getBlacklist());
response.setCreatedAt(flag.getCreatedAt().toString());
response.setUpdatedAt(flag.getUpdatedAt().toString());
return response;
}
public static FeatureFlagResponse fromEntity(FeatureFlag flag) {
FeatureFlagResponse response = new FeatureFlagResponse();
response.setId(flag.getId());
response.setFlagKey(flag.getFlagKey());
response.setDescription(flag.getDescription());
response.setFlagType(flag.getFlagType());
response.setEnabled(flag.isEnabled());
response.setPercentage(flag.getPercentage());
response.setWhitelist(flag.getWhitelist());
response.setBlacklist(flag.getBlacklist());
response.setCreatedAt(flag.getCreatedAt().toString());
response.setUpdatedAt(flag.getUpdatedAt().toString());
return response;
}
// Getters and Setters
public Long getId() {
return id;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setId(Long id) {
this.id = id;
}
public String getFlagKey() {
return flagKey;
}
public String getFlagKey() {
return flagKey;
}
public void setFlagKey(String flagKey) {
this.flagKey = flagKey;
}
public void setFlagKey(String flagKey) {
this.flagKey = flagKey;
}
public String getDescription() {
return description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void setDescription(String description) {
this.description = description;
}
public FlagType getFlagType() {
return flagType;
}
public FlagType getFlagType() {
return flagType;
}
public void setFlagType(FlagType flagType) {
this.flagType = flagType;
}
public void setFlagType(FlagType flagType) {
this.flagType = flagType;
}
public Boolean getEnabled() {
return enabled;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Integer getPercentage() {
return percentage;
}
public Integer getPercentage() {
return percentage;
}
public void setPercentage(Integer percentage) {
this.percentage = percentage;
}
public void setPercentage(Integer percentage) {
this.percentage = percentage;
}
public Set<String> getWhitelist() {
return whitelist;
}
public Set<String> getWhitelist() {
return whitelist;
}
public void setWhitelist(Set<String> whitelist) {
this.whitelist = whitelist;
}
public void setWhitelist(Set<String> whitelist) {
this.whitelist = whitelist;
}
public Set<String> getBlacklist() {
return blacklist;
}
public Set<String> getBlacklist() {
return blacklist;
}
public void setBlacklist(Set<String> blacklist) {
this.blacklist = blacklist;
}
public void setBlacklist(Set<String> blacklist) {
this.blacklist = blacklist;
}
public String getCreatedAt() {
return createdAt;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}
}

View file

@ -10,13 +10,13 @@ import org.springframework.samples.petclinic.featureflag.entity.FlagType;
import org.springframework.samples.petclinic.featureflag.repository.FeatureFlagRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Feature Flag Service - Core service for managing and evaluating feature flags
*
* This service provides:
* - CRUD operations for feature flags
* - Advanced flag evaluation with multiple strategies
* - Helper methods for easy integration anywhere in the application
*
* This service provides: - CRUD operations for feature flags - Advanced flag evaluation
* with multiple strategies - Helper methods for easy integration anywhere in the
* application
*/
@Service
@Transactional
@ -31,9 +31,8 @@ public class FeatureFlagService {
}
/**
* Main helper function to check if a feature is enabled
* Can be called from anywhere in the application
*
* Main helper function to check if a feature is enabled Can be called from anywhere
* in the application
* @param flagKey The unique identifier for the feature flag
* @return true if feature is enabled, false otherwise
*/
@ -43,7 +42,6 @@ public class FeatureFlagService {
/**
* Check if feature is enabled for a specific context/user
*
* @param flagKey The unique identifier for the feature flag
* @param context Context identifier (e.g., userId, sessionId, email)
* @return true if feature is enabled for this context, false otherwise
@ -69,12 +67,10 @@ public class FeatureFlagService {
}
/**
* Evaluate a feature flag based on its type and configuration
* Evaluation order (highest to lowest priority):
* 1. GLOBAL_DISABLE - always returns false
* 2. Blacklist - if context is blacklisted, return false
* 3. Enabled check - if not enabled, return false
* 4. Type-specific evaluation (WHITELIST, PERCENTAGE, SIMPLE)
* Evaluate a feature flag based on its type and configuration Evaluation order
* (highest to lowest priority): 1. GLOBAL_DISABLE - always returns false 2. Blacklist
* - if context is blacklisted, return false 3. Enabled check - if not enabled, return
* false 4. Type-specific evaluation (WHITELIST, PERCENTAGE, SIMPLE)
*/
private boolean evaluateFlag(FeatureFlag flag, String context) {
// GLOBAL_DISABLE always returns false
@ -154,8 +150,8 @@ public class FeatureFlagService {
int bucket = hash % 100;
boolean enabled = bucket < flag.getPercentage();
logger.debug("Percentage flag '{}' for context '{}': bucket={}, percentage={}, enabled={}",
flag.getFlagKey(), context, bucket, flag.getPercentage(), enabled);
logger.debug("Percentage flag '{}' for context '{}': bucket={}, percentage={}, enabled={}", flag.getFlagKey(),
context, bucket, flag.getPercentage(), enabled);
return enabled;
}

View file

@ -22,6 +22,7 @@ import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.samples.petclinic.featureflag.service.FeatureFlagService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
@ -51,9 +52,11 @@ class OwnerController {
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
private final OwnerRepository owners;
private final FeatureFlagService featureFlagService;
public OwnerController(OwnerRepository owners) {
public OwnerController(OwnerRepository owners, FeatureFlagService featureFlagService) {
this.owners = owners;
this.featureFlagService = featureFlagService;
}
@InitBinder
@ -170,6 +173,10 @@ class OwnerController {
Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(
"Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));
mav.addObject(owner);
// displaying add pet button based on feature toggle
boolean addNewPetEnabled = featureFlagService.isFeatureEnabled("ADD_NEW_PET","addNewPetEnabled");
mav.addObject("addNewPetEnabled", addNewPetEnabled);
return mav;
}

View file

@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import org.springframework.samples.petclinic.featureflag.annotation.FeatureToggle;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.Assert;
@ -95,6 +96,7 @@ class PetController {
dataBinder.setValidator(new PetValidator());
}
@FeatureToggle(key = "ADD_NEW_PET", disabledMessage = "Adding new pets is currently disabled", disabledRedirect = "/owners/{ownerId}")
@GetMapping("/pets/new")
public String initCreationForm(Owner owner, ModelMap model) {
Pet pet = new Pet();
@ -102,6 +104,7 @@ class PetController {
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
}
@FeatureToggle(key = "ADD_NEW_PET", disabledMessage = "Adding new pets is currently disabled", disabledRedirect = "/owners/{ownerId}")
@PostMapping("/pets/new")
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result,
RedirectAttributes redirectAttributes) {
@ -159,8 +162,9 @@ class PetController {
/**
* Updates the pet details if it exists or adds a new pet to the owner.
*
* @param owner The owner of the pet
* @param pet The pet with updated details
* @param pet The pet with updated details
*/
private void updatePetDetails(Owner owner, Pet pet) {
Integer id = pet.getId();
@ -171,8 +175,7 @@ class PetController {
existingPet.setName(pet.getName());
existingPet.setBirthDate(pet.getBirthDate());
existingPet.setType(pet.getType());
}
else {
} else {
owner.addPet(pet);
}
this.owners.save(owner);

View file

@ -35,7 +35,7 @@
<a th:href="@{__${owner.id}__/edit}" class="btn btn-primary" th:text="#{editOwner}">Edit
Owner</a>
<a th:href="@{__${owner.id}__/pets/new}" class="btn btn-primary" th:text="#{addNewPet}">Add
<a th:if="${addNewPetEnabled}" th:href="@{__${owner.id}__/pets/new}" class="btn btn-primary" th:text="#{addNewPet}">Add
New Pet</a>
<br />