コード例 #1
0
ファイル: GMS.java プロジェクト: NZDIS/jgroups
  public void run() {
    Event evt;

    while (evt_thread != null && event_queue != null) {
      try {
        evt = (Event) event_queue.remove();
        switch (evt.getType()) {
          case Event.SUSPECT:
            impl.suspect((Address) evt.getArg());
            break;
          case Event.MERGE:
            impl.merge((Vector) evt.getArg());
            break;
          default:
            Trace.error(
                "GMS.run()",
                "event handler thread encountered event of type "
                    + Event.type2String(evt.getType())
                    + ": not handled by me !");
            break;
        }
      } catch (QueueClosedException closed) {
        break;
      } catch (Exception ex) {
        Trace.warn("GMS.run()", "exception=" + ex);
      }
    }
  }
コード例 #2
0
ファイル: Discovery.java プロジェクト: randythomas/JGroups
  /**
   * An event is to be sent down the stack. The layer may want to examine its type and perform some
   * action on it, depending on the event's type. If the event is a message MSG, then the layer may
   * need to add a header to it (or do nothing at all) before sending it down the stack using <code>
   * PassDown</code>. In case of a GET_ADDRESS event (which tries to retrieve the stack's address
   * from one of the bottom layers), the layer may need to send a new response event back up the
   * stack using <code>up_prot.up()</code>. The PING protocol is interested in several different
   * down events, Event.FIND_INITIAL_MBRS - sent by the GMS layer and expecting a GET_MBRS_OK
   * Event.TMP_VIEW and Event.VIEW_CHANGE - a view change event Event.BECOME_SERVER - called after
   * client has joined and is fully working group member Event.CONNECT, Event.DISCONNECT.
   */
  @SuppressWarnings("unchecked")
  public Object down(Event evt) {

    switch (evt.getType()) {
      case Event.FIND_INITIAL_MBRS: // sent by GMS layer
      case Event.FIND_ALL_VIEWS:
        // sends the GET_MBRS_REQ to all members, waits 'timeout' ms or until 'num_initial_members'
        // have been retrieved
        long start = System.currentTimeMillis();
        boolean find_all_views = evt.getType() == Event.FIND_ALL_VIEWS;
        Promise<JoinRsp> promise = (Promise<JoinRsp>) evt.getArg();
        List<PingData> rsps = find_all_views ? findAllViews(promise) : findInitialMembers(promise);
        long diff = System.currentTimeMillis() - start;
        if (log.isTraceEnabled())
          log.trace("discovery took " + diff + " ms: responses: " + Util.printPingData(rsps));
        return rsps;

      case Event.TMP_VIEW:
      case Event.VIEW_CHANGE:
        List<Address> tmp;
        view = (View) evt.getArg();
        if ((tmp = view.getMembers()) != null) {
          synchronized (members) {
            members.clear();
            members.addAll(tmp);
          }
        }
        current_coord = !members.isEmpty() ? members.get(0) : null;
        is_coord = current_coord != null && local_addr != null && current_coord.equals(local_addr);

        return down_prot.down(evt);

      case Event.BECOME_SERVER: // called after client has joined and is fully working group member
        down_prot.down(evt);
        is_server = true;
        return null;

      case Event.SET_LOCAL_ADDRESS:
        local_addr = (Address) evt.getArg();
        return down_prot.down(evt);

      case Event.CONNECT:
      case Event.CONNECT_WITH_STATE_TRANSFER:
      case Event.CONNECT_USE_FLUSH:
      case Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH:
        is_leaving = false;
        group_addr = (String) evt.getArg();
        Object ret = down_prot.down(evt);
        handleConnect();
        return ret;

      case Event.DISCONNECT:
        is_leaving = true;
        handleDisconnect();
        return down_prot.down(evt);

      default:
        return down_prot.down(evt); // Pass on to the layer below us
    }
  }
