/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package gobblin.task; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Queue; import org.testng.Assert; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Queues; import com.google.common.collect.SetMultimap; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import gobblin.configuration.SourceState; import gobblin.configuration.State; import gobblin.configuration.WorkUnitState; import gobblin.publisher.DataPublisher; import gobblin.publisher.NoopPublisher; import gobblin.runtime.JobState; import gobblin.runtime.TaskContext; import gobblin.runtime.TaskState; import gobblin.runtime.task.BaseAbstractTask; import gobblin.runtime.task.TaskFactory; import gobblin.runtime.task.TaskIFace; import gobblin.runtime.task.TaskUtils; import gobblin.source.extractor.Extractor; import gobblin.source.workunit.WorkUnit; import gobblin.writer.test.TestingEventBuses; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; public class EventBusPublishingTaskFactory implements TaskFactory { public static final String TASK_ID_KEY = "MyFactory.task.id"; public static final String EVENTBUS_ID_KEY = "eventbus.id"; public static final String RUN_EVENT = "run"; public static final String COMMIT_EVENT = "commit"; public static final String PUBLISH_EVENT = "publish"; public static final String PREVIOUS_STATE_EVENT = "previousState"; @Override public TaskIFace createTask(TaskContext taskContext) { String taskId = taskContext.getTaskState().getProp(TASK_ID_KEY); EventBus eventBus = null; if (taskContext.getTaskState().contains(EVENTBUS_ID_KEY)) { String eventbusId = taskContext.getTaskState().getProp(EVENTBUS_ID_KEY); eventBus = TestingEventBuses.getEventBus(eventbusId); } return new Task(taskContext, taskId, eventBus); } @Override public DataPublisher createDataPublisher(JobState.DatasetState datasetState) { EventBus eventBus = null; if (datasetState.getTaskStates().get(0).contains(EVENTBUS_ID_KEY)) { eventBus = TestingEventBuses.getEventBus(datasetState.getTaskStates().get(0).getProp(EVENTBUS_ID_KEY)); } return new Publisher(datasetState, eventBus); } public static class EventListener { @Getter private final Queue<Event> events = Queues.newArrayDeque(); @Subscribe public void listen(Event event) { this.events.add(event); } public SetMultimap<String, Integer> getEventsSeenMap() { SetMultimap<String, Integer> seenEvents = HashMultimap.create(); for (EventBusPublishingTaskFactory.Event event : this.events) { seenEvents.put(event.getType(), event.getId()); } return seenEvents; } } public static class Source implements gobblin.source.Source<String, String> { public static final String NUM_TASKS_KEY = "num.tasks"; @Override public List<WorkUnit> getWorkunits(SourceState state) { int numTasks = state.getPropAsInt(NUM_TASKS_KEY); String eventBusId = state.getProp(EVENTBUS_ID_KEY); EventBus eventBus = TestingEventBuses.getEventBus(eventBusId); Map<String, SourceState> previousStates = state.getPreviousDatasetStatesByUrns(); for (Map.Entry<String, SourceState> entry : previousStates.entrySet()) { JobState.DatasetState datasetState = (JobState.DatasetState) entry.getValue(); for (TaskState taskState : datasetState.getTaskStates()) { if (taskState.contains(Task.PERSISTENT_STATE) && eventBus != null) { eventBus.post(new Event(PREVIOUS_STATE_EVENT, taskState.getPropAsInt(Task.PERSISTENT_STATE))); } } } List<WorkUnit> workUnits = Lists.newArrayList(); for (int i = 0; i < numTasks; i++) { workUnits.add(createWorkUnit(i, eventBusId)); } return workUnits; } protected WorkUnit createWorkUnit(int wuNumber, String eventBusId) { WorkUnit workUnit = new WorkUnit(); TaskUtils.setTaskFactoryClass(workUnit, EventBusPublishingTaskFactory.class); workUnit.setProp(EVENTBUS_ID_KEY, eventBusId); workUnit.setProp(TASK_ID_KEY, wuNumber); return workUnit; } @Override public Extractor<String, String> getExtractor(WorkUnitState state) throws IOException { throw new UnsupportedOperationException(); } @Override public void shutdown(SourceState state) { // Do nothing } } @Data @EqualsAndHashCode(callSuper = false) public static class Task extends BaseAbstractTask { public static final String PERSISTENT_STATE = "persistent.state"; public static final String EXECUTION_METADATA = "execution.metadata"; private final String taskId; private final EventBus eventBus; public Task(TaskContext taskContext, String taskId, EventBus eventBus) { super(taskContext); this.taskId = taskId; this.eventBus = eventBus; } @Override public void run() { if (this.eventBus != null) { this.eventBus.post(new Event(RUN_EVENT, Integer.parseInt(this.taskId))); } super.run(); } @Override public void commit() { if (this.eventBus != null) { this.eventBus.post(new Event(COMMIT_EVENT, Integer.parseInt(this.taskId))); } super.commit(); } @Override public State getPersistentState() { State state = super.getPersistentState(); state.setProp(PERSISTENT_STATE, this.taskId); return state; } @Override public State getExecutionMetadata() { State state = super.getExecutionMetadata(); state.setProp(EXECUTION_METADATA, this.taskId); return state; } } public static class Publisher extends NoopPublisher { private final EventBus eventBus; public Publisher(State state, EventBus eventBus) { super(state); this.eventBus = eventBus; } @Override public void publishData(Collection<? extends WorkUnitState> states) throws IOException { for (WorkUnitState state : states) { String taskId = state.getProp(TASK_ID_KEY); Assert.assertEquals(state.getProp(Task.EXECUTION_METADATA), taskId); Assert.assertEquals(state.getProp(Task.PERSISTENT_STATE), taskId); if (this.eventBus != null) { this.eventBus.post(new Event(PUBLISH_EVENT, Integer.parseInt(state.getProp(TASK_ID_KEY)))); } } super.publishData(states); } } @Data public static class Event { private final String type; private final int id; } }