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.playlists;
23  
24  
25  import static org.opencastproject.util.RequireUtil.notNull;
26  
27  import java.util.ArrayList;
28  import java.util.Date;
29  import java.util.List;
30  import java.util.UUID;
31  
32  import javax.persistence.CascadeType;
33  import javax.persistence.Column;
34  import javax.persistence.Entity;
35  import javax.persistence.FetchType;
36  import javax.persistence.Id;
37  import javax.persistence.NamedQueries;
38  import javax.persistence.NamedQuery;
39  import javax.persistence.OneToMany;
40  import javax.persistence.OrderColumn;
41  import javax.persistence.PrePersist;
42  import javax.persistence.Table;
43  import javax.persistence.Temporal;
44  import javax.persistence.TemporalType;
45  
46  /**
47   * Entity object for storing playlists in persistence storage. Playlists contain an ordered list of entries,
48   * which represent Opencast entities (for now they can only hold events, but in the future they may also hold series
49   * and the like). Playlists also contain some metadata and their own access control list.
50   *
51   * The playlist ACL only pertains to itself and its entries. The contents of an entry (i.e. the publication of an
52   * event) is still only governed by the contents ACL.
53   */
54  @Entity(name = "Playlist")
55  @Table(name = "oc_playlist")
56  @NamedQueries({
57      @NamedQuery(
58          name = "Playlist.findById",
59          query = "SELECT p FROM Playlist p WHERE p.id = :id and p.organization = :organizationId"
60      ),
61  })
62  public class Playlist {
63  
64    /**
65     * Workaround for generating a UUID for the id if we don't already have one.
66     *
67     * We cannot use EclipseLinks @UuidGenerator annotation for this, because it breaks our JUnit tests.
68     * We also cannot use Hibernates @GenericGenerator for this, since we lack the appropriate library (and possibly
69     * hibernate version).
70     */
71    @PrePersist
72    public void generateId() {
73      if (this.id == null) {
74        this.id = UUID.randomUUID().toString();
75      }
76    }
77  
78    @Id
79    @Column(name = "id")
80    private String id;
81  
82    @Column(name = "organization", nullable = false, length = 128)
83    private String organization;
84  
85    @OneToMany(
86        fetch = FetchType.LAZY,
87        cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE },
88        mappedBy = "playlist",
89        orphanRemoval = true
90    )
91    @OrderColumn(name = "position_entries")
92    private List<PlaylistEntry> entries = new ArrayList<PlaylistEntry>();
93  
94    @Column(name = "title")
95    private String title;
96  
97    @Column(name = "description")
98    private String description;
99  
100   @Column(name = "creator")
101   private String creator;
102 
103   @Column(name = "updated", nullable = false)
104   @Temporal(TemporalType.TIMESTAMP)
105   private Date updated;
106 
107   @Column(name = "deletion_date")
108   @Temporal(TemporalType.TIMESTAMP)
109   protected Date deletionDate = null;
110 
111   @OneToMany(
112       fetch = FetchType.LAZY,
113       cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE },
114       mappedBy = "playlist",
115       orphanRemoval = true
116   )
117   @OrderColumn(name = "position_access_control_entries")
118   private List<PlaylistAccessControlEntry> accessControlEntries = new ArrayList<>();
119 
120   /**
121    * Default constructor
122    */
123   public Playlist() {
124 
125   }
126 
127   public Playlist(String id, String organization, List<PlaylistEntry> entries, String title, String description,
128       String creator, Date updated, List<PlaylistAccessControlEntry> accessControlEntries) {
129     this.id = id;
130     this.organization = organization;
131     this.entries = entries;
132     this.title = title;
133     this.description = description;
134     this.creator = creator;
135     this.updated = updated;
136     this.accessControlEntries = accessControlEntries;
137   }
138 
139   public String getId() {
140     return id;
141   }
142 
143   public void setId(String id) {
144     this.id = id;
145   }
146 
147   public String getOrganization() {
148     return organization;
149   }
150 
151   public void setOrganization(String organization) {
152     this.organization = organization;
153   }
154 
155   public List<PlaylistEntry> getEntries() {
156     return entries;
157   }
158 
159   public void setEntries(List<PlaylistEntry> entries) {
160     for (var entry : entries) {
161       if (this.entries.stream().noneMatch(e -> entry.getId() == e.getId())) {
162         entry.setId(0L);
163       }
164       entry.setPlaylist(this);
165     }
166     this.entries = entries;
167   }
168 
169   public boolean addEntry(PlaylistEntry entry) {
170     notNull(entry, "entry");
171     if (this.entries.contains(entry)) {
172       entries.remove(entry);
173     }
174     entry.setPlaylist(this);
175     return entries.add(entry);
176   }
177 
178   public boolean removeEntry(PlaylistEntry entry) {
179     notNull(entry, "entry");
180     entry.setPlaylist(null);
181     return entries.remove(entry);
182   }
183 
184   public String getTitle() {
185     return title;
186   }
187 
188   public void setTitle(String title) {
189     this.title = title;
190   }
191 
192   public String getDescription() {
193     return description;
194   }
195 
196   public void setDescription(String description) {
197     this.description = description;
198   }
199 
200   public String getCreator() {
201     return creator;
202   }
203 
204   public void setCreator(String creator) {
205     this.creator = creator;
206   }
207 
208   public Date getUpdated() {
209     return updated;
210   }
211 
212   public void setUpdated(Date updated) {
213     this.updated = updated;
214   }
215 
216   public Date getDeletionDate() {
217     return deletionDate;
218   }
219 
220   public void setDeletionDate(Date deletionDate) {
221     this.deletionDate = deletionDate;
222   }
223 
224   public boolean isDeleted() {
225     return this.deletionDate != null;
226   }
227 
228   public List<PlaylistAccessControlEntry> getAccessControlEntries() {
229     return accessControlEntries;
230   }
231 
232   public void setAccessControlEntries(List<PlaylistAccessControlEntry> accessControlEntries) {
233     for (var accessControlEntry : accessControlEntries) {
234       accessControlEntry.setPlaylist(this);
235     }
236     this.accessControlEntries = accessControlEntries;
237   }
238 
239 
240 }