View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  package org.opencastproject.annotation.impl;
23  
24  import static org.opencastproject.db.Queries.namedQuery;
25  
26  import org.opencastproject.annotation.api.Annotation;
27  import org.opencastproject.annotation.api.AnnotationList;
28  import org.opencastproject.annotation.api.AnnotationService;
29  import org.opencastproject.db.DBSession;
30  import org.opencastproject.db.DBSessionFactory;
31  import org.opencastproject.security.api.SecurityService;
32  import org.opencastproject.util.NotFoundException;
33  
34  import org.apache.commons.lang3.tuple.Pair;
35  import org.osgi.service.component.annotations.Activate;
36  import org.osgi.service.component.annotations.Component;
37  import org.osgi.service.component.annotations.Deactivate;
38  import org.osgi.service.component.annotations.Reference;
39  
40  import java.util.Calendar;
41  import java.util.Collection;
42  import java.util.GregorianCalendar;
43  import java.util.function.Function;
44  
45  import javax.persistence.EntityManager;
46  import javax.persistence.EntityManagerFactory;
47  import javax.persistence.Query;
48  import javax.persistence.TemporalType;
49  
50  /**
51   * JPA-based implementation of the {@link AnnotationService}
52   */
53  @Component(
54      immediate = true,
55      service = AnnotationService.class,
56      property = {
57          "service.description=Annotation Service"
58      }
59  )
60  public class AnnotationServiceJpaImpl implements AnnotationService {
61  
62    /** JPA persistence unit name */
63    public static final String PERSISTENCE_UNIT = "org.opencastproject.annotation";
64  
65    /** The factory used to generate the entity manager */
66    protected EntityManagerFactory emf = null;
67  
68    protected DBSessionFactory dbSessionFactory;
69  
70    protected DBSession db;
71  
72    /** Opencast's security service */
73    protected SecurityService securityService;
74  
75    /** OSGi DI */
76    @Reference(target = "(osgi.unit.name=org.opencastproject.annotation)")
77    void setEntityManagerFactory(EntityManagerFactory emf) {
78      this.emf = emf;
79    }
80  
81    @Reference
82    public void setDBSessionFactory(DBSessionFactory dbSessionFactory) {
83      this.dbSessionFactory = dbSessionFactory;
84    }
85  
86    @Activate
87    public void activate() {
88      db = dbSessionFactory.createSession(emf);
89    }
90  
91    @Deactivate
92    public void deactivate() {
93      db.close();
94    }
95  
96    /**
97     * Sets the opencast security service
98     *
99     * @param securityService
100    *          the securityService to set
101    */
102   @Reference
103   public void setSecurityService(SecurityService securityService) {
104     this.securityService = securityService;
105   }
106 
107   public Annotation addAnnotation(Annotation a) {
108     // set the User ID on the annotation
109     a.setUserId(securityService.getUser().getUsername());
110     return db.execTx(namedQuery.persist(a));
111   }
112 
113   public boolean removeAnnotation(Annotation a) {
114     try {
115       db.execTxChecked(em -> {
116         // first merge then remove element
117         em.remove(em.merge(a));
118       });
119       return true;
120     } catch (Exception e) {
121       return false;
122     }
123   }
124 
125   public Annotation changeAnnotation(Annotation a) throws NotFoundException {
126     long id = a.getAnnotationId();
127     return db.execTx(em -> {
128       Query q = em.createNamedQuery("updateAnnotation");
129       q.setParameter("value", a.getValue());
130       q.setParameter("annotationId", id);
131       int no = q.executeUpdate();
132 
133       AnnotationImpl b = null;
134       if (no == 1) {
135         b = em.find(AnnotationImpl.class, id);
136       }
137       return b;
138     });
139   }
140 
141   public Annotation getAnnotation(long id) throws NotFoundException {
142     AnnotationImpl a = db.exec(namedQuery.findById(AnnotationImpl.class, id));
143     if (a == null) {
144       throw new NotFoundException("Annotation '" + id + "' not found");
145     }
146     return a;
147   }
148 
149   @SuppressWarnings("unchecked")
150   public AnnotationList getAnnotations(int offset, int limit) {
151     AnnotationListImpl result = new AnnotationListImpl();
152 
153     db.exec(em -> {
154       result.setTotal(getTotalQuery().apply(em));
155       result.setOffset(offset);
156       result.setLimit(limit);
157 
158       Query q = em.createNamedQuery("findAnnotations");
159       q.setParameter("userId", securityService.getUser().getUsername());
160       q.setFirstResult(offset);
161       q.setMaxResults(limit);
162       Collection<Annotation> annotations = q.getResultList();
163       for (Annotation a : annotations) {
164         result.add(a);
165       }
166     });
167 
168     return result;
169   }
170 
171   public AnnotationList getAnnotationsByTypeAndMediapackageId(String type, String mediapackageId, int offset,
172       int limit) {
173     AnnotationListImpl result = new AnnotationListImpl();
174 
175     db.exec(em -> {
176       result.setTotal(getTotalQuery(type, mediapackageId).apply(em));
177       result.setOffset(offset);
178       result.setLimit(limit);
179 
180       Query q = em.createNamedQuery("findAnnotationsByTypeAndMediapackageId");
181       q.setParameter("userId", securityService.getUser().getUsername());
182       q.setParameter("type", type);
183       q.setParameter("mediapackageId", mediapackageId);
184       q.setFirstResult(offset);
185       q.setMaxResults(limit);
186       @SuppressWarnings("unchecked")
187       Collection<Annotation> annotations = q.getResultList();
188 
189       for (Annotation a : annotations) {
190         result.add(a);
191       }
192     });
193 
194     return result;
195   }
196 
197   public AnnotationList getAnnotationsByMediapackageId(String mediapackageId, int offset, int limit) {
198     AnnotationListImpl result = new AnnotationListImpl();
199 
200     db.exec(em -> {
201       result.setTotal(getTotalByMediapackageIDQuery(mediapackageId).apply(em));
202       result.setOffset(offset);
203       result.setLimit(limit);
204 
205       Query q = em.createNamedQuery("findAnnotationsByMediapackageId");
206       q.setParameter("userId", securityService.getUser().getUsername());
207       q.setParameter("mediapackageId", mediapackageId);
208       q.setFirstResult(offset);
209       q.setMaxResults(limit);
210       @SuppressWarnings("unchecked")
211       Collection<Annotation> annotations = q.getResultList();
212 
213       for (Annotation a : annotations) {
214         result.add(a);
215       }
216     });
217 
218     return result;
219   }
220 
221   @SuppressWarnings("unchecked")
222   public AnnotationList getAnnotationsByTypeAndDay(String type, String day, int offset, int limit) {
223     int year = Integer.parseInt(day.substring(0, 4));
224     int month = Integer.parseInt(day.substring(4, 6)) - 1;
225     int date = Integer.parseInt(day.substring(6, 8));
226 
227     Calendar calBegin = new GregorianCalendar();
228     calBegin.set(year, month, date, 0, 0);
229     Calendar calEnd = new GregorianCalendar();
230     calEnd.set(year, month, date, 23, 59);
231 
232     AnnotationListImpl result = new AnnotationListImpl();
233 
234     db.exec(em -> {
235       result.setTotal(getTotalQuery(type, calBegin, calEnd).apply(em));
236       result.setOffset(offset);
237       result.setLimit(limit);
238 
239       Query q = em.createNamedQuery("findAnnotationsByTypeAndIntervall");
240       q.setParameter("userId", securityService.getUser().getUsername());
241       q.setParameter("type", type);
242       q.setParameter("begin", calBegin, TemporalType.TIMESTAMP);
243       q.setParameter("end", calEnd, TemporalType.TIMESTAMP);
244       q.setFirstResult(offset);
245       q.setMaxResults(limit);
246       Collection<Annotation> annotations = q.getResultList();
247       for (Annotation a : annotations) {
248         result.add(a);
249       }
250     });
251 
252     return result;
253   }
254 
255   @SuppressWarnings("unchecked")
256   public AnnotationList getAnnotationsByDay(String day, int offset, int limit) {
257     AnnotationListImpl result = new AnnotationListImpl();
258 
259     int year = Integer.parseInt(day.substring(0, 4));
260     int month = Integer.parseInt(day.substring(4, 6)) - 1;
261     int date = Integer.parseInt(day.substring(6, 8));
262 
263     Calendar calBegin = new GregorianCalendar();
264     calBegin.set(year, month, date, 0, 0);
265     Calendar calEnd = new GregorianCalendar();
266     calEnd.set(year, month, date, 23, 59);
267 
268     db.exec(em -> {
269       result.setTotal(getTotalQuery(calBegin, calEnd).apply(em));
270       result.setOffset(offset);
271       result.setLimit(limit);
272 
273       Query q = em.createNamedQuery("findAnnotationsByIntervall");
274       q.setParameter("userId", securityService.getUser().getUsername());
275       q.setParameter("begin", calBegin, TemporalType.TIMESTAMP);
276       q.setParameter("end", calEnd, TemporalType.TIMESTAMP);
277       q.setFirstResult(offset);
278       q.setMaxResults(limit);
279       Collection<Annotation> annotations = q.getResultList();
280       for (Annotation a : annotations) {
281         result.add(a);
282       }
283     });
284 
285     return result;
286   }
287 
288   @SuppressWarnings("unchecked")
289   public AnnotationList getAnnotationsByType(String type, int offset, int limit) {
290     AnnotationListImpl result = new AnnotationListImpl();
291 
292     db.exec(em -> {
293       result.setTotal(getTotalQuery(type).apply(em));
294       result.setOffset(offset);
295       result.setLimit(limit);
296 
297       Query q = em.createNamedQuery("findAnnotationsByType");
298       q.setParameter("userId", securityService.getUser().getUsername());
299       q.setParameter("type", type);
300       q.setFirstResult(offset);
301       q.setMaxResults(limit);
302       Collection<Annotation> annotations = q.getResultList();
303       for (Annotation a : annotations) {
304         result.add(a);
305       }
306     });
307 
308     return result;
309   }
310 
311   private Function<EntityManager, Integer> getTotalQuery() {
312     return namedQuery.find(
313         "findTotal",
314         Long.class,
315         Pair.of("userId", securityService.getUser().getUsername())
316     ).andThen(Long::intValue);
317   }
318 
319   private Function<EntityManager, Integer> getTotalQuery(String type) {
320     return namedQuery.find(
321         "findTotalByType",
322         Long.class,
323         Pair.of("userId", securityService.getUser().getUsername()),
324         Pair.of("type", type)
325     ).andThen(Long::intValue);
326   }
327 
328   private Function<EntityManager, Integer> getTotalQuery(String type, String mediapackageId) {
329     return namedQuery.find(
330         "findTotalByTypeAndMediapackageId",
331         Long.class,
332         Pair.of("userId", securityService.getUser().getUsername()),
333         Pair.of("type", type),
334         Pair.of("mediapackageId", mediapackageId)
335     ).andThen(Long::intValue);
336   }
337 
338   private Function<EntityManager, Integer> getTotalByMediapackageIDQuery(String mediapackageId) {
339     return namedQuery.find(
340         "findTotalByMediapackageId",
341         Long.class,
342         Pair.of("userId", securityService.getUser().getUsername()),
343         Pair.of("mediapackageId", mediapackageId)
344     ).andThen(Long::intValue);
345   }
346 
347   private Function<EntityManager, Integer> getTotalQuery(String type, Calendar calBegin, Calendar calEnd) {
348     return namedQuery.find(
349         "findTotalByTypeAndIntervall",
350         Long.class,
351         Pair.of("userId", securityService.getUser().getUsername()),
352         Pair.of("type", type),
353         Pair.of("begin", calBegin),
354         Pair.of("end", calEnd)
355     ).andThen(Long::intValue);
356   }
357 
358   private Function<EntityManager, Integer> getTotalQuery(Calendar calBegin, Calendar calEnd) {
359     return namedQuery.find(
360         "findTotalByIntervall",
361         Long.class,
362         Pair.of("userId", securityService.getUser().getUsername()),
363         Pair.of("begin", calBegin),
364         Pair.of("end", calEnd)
365     ).andThen(Long::intValue);
366   }
367 }