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.transcription.workflowoperation;
22  
23  import org.opencastproject.caption.api.CaptionService;
24  import org.opencastproject.job.api.Job;
25  import org.opencastproject.job.api.JobContext;
26  import org.opencastproject.mediapackage.Attachment;
27  import org.opencastproject.mediapackage.MediaPackage;
28  import org.opencastproject.mediapackage.MediaPackageElement;
29  import org.opencastproject.mediapackage.MediaPackageElementFlavor;
30  import org.opencastproject.mediapackage.MediaPackageElementParser;
31  import org.opencastproject.mediapackage.Track;
32  import org.opencastproject.serviceregistry.api.ServiceRegistry;
33  import org.opencastproject.transcription.api.TranscriptionService;
34  import org.opencastproject.workflow.api.AbstractWorkflowOperationHandler;
35  import org.opencastproject.workflow.api.ConfiguredTagsAndFlavors;
36  import org.opencastproject.workflow.api.WorkflowInstance;
37  import org.opencastproject.workflow.api.WorkflowOperationException;
38  import org.opencastproject.workflow.api.WorkflowOperationHandler;
39  import org.opencastproject.workflow.api.WorkflowOperationInstance;
40  import org.opencastproject.workflow.api.WorkflowOperationResult;
41  import org.opencastproject.workflow.api.WorkflowOperationResult.Action;
42  import org.opencastproject.workspace.api.Workspace;
43  
44  import org.apache.commons.lang3.StringUtils;
45  import org.osgi.service.component.ComponentContext;
46  import org.osgi.service.component.annotations.Activate;
47  import org.osgi.service.component.annotations.Component;
48  import org.osgi.service.component.annotations.Reference;
49  import org.slf4j.Logger;
50  import org.slf4j.LoggerFactory;
51  
52  import java.util.List;
53  
54  @Component(
55      immediate = true,
56      service = WorkflowOperationHandler.class,
57      property = {
58          "service.description=Attach Transcription Workflow Operation Handler",
59          "workflow.operation=attach-watson-transcription"
60      }
61  )
62  public class AttachTranscriptionOperationHandler extends AbstractWorkflowOperationHandler {
63  
64    /** The logging facility */
65    private static final Logger logger = LoggerFactory.getLogger(AttachTranscriptionOperationHandler.class);
66  
67    /** Workflow configuration option keys */
68    static final String TRANSCRIPTION_JOB_ID = "transcription-job-id";
69    static final String TARGET_CAPTION_FORMAT = "target-caption-format";
70    static final String TARGET_TYPE = "target-element-type";
71  
72    /** The transcription service */
73    private TranscriptionService service = null;
74    private Workspace workspace;
75    private CaptionService captionService;
76  
77    @Override
78    @Activate
79    protected void activate(ComponentContext cc) {
80      super.activate(cc);
81    }
82  
83    @Override
84    public WorkflowOperationResult start(final WorkflowInstance workflowInstance, JobContext context)
85            throws WorkflowOperationException {
86      MediaPackage mediaPackage = workflowInstance.getMediaPackage();
87      WorkflowOperationInstance operation = workflowInstance.getCurrentOperation();
88  
89      logger.debug("Attach transcription for mediapackage {} started", mediaPackage);
90  
91      // Get job id.
92      String jobId = StringUtils.trimToNull(operation.getConfiguration(TRANSCRIPTION_JOB_ID));
93      if (jobId == null) {
94        throw new WorkflowOperationException(TRANSCRIPTION_JOB_ID + " missing");
95      }
96  
97      // Check which tags/flavors have been configured
98      ConfiguredTagsAndFlavors tagsAndFlavors = getTagsAndFlavors(
99          workflowInstance, Configuration.none, Configuration.none, Configuration.many, Configuration.one);
100     List<String> targetTagOption = tagsAndFlavors.getTargetTags();
101     MediaPackageElementFlavor targetFlavor = tagsAndFlavors.getSingleTargetFlavor();
102     String captionFormatOption = StringUtils.trimToNull(operation.getConfiguration(TARGET_CAPTION_FORMAT));
103     String typeUnparsed = StringUtils.trimToEmpty(operation.getConfiguration(TARGET_TYPE));
104     MediaPackageElement.Type type = null;
105     if (!typeUnparsed.isEmpty()) {
106       // Case insensitive matching between user input (workflow config key) and enum value
107       for (MediaPackageElement.Type t : MediaPackageElement.Type.values()) {
108         if (t.name().equalsIgnoreCase(typeUnparsed)) {
109           type = t;
110         }
111       }
112       if (type == null || (type != Track.TYPE && type != Attachment.TYPE)) {
113         throw new IllegalArgumentException(String.format("The given type '%s' for mediapackage %s was illegal. Please"
114                 + "check the operations' configuration keys.", type, mediaPackage.getIdentifier()));
115       }
116     } else {
117       type = Track.TYPE;
118     }
119 
120     try {
121       // Get transcription file from the service
122       MediaPackageElement original = service.getGeneratedTranscription(mediaPackage.getIdentifier().toString(), jobId,
123               type);
124       MediaPackageElement transcription = original;
125 
126       // If caption format passed, convert to desired format
127       if (captionFormatOption != null) {
128         Job job = captionService.convert(transcription, "ibm-watson", captionFormatOption, service.getLanguage());
129         if (!waitForStatus(job).isSuccess()) {
130           throw new WorkflowOperationException("Transcription format conversion job did not complete successfully");
131         }
132         transcription = MediaPackageElementParser.getFromXml(job.getPayload());
133       }
134 
135       // Set the target flavor if informed
136       transcription.setFlavor(targetFlavor);
137 
138       // Add tags
139       for (String tag : targetTagOption) {
140         transcription.addTag(tag);
141       }
142 
143       // Add to media package
144       mediaPackage.add(transcription);
145 
146       String uri = transcription.getURI().toString();
147       String ext = uri.substring(uri.lastIndexOf("."));
148       transcription.setURI(workspace.moveTo(transcription.getURI(), mediaPackage.getIdentifier().toString(),
149               transcription.getIdentifier(), "captions." + ext));
150     } catch (Exception e) {
151       throw new WorkflowOperationException(e);
152     }
153 
154     return createResult(mediaPackage, Action.CONTINUE);
155   }
156 
157   @Reference(target = "(provider=ibm.watson)")
158   public void setTranscriptionService(TranscriptionService service) {
159     this.service = service;
160   }
161 
162   @Reference
163   public void setWorkspace(Workspace service) {
164     this.workspace = service;
165   }
166 
167   @Reference
168   public void setCaptionService(CaptionService service) {
169     this.captionService = service;
170   }
171 
172   @Reference
173   @Override
174   public void setServiceRegistry(ServiceRegistry serviceRegistry) {
175     super.setServiceRegistry(serviceRegistry);
176   }
177 
178 }
179