+
+
+ @Override
+ @Transactional(readOnly=true)
+ public FieldUnitDTO findFieldUnitDTO(DerivateDTO derivedUnitDTO, Collection<FieldUnitDTO> fieldUnits,
+ HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen) {
+ //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
+ //from which this DerivedUnit was derived until all FieldUnits are found.
+ List<SpecimenOrObservationBase> specimens = new ArrayList<>();
+ List<String> propertyPaths = new ArrayList<>();
+
+ propertyPaths.add("descriptions.elements.media.title");
+ propertyPaths.add("kindOfUnit");
+ propertyPaths.add("derivedFrom");
+
+ specimens = dao.findOriginalsForDerivedUnit(derivedUnitDTO.getUuid(), propertyPaths);
+
+ if (specimens.size() > 1){
+ logger.debug("The derived unit with uuid " + derivedUnitDTO.getUuid() + "has more than one orginal");
+ }
+ // for (SpecimenOrObservationBase specimen: specimens){
+ SpecimenOrObservationBase specimen = null;
+ if (specimens.size() > 0){
+ specimen = specimens.get(0);
+ }else{
+ return null;
+ }
+ FieldUnitDTO fieldUnitDto = null;
+ if (alreadyCollectedSpecimen.get(specimen.getUuid()) != null){
+ alreadyCollectedSpecimen.get(specimen.getUuid()).addDerivate(derivedUnitDTO);
+// if ( alreadyCollectedSpecimen.get(specimen.getUuid()) instanceof FieldUnitDTO){
+// ((FieldUnitDTO)alreadyCollectedSpecimen.get(specimen.getUuid())).getTaxonRelatedDerivedUnits().add(derivedUnitDTO.getUuid());
+// }
+ }else{
+ if (specimen.isInstanceOf(FieldUnit.class)){
+ fieldUnitDto = new FieldUnitDTO((FieldUnit)specimen);
+ fieldUnitDto.addDerivate(derivedUnitDTO);
+ fieldUnits.add(fieldUnitDto);
+
+ }else{
+ DerivateDTO originalDTO;
+ if (specimen instanceof DnaSample){
+ originalDTO = new DNASampleDTO((DnaSample)specimen);
+ } else {
+ originalDTO = new PreservedSpecimenDTO((DerivedUnit)specimen);
+ }
+ originalDTO.addDerivate(derivedUnitDTO);
+ fieldUnitDto = findFieldUnitDTO(originalDTO, fieldUnits,
+ alreadyCollectedSpecimen);
+ }
+
+ }
+ // }
+ alreadyCollectedSpecimen.put(derivedUnitDTO.getUuid(), derivedUnitDTO);
+// if (fieldUnitDto != null){
+// fieldUnitDto.addTaxonRelatedDerivedUnits(derivedUnitDTO);
+// }
+ return fieldUnitDto;
+
+ }
+
+ @Override
+ @Transactional(readOnly=true)
+ public FieldUnitDTO loadFieldUnitDTO(UUID derivedUnitUuid) {
+
+ FieldUnitDTO fieldUnitDTO = null;
+ DerivateDTO derivedUnitDTO = null;
+
+ Map<UUID, DerivateDTO> cycleDetectionMap = new HashMap<>();
+ SpecimenOrObservationBase derivative = dao.load(derivedUnitUuid);
+ if(derivative != null){
+ derivedUnitDTO = DerivateDTO.newInstance(derivative);
+ while(true){
+ Set<DerivateDTO> originals = originalDTOs(derivedUnitUuid);
+
+ if(originals.isEmpty()){
+ break;
+ }
+ if (originals.size() > 1){
+ logger.debug("The derived unit with uuid " + derivedUnitUuid + "has more than one orginal, ignoring all but the first one.");
+ }
+
+ DerivateDTO originalDTO = originals.iterator().next();
+
+ // cycle detection and handling
+ if(cycleDetectionMap.containsKey(originalDTO.getUuid())){
+ // cycle detected!!!
+ try {
+ throw new Exception();
+ } catch(Exception e){
+ logger.error("Cycle in derivate graph detected at DerivedUnit with uuid=" + originalDTO.getUuid() , e);
+ }
+ // to solve the situation for the output we remove the derivate from the more distant graph node
+ // by removing it from the derivatives of its original
+ // but let the derivate to be added to the original which is closer to the FieldUnit (below at originalDTO.addDerivate(derivedUnitDTO);)
+ for(DerivateDTO seenOriginal: cycleDetectionMap.values()){
+ for(DerivateDTO derivateDTO : seenOriginal.getDerivates()){
+ if(derivateDTO.equals(originalDTO)){
+ seenOriginal.getDerivates().remove(originalDTO);
+ }
+ }
+ }
+ } else {
+ cycleDetectionMap.put(originalDTO.getUuid(), originalDTO);
+ }
+
+
+ if (originalDTO instanceof FieldUnitDTO){
+ fieldUnitDTO = (FieldUnitDTO)originalDTO;
+ if(derivedUnitDTO != null){
+ fieldUnitDTO.addDerivate(derivedUnitDTO);
+ }
+ break;
+ }else{
+ if (derivedUnitDTO == null){
+ derivedUnitDTO = originalDTO;
+ } else {
+ originalDTO.addDerivate(derivedUnitDTO);
+ derivedUnitDTO = originalDTO;
+ }
+ }
+ }
+ }
+ return fieldUnitDTO;
+
+ }
+
+ /**
+ * @param originalDTO
+ * @return
+ */
+ private Set<DerivateDTO> originalDTOs(UUID derivativeUuid) {
+
+ Set<DerivateDTO> dtos = new HashSet<>();
+
+ List<SpecimenOrObservationBase> specimens = dao.findOriginalsForDerivedUnit(derivativeUuid, null);
+ for(SpecimenOrObservationBase sob : specimens){
+ dtos.add(DerivateDTO.newInstance(sob));
+ }
+
+ return dtos;
+ }
+
+