1 /*
2 * The coLAB project
3 * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO
4 *
5 * Licensed under the MIT License
6 */
7 package ch.colabproject.colab.api.persistence.jpa.document;
8
9 import ch.colabproject.colab.api.exceptions.ColabMergeException;
10 import ch.colabproject.colab.api.model.document.AbstractResource;
11 import ch.colabproject.colab.api.model.document.Resource;
12 import ch.colabproject.colab.api.model.document.ResourceRef;
13 import java.util.List;
14 import java.util.stream.Collectors;
15 import javax.ejb.LocalBean;
16 import javax.ejb.Stateless;
17 import javax.persistence.EntityManager;
18 import javax.persistence.PersistenceContext;
19 import javax.persistence.TypedQuery;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 /**
24 * Resource and resource reference persistence
25 * <p>
26 * Note : Most of database operations are handled by managed entities and cascade.
27 *
28 * @author sandra
29 */
30 @Stateless
31 @LocalBean
32 public class ResourceDao {
33
34 /** logger */
35 private static final Logger logger = LoggerFactory.getLogger(ResourceDao.class);
36
37 /**
38 * Access to the persistence unit
39 */
40 @PersistenceContext(unitName = "COLAB_PU")
41 private EntityManager em;
42
43 // /**
44 // * Find a resource by id
45 // *
46 // * @param id the id of the resource to fetch
47 // *
48 // * @return the resource with the given id or null if such a resource does not exist
49 // */
50 // private Resource findResource(Long id) {
51 // logger.trace("find resource #{}", id);
52 //
53 // return em.find(Resource.class, id);
54 // }
55
56 // /**
57 // * Find a resource reference by id
58 // *
59 // * @param id the id of the resource reference to fetch
60 // *
61 // * @return the resource reference with the given id or null if such a resource reference does
62 // * not exist
63 // */
64 // private ResourceRef findResourceRef(Long id) {
65 // logger.trace("find resource reference #{}", id);
66 //
67 // return em.find(ResourceRef.class, id);
68 // }
69
70 /**
71 * @param id the id of the resource / resource reference to fetch
72 *
73 * @return the resource / resource reference with the given id or null if such a resource /
74 * resource reference does not exist
75 */
76 public AbstractResource findResourceOrRef(Long id) {
77 logger.trace("find abstract resource #{}", id);
78
79 return em.find(AbstractResource.class, id);
80 }
81
82 /**
83 * Retrieve the resources references that have the given target
84 *
85 * @param target the target
86 *
87 * @return the matching references
88 */
89 public List<ResourceRef> findDirectReferences(AbstractResource target) {
90 logger.trace("find the direct references of the target {}", target);
91
92 TypedQuery<ResourceRef> query = em.createNamedQuery("ResourceRef.findDirectReferences",
93 ResourceRef.class);
94
95 query.setParameter("targetId", target.getId());
96
97 return query.getResultList();
98 }
99
100 /**
101 * Retrieve all resources which transitively references the given target
102 *
103 * @param target the target
104 *
105 * @return the matching references
106 */
107 public List<ResourceRef> findAllReferences(AbstractResource target) {
108 logger.trace("find all references to the target {}", target);
109
110 // first, fetch direct references
111 List<ResourceRef> list = findDirectReferences(target);
112
113 // and recurse
114 list.addAll(list.stream().flatMap(res -> {
115 return findAllReferences(res).stream();
116 }).collect(Collectors.toList()));
117
118 return list;
119 }
120
121 /**
122 * Update resource. Only fields which are editable by users will be impacted.
123 *
124 * @param <T> a sub type of AbstractResource
125 * @param resourceOrRef the resource as supplied by clients (ie not managed by JPA)
126 *
127 * @return return updated managed resource
128 *
129 * @throws ColabMergeException if the update failed
130 */
131 public <T extends AbstractResource> T updateResourceOrRef(T resourceOrRef)
132 throws ColabMergeException {
133 logger.trace("update resource or ref {}", resourceOrRef);
134
135 @SuppressWarnings("unchecked")
136 T managedResource = (T) this.findResourceOrRef(resourceOrRef.getId());
137
138 managedResource.mergeToUpdate(resourceOrRef);
139
140 return managedResource;
141 }
142
143 /**
144 * Persist a brand new resource to database
145 *
146 * @param resource the new resource to persist
147 *
148 * @return the new persisted and managed resource
149 */
150 public Resource persistResource(Resource resource) {
151 logger.trace("persist resource {}", resource);
152
153 em.persist(resource);
154
155 return resource;
156 }
157
158 // Note : there is no persistResourceRef because they are automatically generated
159 // and are persisted by cascade
160
161 /**
162 * Delete the resource / resource reference from database. This can't be undone
163 *
164 * @param resourceOrRef the resource / resource reference to delete
165 */
166 public void deleteResourceOrRef(AbstractResource resourceOrRef) {
167 logger.trace("delete abstract resource {}", resourceOrRef);
168
169 // TODO: move to recycle bin first
170
171 em.remove(resourceOrRef);
172 }
173
174 }