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