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  package org.opencastproject.message.broker.api.assetmanager;
22  
23  import org.opencastproject.mediapackage.Catalog;
24  import org.opencastproject.mediapackage.MediaPackage;
25  import org.opencastproject.mediapackage.MediaPackageElements;
26  import org.opencastproject.mediapackage.MediaPackageException;
27  import org.opencastproject.mediapackage.MediaPackageParser;
28  import org.opencastproject.message.broker.api.MessageItem;
29  import org.opencastproject.metadata.dublincore.DublinCoreCatalog;
30  import org.opencastproject.metadata.dublincore.DublinCores;
31  import org.opencastproject.security.api.AccessControlList;
32  import org.opencastproject.security.api.AccessControlParser;
33  import org.opencastproject.util.RequireUtil;
34  import org.opencastproject.workspace.api.Workspace;
35  
36  import org.apache.commons.io.IOUtils;
37  
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.io.Serializable;
41  import java.nio.charset.StandardCharsets;
42  import java.util.Date;
43  import java.util.Optional;
44  import java.util.function.Function;
45  
46  import javax.annotation.ParametersAreNonnullByDefault;
47  
48  /**
49   * {@link Serializable} class that represents all of the possible messages sent through an AssetManager queue.
50   */
51  @ParametersAreNonnullByDefault
52  public abstract class AssetManagerItem implements MessageItem, Serializable {
53    private static final long serialVersionUID = 5440420510139202434L;
54  
55    public enum Type {
56      Update, Delete
57    }
58  
59    // common fields
60  
61    private final String mediaPackageId;
62    private final long date;
63  
64    private AssetManagerItem(String mediaPackageId, Date date) {
65      this.mediaPackageId = RequireUtil.notNull(mediaPackageId, "mediaPackageId");
66      this.date = RequireUtil.notNull(date, "date").getTime();
67    }
68  
69    public abstract Type getType();
70  
71    public abstract <A> A decompose(Function<? super TakeSnapshot, ? extends A> takeSnapshot,
72        Function<? super DeleteEpisode, ? extends A> deleteEpisode);
73  
74    public final Date getDate() {
75      return new Date(date);
76    }
77  
78    @Override
79    public final String getId() {
80      return mediaPackageId;
81    }
82  
83    /*
84     * ------------------------------------------------------------------------------------------------------------------
85     */
86  
87    /**
88     * An event for taking a snapshot of a media package.
89     */
90    public static final class TakeSnapshot extends AssetManagerItem {
91      private static final long serialVersionUID = 3530625835200867594L;
92  
93      private final String mediapackage;
94      private final String acl;
95      private final long version;
96      private final String episodeDublincore;
97  
98      private TakeSnapshot(String mediaPackageId, String mediapackage, String episodeDublincore, String acl, long version,
99              Date date) {
100       super(mediaPackageId, date);
101       this.mediapackage = mediapackage;
102       this.episodeDublincore = episodeDublincore;
103       this.acl = acl;
104       this.version = version;
105     }
106 
107     @Override
108     public <A> A decompose(Function<? super TakeSnapshot, ? extends A> takeSnapshot,
109         Function<? super DeleteEpisode, ? extends A> deleteEpisode) {
110       return takeSnapshot.apply(this);
111     }
112 
113     @Override
114     public Type getType() {
115       return Type.Update;
116     }
117 
118     public MediaPackage getMediapackage() {
119       try {
120         return MediaPackageParser.getFromXml(mediapackage);
121       } catch (MediaPackageException e) {
122         throw new RuntimeException(e);
123       }
124     }
125 
126     public AccessControlList getAcl() {
127       return AccessControlParser.parseAclSilent(acl);
128     }
129 
130     public Optional<DublinCoreCatalog> getEpisodeDublincore() {
131       if (episodeDublincore == null) {
132         return Optional.empty();
133       }
134 
135       try (InputStream is = IOUtils.toInputStream(episodeDublincore, "UTF-8")) {
136         return Optional.of(DublinCores.read(is));
137       } catch (IOException e) {
138         throw new RuntimeException(e);
139       }
140     }
141 
142     public long getVersion() {
143       return version;
144     }
145 
146     //
147 
148     public static final Function<TakeSnapshot, MediaPackage> getMediaPackage =
149         new Function<TakeSnapshot, MediaPackage>() {
150       @Override
151       public MediaPackage apply(TakeSnapshot a) {
152         return a.getMediapackage();
153       }
154     };
155 
156     public static final Function<TakeSnapshot, Optional<DublinCoreCatalog>> getEpisodeDublincore
157         = new Function<TakeSnapshot, Optional<DublinCoreCatalog>>() {
158           @Override
159           public Optional<DublinCoreCatalog> apply(TakeSnapshot a) {
160             return a.getEpisodeDublincore();
161           }
162         };
163 
164     public static final Function<TakeSnapshot, AccessControlList> getAcl =
165         new Function<TakeSnapshot, AccessControlList>() {
166       @Override
167       public AccessControlList apply(TakeSnapshot a) {
168         return a.getAcl();
169       }
170     };
171 
172   }
173 
174   /*
175    * ------------------------------------------------------------------------------------------------------------------
176    */
177 
178   /*
179    * ------------------------------------------------------------------------------------------------------------------
180    */
181 
182   /**
183    * A event that will be sent when all versions of a media package (aka the whole episode) have been deleted.
184    */
185   public static final class DeleteEpisode extends AssetManagerItem {
186     private static final long serialVersionUID = -4906056424740181256L;
187 
188     private DeleteEpisode(String mediaPackageId, Date date) {
189       super(mediaPackageId, date);
190     }
191 
192     @Override
193     public <A> A decompose(Function<? super TakeSnapshot, ? extends A> takeSnapshot,
194         Function<? super DeleteEpisode, ? extends A> deleteEpisode) {
195       return deleteEpisode.apply(this);
196     }
197 
198     @Override
199     public Type getType() {
200       return Type.Delete;
201     }
202 
203     public String getMediaPackageId() {
204       return getId();
205     }
206 
207     public static final Function<DeleteEpisode, String> getMediaPackageId = new Function<DeleteEpisode, String>() {
208       @Override
209       public String apply(DeleteEpisode a) {
210         return a.getMediaPackageId();
211       }
212     };
213   }
214 
215   /*
216    * ------------------------------------------------------------------------------------------------------------------
217    */
218 
219   //
220   // constructor methods
221   //
222 
223   /**
224    * @param workspace
225    *          The workspace
226    * @param mp
227    *          The media package to update.
228    * @param acl
229    *          The access control list of the media package to update.
230    * @param version
231    *          The version of the media package.
232    * @param date
233    *          The modification date.
234    * @return Builds a {@link AssetManagerItem} for taking a media package snapshot.
235    */
236   public static TakeSnapshot add(Workspace workspace, MediaPackage mp, AccessControlList acl, long version, Date date) {
237     String dcXml = null;
238     for (Catalog catalog: mp.getCatalogs(MediaPackageElements.EPISODE)) {
239       try (InputStream in = workspace.read(catalog.getURI())) {
240         dcXml = IOUtils.toString(in, StandardCharsets.UTF_8);
241       } catch (Exception e) {
242         throw new IllegalStateException(String.format("Unable to load dublin core catalog for event '%s'",
243                 mp.getIdentifier()), e);
244       }
245     }
246     return new TakeSnapshot(mp.getIdentifier().toString(), MediaPackageParser.getAsXml(mp), dcXml,
247             AccessControlParser.toJsonSilent(acl), version, date);
248   }
249 
250   /**
251    * @param mediaPackageId
252    *          The unique id of the media package to delete.
253    * @param date
254    *          The modification date.
255    * @return Builds {@link AssetManagerItem} for deleting an episode from the asset manager.
256    */
257   public static AssetManagerItem deleteEpisode(String mediaPackageId, Date date) {
258     return new DeleteEpisode(mediaPackageId, date);
259   }
260 }