001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.wake.impl; 020 021import org.apache.reef.tang.annotations.Unit; 022import org.apache.reef.wake.EventHandler; 023 024import javax.inject.Inject; 025import java.util.logging.Level; 026import java.util.logging.Logger; 027 028/** 029 * An EventHandler combines two events of different types into a single Pair of events. 030 * Handler will block until both events are received. 031 * <p/> 032 * onNext is thread safe 033 * 034 * @param <L> type of event 035 * @param <R> type of event 036 * @see BlockingEventHandler 037 */ 038@Unit 039public final class MergingEventHandler<L, R> { 040 041 private static final Logger LOG = Logger.getLogger(MergingEventHandler.class.getName()); 042 private final EventHandler<L> left = new Left(); 043 private final EventHandler<R> right = new Right(); 044 private final Object mutex = new Object(); 045 private final EventHandler<Pair<L, R>> destination; 046 private L leftEvent; 047 private R rightEvent; 048 049 public EventHandler<L> getLeft() { 050 return left; 051 } 052 053 public EventHandler<R> getRight() { 054 return right; 055 } 056 057 @Inject 058 public MergingEventHandler(final EventHandler<Pair<L, R>> destination) { 059 this.destination = destination; 060 reset(); 061 } 062 063 /* 064 * Not thread safe. Must be externally synchronized. 065 */ 066 private void reset() { 067 rightEvent = null; 068 leftEvent = null; 069 } 070 071 public static final class Pair<S1, S2> { 072 private final S1 first; 073 private final S2 second; 074 075 public S1 getFirst() { 076 return first; 077 } 078 079 public S2 getSecond() { 080 return second; 081 } 082 083 private Pair(final S1 s1, final S2 s2) { 084 this.first = s1; 085 this.second = s2; 086 } 087 } 088 089 private class Left implements EventHandler<L> { 090 091 @Override 092 public void onNext(final L event) { 093 094 L leftRef = null; 095 R rightRef = null; 096 097 synchronized (mutex) { 098 099 while (leftEvent != null) { 100 try { 101 mutex.wait(); 102 } catch (final InterruptedException e) { 103 LOG.log(Level.SEVERE, "Wait interrupted.", e); 104 } 105 } 106 107 if (LOG.isLoggable(Level.FINEST)) { 108 LOG.log(Level.FINEST, "{0} producing left {1}", 109 new Object[]{Thread.currentThread(), event}); 110 } 111 112 leftEvent = event; 113 leftRef = event; 114 115 if (rightEvent != null) { 116 rightRef = rightEvent; 117 reset(); 118 mutex.notifyAll(); 119 } 120 } 121 122 if (rightRef != null) { 123 // I get to fire the event 124 destination.onNext(new Pair<L, R>(leftRef, rightRef)); 125 } 126 } 127 } 128 129 private class Right implements EventHandler<R> { 130 131 @Override 132 public void onNext(final R event) { 133 134 L leftRef = null; 135 R rightRef = null; 136 137 synchronized (mutex) { 138 139 while (rightEvent != null) { 140 try { 141 mutex.wait(); 142 } catch (final InterruptedException e) { 143 LOG.log(Level.SEVERE, "Wait interrupted.", e); 144 } 145 } 146 147 if (LOG.isLoggable(Level.FINEST)) { 148 LOG.log(Level.FINEST, "{0} producing right {1}", 149 new Object[]{Thread.currentThread(), event}); 150 } 151 152 rightEvent = event; 153 rightRef = event; 154 155 if (leftEvent != null) { 156 leftRef = leftEvent; 157 reset(); 158 mutex.notifyAll(); 159 } 160 } 161 162 if (leftRef != null) { 163 // I get to fire the event 164 destination.onNext(new Pair<L, R>(leftRef, rightRef)); 165 } 166 } 167 } 168}