コード例 #3
0
  // Starts the simulation. It will end when no more packets are in the
  // medium
  public void runSimulator() {
    Event next;
    Packet p;

    while (true) {
      next = eventList.removeNext();

      if (next == null) {
        break;
      }

      if (traceLevel > 1) {
        System.out.println();
        System.out.println(
            "main(): event received.  t=" + next.getTime() + ", node=" + next.getEntity());
        if (next.getType() == FROMLAYER2) {
          p = next.getPacket();
          System.out.print("  src=" + p.getSource() + ", ");
          System.out.print("dest=" + p.getDest() + ", ");
          System.out.print("contents=[");
          for (int i = 0; i < NUMENTITIES - 1; i++) {
            System.out.print(p.getMincost(i) + ", ");
          }
          System.out.println(p.getMincost(NUMENTITIES - 1) + "]");
        } else if (next.getType() == LINKCHANGE) {
          System.out.println("  Link cost change.");
        }
      }

      time = next.getTime();

      if (next.getType() == FROMLAYER2) {
        p = next.getPacket();
        if ((next.getEntity() < 0) || (next.getEntity() >= NUMENTITIES)) {
          System.out.println("main(): Panic. Unknown event entity.");
        } else {
          entity[next.getEntity()].update(p);
        }
      } else if (next.getType() == LINKCHANGE) {
        if (time < 10001.0) {
          cost[0][1] = 20;
          cost[1][0] = 20;
          entity[0].linkCostChangeHandler(1, 20);
          entity[1].linkCostChangeHandler(0, 20);
        } else {
          cost[0][1] = 1;
          cost[1][0] = 1;
          entity[0].linkCostChangeHandler(1, 1);
          entity[1].linkCostChangeHandler(0, 1);
        }
      } else {
        System.out.println("main(): Panic.  Unknown event type.");
      }
    }

    System.out.println("Simulator terminated at t=" + time + ", no packets in medium.");
  }
コード例 #4
0
 public static void dispatchEvent(World world, Entity entity, Event event) {
   if (scm.has(entity) && scm.get(entity).hasEventScripts(event.getType()))
     for (Script script : scm.get(entity).getScriptsByEvent(event.getType())) {
       script.run(world, event);
     }
   else
     LOGGER.fine(
         "Dispatch event " + event.getType() + "  to a entity which do not has ScriptComponent");
 }
コード例 #5
0
ファイル: ProM.java プロジェクト: ijlalhussain/LogGenerator
 /**
  * @param event AbstractEvent
  * @return EventType
  */
 public static XLifecycleExtension.StandardModel getType(Event event) {
   XLifecycleExtension.StandardModel type = XLifecycleExtension.StandardModel.COMPLETE;
   if (event.getType().equals(Event.Type.STARTED)) {
     type = XLifecycleExtension.StandardModel.START;
   }
   if (event.getType().equals(Event.Type.CANCELLED)) {
     type = XLifecycleExtension.StandardModel.ATE_ABORT;
   }
   return type;
 }
コード例 #6
0
ファイル: EventBuilder.java プロジェクト: rnovacek/candlepin
 public EventBuilder setNewEntity(AbstractHibernateObject updated) {
   if (updated != null) {
     if (event.getType() == Type.DELETED || event.getType() == Type.EXPIRED) {
       throw new IllegalArgumentException("You cannot set the new entity for a deletion event");
     }
     setEventData(updated);
     event.setNewEntity(factory.entityToJson(updated));
   }
   return this;
 }
コード例 #7
0
ファイル: EventTest.java プロジェクト: enonic/xp
  @Test
  public void testClone() {
    final Event event = this.createTestEvent();
    final Event clonedEvent = Event.create(event).build();

    assertEquals(event.getType(), clonedEvent.getType());
    assertEquals(event.isDistributed(), clonedEvent.isDistributed());
    assertEquals(event.getData(), clonedEvent.getData());
    assertEquals(event, clonedEvent);
  }
コード例 #8
0
ファイル: GMS.java プロジェクト: NZDIS/jgroups
 // Priority handling, otherwise GMS.down(DISCONNECT) would block !
 // Similar to FLUSH protocol
 public void receiveDownEvent(Event evt) {
   if (evt.getType() == Event.BLOCK_OK) {
     passDown(evt);
     return;
   }
   super.receiveDownEvent(evt);
 }
