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