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.assetmanager.util;
22  
23  import static org.opencastproject.assetmanager.api.AssetManager.DEFAULT_OWNER;
24  import static org.opencastproject.mediapackage.MediaPackageElements.XACML_POLICY_EPISODE;
25  import static org.opencastproject.mediapackage.MediaPackageElements.XACML_POLICY_SERIES;
26  import static org.opencastproject.systems.OpencastConstants.WORKFLOW_PROPERTIES_NAMESPACE;
27  
28  import org.opencastproject.assetmanager.api.AssetManager;
29  import org.opencastproject.assetmanager.api.Property;
30  import org.opencastproject.assetmanager.api.PropertyId;
31  import org.opencastproject.assetmanager.api.Value;
32  import org.opencastproject.assetmanager.api.query.AQueryBuilder;
33  import org.opencastproject.assetmanager.api.query.ARecord;
34  import org.opencastproject.assetmanager.api.query.AResult;
35  import org.opencastproject.mediapackage.Attachment;
36  import org.opencastproject.mediapackage.Catalog;
37  import org.opencastproject.mediapackage.MediaPackage;
38  import org.opencastproject.mediapackage.MediaPackageElement;
39  import org.opencastproject.mediapackage.MediaPackageElementFlavor;
40  
41  import java.util.Arrays;
42  import java.util.Collection;
43  import java.util.Collections;
44  import java.util.HashMap;
45  import java.util.HashSet;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Set;
49  import java.util.stream.Collectors;
50  
51  /**
52   * Utility class to store and retrieve Workflow Properties (which are stored in specially prefixed Asset Manager
53   * properties)
54   */
55  public final class WorkflowPropertiesUtil {
56    private static final Set<MediaPackageElementFlavor> SECURITY_FLAVORS = new HashSet<>(
57            Arrays.asList(XACML_POLICY_EPISODE, XACML_POLICY_SERIES));
58  
59    private WorkflowPropertiesUtil() {
60    }
61  
62    /**
63     * Retrieve latest properties for a set of event ids
64     * @param assetManager The Asset Manager to use
65     * @param eventIds Collection of event IDs (can be a set, but doesn't have to be)
66     * @return A map mapping event IDs to key value pairs (which are themselves maps) representing the properties
67     */
68    public static Map<String, Map<String, String>> getLatestWorkflowPropertiesForEvents(final AssetManager assetManager,
69            final Collection<String> eventIds) {
70      final AQueryBuilder query = assetManager.createQuery();
71      final AResult result = query.select(query.snapshot(), query.propertiesOf(WORKFLOW_PROPERTIES_NAMESPACE))
72              .where(query.mediaPackageIds(eventIds.toArray(new String[0])).and(query.version().isLatest())).run();
73      final Map<String, Map<String, String>> workflowProperties = new HashMap<>(eventIds.size());
74      for (final ARecord record : result.getRecords()) {
75        final List<Property> recordProps = record.getProperties();
76        final Map<String, String> eventMap = new HashMap<>(recordProps.size());
77        for (final Property property : recordProps) {
78          eventMap.put(property.getId().getName(), property.getValue().get(Value.STRING));
79        }
80        final String eventId = record.getMediaPackageId();
81        workflowProperties.put(eventId, eventMap);
82      }
83      return workflowProperties;
84    }
85  
86    /**
87     * Retrieve the latest properties for a single media package
88     * @param assetManager The Asset Manager to use
89     * @param mediaPackageId The media package to query
90     * @return A list of properties represented by a Map
91     */
92    public static Map<String, String> getLatestWorkflowProperties(final AssetManager assetManager,
93            final String mediaPackageId) {
94      return assetManager.selectProperties(mediaPackageId, WORKFLOW_PROPERTIES_NAMESPACE)
95              .parallelStream()
96              .collect(Collectors.toMap(
97                      p -> p.getId().getName(),
98                      p -> p.getValue().get(Value.STRING)));
99    }
100 
101   /**
102    * Store selected properties for a media package
103    * @param assetManager The Asset Manager to use
104    * @param mediaPackage The media package to store properties relative to
105    * @param properties A list of properties represented by a Map
106    */
107   public static void storeProperties(final AssetManager assetManager, final MediaPackage mediaPackage,
108           final Map<String, String> properties) {
109 
110     // Properties can only be created if a snapshot exists. Hence, we create a snapshot if there is none right now.
111     // Although, to avoid lots of potentially slow IO operations, we archive a slimmer version of the media package,
112     // containing only metadata and security attachments.
113     if (!assetManager.snapshotExists(mediaPackage.getIdentifier().toString())) {
114       MediaPackage simplifiedMediaPackage = (MediaPackage) mediaPackage.clone();
115       for (MediaPackageElement element : mediaPackage.getElements()) {
116         if (element instanceof Catalog) {
117           continue;
118         }
119         if (element instanceof Attachment && SECURITY_FLAVORS.contains(element.getFlavor())) {
120           continue;
121         }
122         simplifiedMediaPackage.remove(element);
123       }
124 
125       assetManager.takeSnapshot(DEFAULT_OWNER, simplifiedMediaPackage);
126     }
127 
128     // Store all properties
129     for (final Map.Entry<String, String> entry : properties.entrySet()) {
130       final PropertyId propertyId = PropertyId
131               .mk(mediaPackage.getIdentifier().toString(), WORKFLOW_PROPERTIES_NAMESPACE, entry.getKey());
132       final Property property = Property.mk(propertyId, Value.mk(entry.getValue()));
133       assetManager.setProperty(property);
134     }
135   }
136 
137   public static void storeProperty(final AssetManager assetManager, final MediaPackage mediaPackage,
138           final String name, final String value) {
139     storeProperties(assetManager, mediaPackage, Collections.singletonMap(name, value));
140   }
141 }