コード例 #9
0
ファイル: GMS.java プロジェクト: NZDIS/jgroups
  /**
   * <b>Callback</b>. Called by superclass when event may be handled.
   *
   * <p><b>Do not use <code>PassDown</code> in this method as the event is passed down by default by
   * the superclass after this method returns !</b>
   *
   * @return boolean Defaults to true. If false, event will not be passed down the stack.
   */
  public boolean handleDownEvent(Event evt) {
    switch (evt.getType()) {
      case Event.CONNECT:
        passDown(evt);
        try {
          group_addr = (String) evt.getArg();
        } catch (ClassCastException cce) {
          Trace.error(
              "GMS.handleDownEvent(CONNECT)",
              "group address must " + "be a string (group name) to make sense");
        }
        impl.join(local_addr);
        passUp(new Event(Event.CONNECT_OK));
        startEventHandlerThread();
        return false; // don't pass down: was already passed down

      case Event.DISCONNECT:
        impl.leave((Address) evt.getArg());
        passUp(new Event(Event.DISCONNECT_OK));
        stopEventHandlerThread();
        initState();
        return true; // pass down
    }

    return impl.handleDownEvent(evt);
  }
コード例 #10
0
ファイル: DAISYCHAIN.java プロジェクト: DevFactory/JGroups
  public Object up(Event evt) {
    switch (evt.getType()) {
      case Event.MSG:
        Message msg = (Message) evt.getArg();
        DaisyHeader hdr = (DaisyHeader) msg.getHeader(getId());
        if (hdr == null) break;

        // 1. forward the message to the next in line if ttl > 0
        short ttl = hdr.getTTL();
        if (log.isTraceEnabled())
          log.trace(local_addr + ": received message from " + msg.getSrc() + " with ttl=" + ttl);
        if (--ttl > 0) {
          Message copy = msg.copy(true);
          copy.setDest(next);
          copy.putHeader(getId(), new DaisyHeader(ttl));
          msgs_forwarded++;
          if (log.isTraceEnabled())
            log.trace(local_addr + ": forwarding message to " + next + " with ttl=" + ttl);
          down_prot.down(new Event(Event.MSG, copy));
        }

        // 2. Pass up
        msg.setDest(null);
        break;
    }
    return up_prot.up(evt);
  }
コード例 #11
0
 public Object down(Event evt) {
   if (drop_next && evt.getType() == Event.MSG) {
     drop_next = false;
     return null;
   }
   return super.down(evt);
 }
コード例 #12
0
  @Test
  public void deserializeEventDataAccountEvent() throws IOException {
    String json = resource("account_event.json");
    Event e = StripeObject.PRETTY_PRINT_GSON.fromJson(json, Event.class);

    assertEquals(e.getType(), "account.updated");
  }
コード例 #13
0
ファイル: FORK.java プロジェクト: xiongrl/JGroups
  public Object up(Event evt) {
    switch (evt.getType()) {
      case Event.MSG:
        Message msg = (Message) evt.getArg();
        ForkHeader hdr = (ForkHeader) msg.getHeader(id);
        if (hdr == null) break;
        if (hdr.fork_stack_id == null)
          throw new IllegalArgumentException("header has a null fork_stack_id");
        Protocol bottom_prot = get(hdr.fork_stack_id);
        return bottom_prot != null
            ? bottom_prot.up(evt)
            : this.unknownForkHandler.handleUnknownForkStack(msg, hdr.fork_stack_id);

      case Event.VIEW_CHANGE:
        for (Protocol bottom : fork_stacks.values()) bottom.up(evt);
        break;

      case Event.STATE_TRANSFER_OUTPUTSTREAM:
        if (!process_state_events) break;
        getStateFromMainAndForkChannels(evt);
        return null;

      case Event.STATE_TRANSFER_INPUTSTREAM:
        if (!process_state_events) break;
        setStateInMainAndForkChannels((InputStream) evt.getArg());
        return null;
    }
    return up_prot.up(evt);
  }
コード例 #14
0
ファイル: ScrollPane.java プロジェクト: ShadowLordAlpha/TWL
 @Override
 protected boolean handleEvent(Event evt) {
   if (evt.isKeyEvent() && content != null && content.canAcceptKeyboardFocus()) {
     if (content.handleEvent(evt)) {
       content.requestKeyboardFocus();
       return true;
     }
   }
   if (super.handleEvent(evt)) {
     return true;
   }
   switch (evt.getType()) {
     case KEY_PRESSED:
     case KEY_RELEASED:
       {
         int keyCode = evt.getKeyCode();
         if (keyCode == Event.KEY_LEFT || keyCode == Event.KEY_RIGHT) {
           return scrollbarH.handleEvent(evt);
         }
         if (keyCode == Event.KEY_UP
             || keyCode == Event.KEY_DOWN
             || keyCode == Event.KEY_PRIOR
             || keyCode == Event.KEY_NEXT) {
           return scrollbarV.handleEvent(evt);
         }
         break;
       }
     case MOUSE_WHEEL:
       if (scrollbarV.isVisible()) {
         return scrollbarV.handleEvent(evt);
       }
       return false;
   }
   return evt.isMouseEvent() && contentArea.isMouseInside(evt);
 }
