View Javadoc
1   package de.dlr.shepard.neo4Core.services;
2   
3   import java.util.ArrayList;
4   import java.util.Date;
5   import java.util.List;
6   
7   import de.dlr.shepard.exceptions.InvalidBodyException;
8   import de.dlr.shepard.neo4Core.dao.CollectionDAO;
9   import de.dlr.shepard.neo4Core.dao.DataObjectDAO;
10  import de.dlr.shepard.neo4Core.dao.UserDAO;
11  import de.dlr.shepard.neo4Core.entities.Collection;
12  import de.dlr.shepard.neo4Core.entities.DataObject;
13  import de.dlr.shepard.neo4Core.entities.User;
14  import de.dlr.shepard.neo4Core.io.DataObjectIO;
15  import de.dlr.shepard.util.DateHelper;
16  import de.dlr.shepard.util.QueryParamHelper;
17  import lombok.extern.slf4j.Slf4j;
18  
19  @Slf4j
20  public class DataObjectService {
21  	private DataObjectDAO dataObjectDAO = new DataObjectDAO();
22  	private CollectionDAO collectionDAO = new CollectionDAO();
23  	private UserDAO userDAO = new UserDAO();
24  	private DateHelper dateHelper = new DateHelper();
25  
26  	/**
27  	 * Creates a DataObject and stores it in Neo4J
28  	 *
29  	 * @param collectionShepardId identifies the Collection
30  	 * @param dataObject          to be stored
31  	 * @param username            of the related user
32  	 * @return the stored DataObject with the auto generated id
33  	 */
34  	public DataObject createDataObjectByCollectionShepardId(long collectionShepardId, DataObjectIO dataObject,
35  			String username) {
36  		Collection collection = collectionDAO.findLightByShepardId(collectionShepardId);
37  		User user = userDAO.find(username);
38  		DataObject parent = findRelatedDataObjectByShepardId(collection.getShepardId(), dataObject.getParentId(), null);
39  		List<DataObject> predecessors = findRelatedDataObjectsByShepardIds(collection.getShepardId(),
40  				dataObject.getPredecessorIds(), null);
41  		DataObject toCreate = new DataObject();
42  		toCreate.setAttributes(dataObject.getAttributes());
43  		toCreate.setDescription(dataObject.getDescription());
44  		toCreate.setName(dataObject.getName());
45  		toCreate.setCollection(collection);
46  		toCreate.setParent(parent);
47  		toCreate.setPredecessors(predecessors);
48  		toCreate.setCreatedAt(dateHelper.getDate());
49  		toCreate.setCreatedBy(user);
50  		DataObject created = dataObjectDAO.createOrUpdate(toCreate);
51  		created.setShepardId(created.getId());
52  		created = dataObjectDAO.createOrUpdate(created);
53  		return created;
54  	}
55  
56  	/**
57  	 * Searches the neo4j database for a dataObject
58  	 *
59  	 * @param shepardId identifies the searched dataObject
60  	 * @return the DataObject with the given id or null
61  	 */
62  	public DataObject getDataObjectByShepardId(long shepardId) {
63  		DataObject dataObject = dataObjectDAO.findByShepardId(shepardId);
64  		if (dataObject == null || dataObject.isDeleted()) {
65  			log.error("Data Object with id {} is null or deleted", shepardId);
66  			return null;
67  		}
68  		cutDeleted(dataObject);
69  		return dataObject;
70  	}
71  
72  	/**
73  	 * Searches the database for DataObjects.
74  	 *
75  	 * @param collectionShepardId  identifies the collection
76  	 * @param paramsWithShepardIds encapsulates possible parameters
77  	 * @return a List of DataObjects
78  	 */
79  	public List<DataObject> getAllDataObjectsByShepardIds(long collectionShepardId,
80  			QueryParamHelper paramsWithShepardIds) {
81  		var unfiltered = dataObjectDAO.findByCollectionByShepardIds(collectionShepardId, paramsWithShepardIds);
82  		var dataObjects = unfiltered.stream().map(this::cutDeleted).toList();
83  		return dataObjects;
84  	}
85  
86  	/**
87  	 * Updates a DataObject with new attributes. Hereby only not null attributes
88  	 * will replace the old attributes.
89  	 *
90  	 * @param dataObjectShepardId Identifies the dataObject
91  	 * @param dataObject          DataObject entity for updating.
92  	 * @param username            of the related user
93  	 * @return updated DataObject.
94  	 */
95  	public DataObject updateDataObjectByShepardId(long dataObjectShepardId, DataObjectIO dataObject, String username) {
96  		DataObject old = dataObjectDAO.findByShepardId(dataObjectShepardId);
97  		User user = userDAO.find(username);
98  		DataObject parent = findRelatedDataObjectByShepardId(old.getCollection().getShepardId(),
99  				dataObject.getParentId(), dataObjectShepardId);
100 		List<DataObject> predecessors = findRelatedDataObjectsByShepardIds(old.getCollection().getShepardId(),
101 				dataObject.getPredecessorIds(), dataObjectShepardId);
102 		old.setAttributes(dataObject.getAttributes());
103 		old.setDescription(dataObject.getDescription());
104 		old.setName(dataObject.getName());
105 		old.setParent(parent);
106 		old.setPredecessors(predecessors);
107 		old.setUpdatedAt(dateHelper.getDate());
108 		old.setUpdatedBy(user);
109 		DataObject updated = dataObjectDAO.createOrUpdate(old);
110 		cutDeleted(updated);
111 		return updated;
112 	}
113 
114 	/**
115 	 * set the deleted flag for the DataObject
116 	 *
117 	 * @param dataObjectShepardId identifies the DataObject to be deleted
118 	 * @param username            of the related user
119 	 * @return a boolean to identify if the DataObject was successfully removed
120 	 */
121 	public boolean deleteDataObjectByShepardId(long dataObjectShepardId, String username) {
122 		Date date = dateHelper.getDate();
123 		User user = userDAO.find(username);
124 		boolean result = dataObjectDAO.deleteDataObjectByShepardId(dataObjectShepardId, user, date);
125 		return result;
126 	}
127 
128 	private DataObject cutDeleted(DataObject dataObject) {
129 		var incoming = dataObject.getIncoming().stream().filter(i -> !i.isDeleted()).toList();
130 		dataObject.setIncoming(incoming);
131 		if (dataObject.getParent() != null && dataObject.getParent().isDeleted()) {
132 			dataObject.setParent(null);
133 		}
134 		var children = dataObject.getChildren().stream().filter(s -> !s.isDeleted()).toList();
135 		dataObject.setChildren(children);
136 		var predecessors = dataObject.getPredecessors().stream().filter(s -> !s.isDeleted()).toList();
137 		dataObject.setPredecessors(predecessors);
138 		var sucessors = dataObject.getSuccessors().stream().filter(s -> !s.isDeleted()).toList();
139 		dataObject.setSuccessors(sucessors);
140 		var references = dataObject.getReferences().stream().filter(ref -> !ref.isDeleted()).toList();
141 		dataObject.setReferences(references);
142 		return dataObject;
143 	}
144 
145 	private List<DataObject> findRelatedDataObjectsByShepardIds(long collectionShepardId, long[] referencedShepardIds,
146 			Long dataObjectShepardId) {
147 		if (referencedShepardIds == null)
148 			return new ArrayList<>();
149 
150 		var result = new ArrayList<DataObject>(referencedShepardIds.length);
151 		/*
152 		 * TODO: seems to be inefficient since this loops generates referencedIds.length
153 		 * calls to Neo4j this could possibly be packed into one query (or in chunks of
154 		 * queries in case of a large referencedIds array)
155 		 */
156 		for (var shepardId : referencedShepardIds) {
157 			result.add(findRelatedDataObjectByShepardId(collectionShepardId, shepardId, dataObjectShepardId));
158 		}
159 		return result;
160 	}
161 
162 	private DataObject findRelatedDataObjectByShepardId(long collectionShepardId, Long referencedShepardId,
163 			Long dataObjectShepardId) {
164 		if (referencedShepardId == null)
165 			return null;
166 		else if (referencedShepardId.equals(dataObjectShepardId))
167 			throw new InvalidBodyException("Self references are not allowed.");
168 
169 		var dataObject = dataObjectDAO.findByShepardId(referencedShepardId);
170 		if (dataObject == null || dataObject.isDeleted())
171 			throw new InvalidBodyException(
172 					String.format("The DataObject with id %d could not be found.", referencedShepardId));
173 
174 		// Prevent cross collection references
175 		if (!dataObject.getCollection().getShepardId().equals(collectionShepardId))
176 			throw new InvalidBodyException(
177 					"Related data objects must belong to the same collection as the new data object");
178 
179 		return dataObject;
180 	}
181 
182 }