View Javadoc
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 }