コード例 #15
0
ファイル: EventDB.java プロジェクト: nstamas/EventDB
  /**
   * addAthlete(String n, String t) This method creates an iterator, itr, and iterates through each
   * event to match the event passed into the parameter, t. If t matches an event, it will check to
   * make sure the athlete is not already in that event, and then add that athlete to the event. If
   * the event does not match, or if the athlete is already in that event, the athlete will not be
   * added
   *
   * @param t The event name that is compared with the events already created
   * @param n The athlete name that is compared with the athletes already added
   */
  public void addAthlete(String n, String t) {

    Iterator<Event> itr1 = events.iterator();
    Event currentEvent;
    boolean eventExists = false;
    boolean contains = false;

    while (itr1.hasNext()) {
      if (itr1.next().getType().equalsIgnoreCase(t)) {
        eventExists = true;
      }
    }

    if (!eventExists) {
      throw new java.lang.IllegalArgumentException("Error " + "event not found");
    }

    itr1 = events.iterator();
    while (itr1.hasNext()) {
      currentEvent = itr1.next();
      if (currentEvent.getType().equalsIgnoreCase(t)) {
        Iterator<String> itr2 = currentEvent.getRoster().iterator();
        while (itr2.hasNext()) {
          String currAthlete = itr2.next();
          if (currAthlete.equalsIgnoreCase(n)) {
            contains = true;
            break;
          }
        }
        if (!contains) {
          currentEvent.getRoster().add(n);
        }
      }
    }
  }
コード例 #16
0
  @SuppressWarnings("unchecked")
  protected void dispatch(Event event) {
    // all events go thru this loop
    if (LOG.isDebugEnabled()) {
      LOG.debug("Dispatching the event " + event.getClass().getName() + "." + event.toString());
    }

    Class<? extends Enum> type = event.getType().getDeclaringClass();

    try {
      EventHandler handler = eventDispatchers.get(type);
      if (handler != null) {
        handler.handle(event);
      } else {
        throw new Exception("No handler for registered for " + type);
      }
    } catch (Throwable t) {
      // TODO Maybe log the state of the queue
      LOG.fatal("Error in dispatcher thread", t);
      // If serviceStop is called, we should exit this thread gracefully.
      if (exitOnDispatchException
          && (ShutdownHookManager.get().isShutdownInProgress()) == false
          && stopped == false) {
        Thread shutDownThread = new Thread(createShutDownThread());
        shutDownThread.setName("AsyncDispatcher ShutDown handler");
        shutDownThread.start();
      }
    }
  }
コード例 #17
0
ファイル: Locking.java プロジェクト: an1310/JGroups
  public Object up(Event evt) {
    switch (evt.getType()) {
      case Event.MSG:
        Message msg = (Message) evt.getArg();
        LockingHeader hdr = (LockingHeader) msg.getHeader(id);
        if (hdr == null) break;

        Request req = (Request) msg.getObject();
        if (log.isTraceEnabled())
          log.trace("[" + local_addr + "] <-- [" + msg.getSrc() + "] " + req);
        switch (req.type) {
          case GRANT_LOCK:
          case RELEASE_LOCK:
            handleLockRequest(req);
            break;
          case LOCK_GRANTED:
            handleLockGrantedResponse(req.lock_name, req.owner, msg.getSrc());
            break;
          case LOCK_DENIED:
            handleLockDeniedResponse(req.lock_name, req.owner);
            break;
          case CREATE_LOCK:
            handleCreateLockRequest(req.lock_name, req.owner);
            break;
          case DELETE_LOCK:
            handleDeleteLockRequest(req.lock_name);
            break;
          case COND_SIG:
          case COND_SIG_ALL:
            handleSignalRequest(req);
            break;
          case LOCK_AWAIT:
            handleAwaitRequest(req.lock_name, req.owner);
            handleLockRequest(req);
            break;
          case DELETE_LOCK_AWAIT:
            handleDeleteAwaitRequest(req.lock_name, req.owner);
            break;
          case SIG_RET:
            handleSignalResponse(req.lock_name, req.owner);
            break;
          case CREATE_AWAITER:
            handleCreateAwaitingRequest(req.lock_name, req.owner);
            break;
          case DELETE_AWAITER:
            handleDeleteAwaitingRequest(req.lock_name, req.owner);
            break;
          default:
            log.error("Request of type " + req.type + " not known");
            break;
        }
        return null;

      case Event.VIEW_CHANGE:
        handleView((View) evt.getArg());
        break;
    }
    return up_prot.up(evt);
  }
