LocationGroupController.java
/*
* Copyright 2005-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openwms.common.location;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.ameba.exception.NotFoundException;
import org.ameba.http.MeasuredRestController;
import org.ameba.i18n.Translator;
import org.openwms.common.SimpleLink;
import org.openwms.common.location.api.ErrorCodeTransformers;
import org.openwms.common.location.api.ErrorCodeVO;
import org.openwms.common.location.api.LocationGroupState;
import org.openwms.common.location.api.LocationGroupVO;
import org.openwms.common.location.api.ValidationGroups;
import org.openwms.core.SpringProfiles;
import org.openwms.core.http.AbstractWebController;
import org.openwms.core.http.Index;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Profile;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import static java.util.Arrays.asList;
import static org.openwms.common.CommonMessageCodes.LOCATION_GROUP_NOT_FOUND;
import static org.openwms.common.location.api.LocationApiConstants.API_LOCATION_GROUP;
import static org.openwms.common.location.api.LocationApiConstants.API_LOCATION_GROUPS;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
/**
* A LocationGroupController.
*
* @author Heiko Scherrer
*/
@Profile("!" + SpringProfiles.IN_MEMORY)
@Validated
@RefreshScope
@MeasuredRestController
public class LocationGroupController extends AbstractWebController {
public static final String PARENT = "parent";
private final Translator translator;
private final LocationGroupService locationGroupService;
private final LocationGroupMapper mapper;
private final ErrorCodeTransformers.GroupStateIn groupStateIn;
private final ErrorCodeTransformers.GroupStateOut groupStateOut;
LocationGroupController(Translator translator, LocationGroupService locationGroupService, LocationGroupMapper mapper,
ErrorCodeTransformers.GroupStateIn groupStateIn,
ErrorCodeTransformers.GroupStateOut groupStateOut) {
this.translator = translator;
this.locationGroupService = locationGroupService;
this.mapper = mapper;
this.groupStateIn = groupStateIn;
this.groupStateOut = groupStateOut;
}
/**
* Creates a new location group.
*
* @param vo The LocationGroupVO object containing the data for the new location group. The object must be
* validated using the annotated constraints specified in the ValidationGroups.Create interface.
* @return A ResponseEntity object containing the LocationGroupVO of the newly created location group,
* or an empty ResponseEntity if the creation failed.
*/
@PostMapping(API_LOCATION_GROUPS)
public ResponseEntity<LocationGroupVO> create(@Validated(ValidationGroups.Create.class) @Valid @RequestBody LocationGroupVO vo, HttpServletRequest req) {
var result = locationGroupService.create(vo);
var location = getLocationURIForCreatedResource(req, result.getPersistentKey());
return ResponseEntity.created(location).body(mapper.convertToVO(result));
}
@Transactional(readOnly = true)
@GetMapping(value = API_LOCATION_GROUPS, params = {"name"})
public LocationGroupVO findByName(
@RequestParam("name") String name
) {
var locationGroup = locationGroupService.findByName(name)
.orElseThrow(() -> new NotFoundException(translator, LOCATION_GROUP_NOT_FOUND, new String[]{name}, name));
var result = mapper.convertToVO(locationGroup);
if (locationGroup.hasParent()) {
result.add(new SimpleLink(linkTo(methodOn(LocationGroupController.class)
.findByName(locationGroup.getParent().getName())).withRel(PARENT)));
}
return result;
}
@Transactional(readOnly = true)
@GetMapping(value = API_LOCATION_GROUPS, params = {"names"})
public List<LocationGroupVO> findByNames(
@RequestParam("names") List<String> names
) {
var vos = mapper.convertToVO(locationGroupService.findByNames(names));
vos.forEach(lg -> {
if (lg.hasParent()) {
lg.add(new SimpleLink(linkTo(methodOn(LocationGroupController.class)
.findByName(lg.getParent())).withRel(PARENT)));
}
});
return vos;
}
@Transactional(readOnly = true)
@GetMapping(API_LOCATION_GROUPS)
public List<LocationGroupVO> findAll() {
var result = mapper.convertToVO(locationGroupService.findAll());
result.forEach(lg -> {
if (lg.hasParent()) {
lg.add(new SimpleLink(linkTo(methodOn(LocationGroupController.class)
.findByName(lg.getParent())).withRel(PARENT)));
}
}
);
return result;
}
@PatchMapping(value = API_LOCATION_GROUPS, params = {"name", "op=change-state"})
public ResponseEntity<Void> changeGroupState(
@RequestParam(name = "name") String name,
@RequestParam(name = "op") String op,
@RequestBody ErrorCodeVO errorCode
) {
locationGroupService.changeGroupStates(
name,
groupStateIn.available(errorCode.getErrorCode()),
groupStateOut.available(errorCode.getErrorCode())
);
return ResponseEntity.ok().build();
}
@PatchMapping(value = API_LOCATION_GROUP + "/{pKey}", params = "op=change-state")
public ResponseEntity<Void> changeGroupState(
@PathVariable String pKey,
@RequestParam(name = "op") String op,
@RequestParam(name = "statein") LocationGroupState stateIn,
@RequestParam(name = "stateout") LocationGroupState stateOut
) {
locationGroupService.changeGroupState(pKey, stateIn, stateOut);
return ResponseEntity.ok().build();
}
@DeleteMapping(value = API_LOCATION_GROUPS + "/{pKey}")
public ResponseEntity<Void> deleteLocationGroup(@PathVariable("pKey") String pKey) {
locationGroupService.delete(pKey);
return ResponseEntity.noContent().build();
}
@PatchMapping(value = API_LOCATION_GROUPS + "/{pKey}")
public ResponseEntity<Void> modifyLocationGroup(
@PathVariable String pKey,
@RequestBody LocationGroupVO locationGroupVO
) {
locationGroupService.update(pKey, locationGroupVO);
return ResponseEntity.ok().build();
}
@GetMapping(API_LOCATION_GROUPS + "/index")
public ResponseEntity<Index> index() {
return ResponseEntity.ok(
new Index(
linkTo(methodOn(LocationGroupController.class).create(LocationGroupVO.create("FOO", "INFEED_AND_OUTFEED"), null)).withRel("location-groups-create"),
linkTo(methodOn(LocationGroupController.class).deleteLocationGroup("UUID")).withRel("location-groups-delete"),
linkTo(methodOn(LocationGroupController.class).findByName("FOO")).withRel("location-groups-findbyname"),
linkTo(methodOn(LocationGroupController.class).findByNames(asList("FOO", "BAR"))).withRel("location-groups-findbynames"),
linkTo(methodOn(LocationGroupController.class).findAll()).withRel("location-groups-findall"),
linkTo(methodOn(LocationGroupController.class).changeGroupState("UUID", "change-state", LocationGroupState.AVAILABLE, LocationGroupState.NOT_AVAILABLE)).withRel("location-groups-changestate"),
linkTo(methodOn(LocationGroupController.class).changeGroupState("FOO", "change-state", ErrorCodeVO.LOCK_STATE_IN_AND_OUT)).withRel("location-groups-changestate-with-bitmap"),
linkTo(methodOn(LocationGroupController.class).modifyLocationGroup("FOO", null)).withRel("location-groups-modify")
)
);
}
}