コード例 #18
0
ファイル: Executing.java プロジェクト: rhusar/JGroups
 public Object up(Event evt) {
   switch (evt.getType()) {
     case Event.VIEW_CHANGE:
       handleView(evt.getArg());
       break;
   }
   return up_prot.up(evt);
 }
コード例 #19
0
ファイル: Session.java プロジェクト: dhammalab/satipatthana
 private Event getNextDisappearEventWithTheSameType(Event event, int position) {
   for (int i = position, n = events.size(); i < n; i++) {
     if (events.get(i).getType() == event.getType() && !events.get(i).isNoteAppear()) {
       return events.get(i);
     }
   }
   return null;
 }
コード例 #20
0
ファイル: FORK.java プロジェクト: xiongrl/JGroups
 public Object down(Event evt) {
   switch (evt.getType()) {
     case Event.SET_LOCAL_ADDRESS:
       local_addr = (Address) evt.getArg();
       break;
   }
   return down_prot.down(evt);
 }
コード例 #21
0
 public Object down(Event evt) {
   if (channel != null) {
     if (evt.getType() == Event.MSG && !(channel.isConnected() || channel.isConnecting()))
       throw new IllegalStateException("channel is not connected");
     return channel.down(evt);
   }
   return null;
 }
コード例 #22
0
ファイル: JChannel.java プロジェクト: schaebo/JGroups
 /**
  * Sends an event down the protocol stack. Note that - contrary to {@link #send(Message)}, if the
  * event is a message, no checks are performed whether the channel is closed or disconnected.
  *
  * @param evt the message to send down, encapsulated in an event
  */
 public Object down(Event evt) {
   if (evt == null) return null;
   if (stats && evt.getType() == Event.MSG) {
     sent_msgs++;
     sent_bytes += ((Message) evt.getArg()).getLength();
   }
   return prot_stack.down(evt);
 }
コード例 #23
0
ファイル: Session.java プロジェクト: dhammalab/satipatthana
 public int getCompletedNotesCount(NoteType noteType) {
   int disappearCount = 0;
   for (Event event : events) {
     if (!event.isNoteAppear() && noteType == event.getType()) {
       disappearCount++;
     }
   }
   return disappearCount;
 }
コード例 #24
0
ファイル: EXAMPLE.java プロジェクト: nicolas-raoul/JGroups
  public Object up(Event evt) {
    switch (evt.getType()) {
      case Event.MSG:
        Message msg = (Message) evt.getArg();
        // Do something with the event, e.g. extract the message and remove a header.
        // Optionally pass up
        break;
    }

    return up_prot.up(evt); // Pass up to the layer above us
  }
コード例 #25
0
  /**
   * Determines if an event should be printed or not.
   *
   * <p>Filters may be: - by event source - by event type
   *
   * @param source used to filter by
   * @param event event to check
   * @return true if filter does not match, else true
   */
  private boolean shouldPrint(final Node source, final Event event) {
    if (isNodeFiltered(source)) {
      return false;
    }

    if (isTypeFiltered(event.getType())) {
      return false;
    }

    return true;
  }
コード例 #26
0
ファイル: STATE_TRANSFER.java プロジェクト: xiongrl/JGroups
  public Object down(Event evt) {
    switch (evt.getType()) {
      case Event.TMP_VIEW:
      case Event.VIEW_CHANGE:
        handleViewChange((View) evt.getArg());
        break;

      case Event.GET_STATE:
        Address target;
        StateTransferInfo info = (StateTransferInfo) evt.getArg();
        if (info.target == null) {
          target = determineCoordinator();
        } else {
          target = info.target;
          if (target.equals(local_addr)) {
            log.error("%s: cannot fetch state from myself", local_addr);
            target = null;
          }
        }
        if (target == null) {
          log.debug("%s: first member (no state)", local_addr);
          up_prot.up(new Event(Event.GET_STATE_OK, new StateTransferInfo()));
        } else {
          Message state_req =
              new Message(target)
                  .putHeader(this.id, new StateHeader(StateHeader.STATE_REQ))
                  .setFlag(Message.Flag.DONT_BUNDLE, Message.Flag.OOB, Message.Flag.SKIP_BARRIER);
          log.debug("%s: asking %s for state", local_addr, target);

          // suspend sending and handling of message garbage collection gossip messages,
          // fixes bugs #943480 and #938584). Wake up when state has been received
          /*if(log.isDebugEnabled())
              log.debug("passing down a SUSPEND_STABLE event");
          down_prot.down(new Event(Event.SUSPEND_STABLE, new Long(info.timeout)));*/
          waiting_for_state_response = true;
          start = System.currentTimeMillis();
          down_prot.down(new Event(Event.MSG, state_req));
        }
        return null; // don't pass down any further !

      case Event.CONFIG:
        Map<String, Object> config = (Map<String, Object>) evt.getArg();
        if (config != null && config.containsKey("flush_supported")) {
          flushProtocolInStack = true;
        }
        break;

      case Event.SET_LOCAL_ADDRESS:
        local_addr = (Address) evt.getArg();
        break;
    }

    return down_prot.down(evt); // pass on to the layer below us
  }
コード例 #27
0
 @POST
 @Consumes(MediaType.APPLICATION_JSON)
 public Response post(List<Event> events) throws IOException {
   Set<String> badEvents = Sets.newHashSet();
   for (Event event : events) {
     if (acceptedEventType(event.getType())) {
       for (EventWriter writer : writers) {
         writer.write(event);
       }
       increment(event.getType());
     } else {
       badEvents.add(event.getType());
     }
   }
   if (!badEvents.isEmpty()) {
     String errorMessage = "Invalid event type(s): " + Joiner.on(", ").join(badEvents);
     return Response.status(Status.BAD_REQUEST).entity(errorMessage).build();
   }
   return Response.status(Response.Status.ACCEPTED).build();
 }
コード例 #28
0
ファイル: EventDB.java プロジェクト: nstamas/EventDB
 /**
  * getRoster(String t) Retrieves the athlete roster from the event, t, and returns it. If the
  * event is not in the database, it returns null.
  *
  * @param t The event name that the method is searching for
  * @return currentEvent.getRoster(), the roster, if the event is found, else it returns null if
  *     the event is empty or not in the database.
  */
 public List<String> getRoster(String t) {
   Iterator<Event> itr = events.iterator();
   Event currentEvent;
   while (itr.hasNext()) {
     currentEvent = itr.next();
     // checking to make sure event is register
     if (currentEvent.getType().equalsIgnoreCase(t)) {
       return currentEvent.getRoster();
     }
   }
   return null;
 }
コード例 #29
0
ファイル: EventDB.java プロジェクト: nstamas/EventDB
 /**
  * removeEvent(String t) This method creates an iterator, itr, and iterates through each event to
  * match the event passed into the parameter, t. If t matches an event, the method will remove the
  * event, t, from the database, and it will return true. If the event, t, does not match a current
  * event, it will return false.
  *
  * @param t The event name that is compared with the events already created
  * @return true if the event is removed and false if the event, t, is not in the database and
  *     therefore not removed.
  */
 public boolean removeEvent(String t) {
   Iterator<Event> itr = events.iterator();
   Event currentEvent;
   while (itr.hasNext()) {
     currentEvent = itr.next();
     if (currentEvent.getType().equalsIgnoreCase(t)) {
       events.remove(currentEvent);
       return true;
     }
   }
   return false;
 }
コード例 #30
0
ファイル: Session.java プロジェクト: dhammalab/satipatthana
 public void addEvent(Event event) {
   if (event == null) {
     throw new IllegalArgumentException("Event could not be null");
   }
   Event latestEvent = getLatestEvent(event.getType());
   if (latestEvent == null || latestEvent.isNoteAppear() != event.isNoteAppear()) {
     events.add(event);
   } else {
     throw new IllegalArgumentException(
         "Note could not appear twice in a row. It could only appear and then disappear");
   }
 }