/* * Quasar: lightweight threads and actors for the JVM. * Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.actors; import co.paralleluniverse.common.monitoring.FlightRecorder; import co.paralleluniverse.common.monitoring.FlightRecorderMessage; import co.paralleluniverse.common.util.Debug; import co.paralleluniverse.fibers.SuspendExecution; import co.paralleluniverse.strands.channels.SendPort; import co.paralleluniverse.strands.queues.QueueCapacityExceededException; import java.util.Objects; public abstract class ActorImpl<Message> implements java.io.Serializable { static final long serialVersionUID = 894359345L; // private static final int MAX_SEND_RETRIES = 10; // protected transient ActorRef<Message> ref; // can actually be set after onstruction by ActorRef.readResolve() private volatile String name; private final SendPort<Object> mailbox; private LifecycleListener lifecycleListener; protected transient final FlightRecorder flightRecorder; @Override public String toString() { return "Actor@" + (name != null ? name : Integer.toHexString(System.identityHashCode(this))); } protected ActorImpl(String name, SendPort<Object> mailbox, ActorRef<Message> ref) { this.name = name; this.mailbox = mailbox; this.flightRecorder = Debug.isDebug() ? Debug.getGlobalFlightRecorder() : null; this.ref = ref != null ? ref : new ActorRef<>(this); } public String getName() { return name; } protected void setName(String name) { if (this.name != null) throw new IllegalStateException("Actor " + this + " already has a name: " + this.name); this.name = name; } public ActorRef<Message> ref() { return ref; } void setRef(ActorRef<Message> ref) { this.ref = ref; } //<editor-fold desc="Mailbox methods"> /////////// Mailbox methods /////////////////////////////////// protected SendPort<Object> mailbox() { return mailbox; } public SendPort<Object> getMailbox() { return mailbox; } public void sendOrInterrupt(Object message) { try { internalSendNonSuspendable(message); } catch (QueueCapacityExceededException e) { interrupt(); } } protected void sendSync(Message message) throws SuspendExecution { MutabilityTester.testMutability(message); try { internalSend(message); } catch (QueueCapacityExceededException e) { throwIn(e); } } public void close() { throw new UnsupportedOperationException(); } public void close(Throwable t) { throw new UnsupportedOperationException(); } protected abstract void interrupt(); protected abstract boolean trySend(Message message); /** * For internal use * * @param message */ protected abstract void internalSend(Object message) throws SuspendExecution; protected abstract void internalSendNonSuspendable(Object message); //</editor-fold> //<editor-fold desc="Lifecycle"> /////////// Lifecycle /////////////////////////////////// protected abstract void throwIn(RuntimeException e); protected abstract void addLifecycleListener(LifecycleListener listener); protected abstract void removeLifecycleListener(LifecycleListener listener); protected abstract void removeObserverListeners(ActorRef actor); protected LifecycleListener getLifecycleListener() { if (lifecycleListener == null) // maybe benign race lifecycleListener = new ActorLifecycleListener(ref(), null); return lifecycleListener; } protected static class ActorLifecycleListener implements LifecycleListener, java.io.Serializable { private final ActorRef observer; private final Object id; public ActorLifecycleListener(ActorRef observer, Object id) { this.observer = observer; this.id = id; } @Override public void dead(ActorRef actor, Throwable cause) { observer.getImpl().internalSendNonSuspendable(new ExitMessage(actor, cause, id)); } @Override public int hashCode() { return Objects.hashCode(this.id); } @Override public boolean equals(Object obj) { if (!(obj instanceof ActorLifecycleListener)) return false; return Objects.equals(observer, ((ActorLifecycleListener) obj).observer) && Objects.equals(id, ((ActorLifecycleListener) obj).id); } @Override public String toString() { return "ActorLifecycleListener{" + "observer: " + observer + ", id: " + id + '}'; } @Override public Object getId() { return id; } public ActorRef getObserver() { return observer; } } //</editor-fold> static ActorImpl getActorRefImpl(ActorRef actor) { while (actor instanceof ActorRefDelegate) actor = ((ActorRefDelegate) actor).getRef(); return actor.getImpl(); } //<editor-fold defaultstate="collapsed" desc="Recording"> /////////// Recording /////////////////////////////////// protected final boolean isRecordingLevel(int level) { if (flightRecorder == null) return false; final FlightRecorder.ThreadRecorder recorder = flightRecorder.get(); if (recorder == null) return false; return recorder.recordsLevel(level); } protected final void record(int level, String clazz, String method, String format) { if (flightRecorder != null) record(flightRecorder.get(), level, clazz, method, format); } protected final void record(int level, String clazz, String method, String format, Object arg1) { if (flightRecorder != null) record(flightRecorder.get(), level, clazz, method, format, arg1); } protected final void record(int level, String clazz, String method, String format, Object arg1, Object arg2) { if (flightRecorder != null) record(flightRecorder.get(), level, clazz, method, format, arg1, arg2); } protected final void record(int level, String clazz, String method, String format, Object arg1, Object arg2, Object arg3) { if (flightRecorder != null) record(flightRecorder.get(), level, clazz, method, format, arg1, arg2, arg3); } protected final void record(int level, String clazz, String method, String format, Object arg1, Object arg2, Object arg3, Object arg4) { if (flightRecorder != null) record(flightRecorder.get(), level, clazz, method, format, arg1, arg2, arg3, arg4); } protected final void record(int level, String clazz, String method, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { if (flightRecorder != null) record(flightRecorder.get(), level, clazz, method, format, arg1, arg2, arg3, arg4, arg5); } protected final void record(int level, String clazz, String method, String format, Object... args) { if (flightRecorder != null) record(flightRecorder.get(), level, clazz, method, format, args); } private static void record(FlightRecorder.ThreadRecorder recorder, int level, String clazz, String method, String format) { if (recorder != null) recorder.record(level, makeFlightRecorderMessage(recorder, clazz, method, format, null)); } private static void record(FlightRecorder.ThreadRecorder recorder, int level, String clazz, String method, String format, Object arg1) { if (recorder != null) recorder.record(level, makeFlightRecorderMessage(recorder, clazz, method, format, new Object[]{arg1})); } private static void record(FlightRecorder.ThreadRecorder recorder, int level, String clazz, String method, String format, Object arg1, Object arg2) { if (recorder != null) recorder.record(level, makeFlightRecorderMessage(recorder, clazz, method, format, new Object[]{arg1, arg2})); } private static void record(FlightRecorder.ThreadRecorder recorder, int level, String clazz, String method, String format, Object arg1, Object arg2, Object arg3) { if (recorder != null) recorder.record(level, makeFlightRecorderMessage(recorder, clazz, method, format, new Object[]{arg1, arg2, arg3})); } private static void record(FlightRecorder.ThreadRecorder recorder, int level, String clazz, String method, String format, Object arg1, Object arg2, Object arg3, Object arg4) { if (recorder != null) recorder.record(level, makeFlightRecorderMessage(recorder, clazz, method, format, new Object[]{arg1, arg2, arg3, arg4})); } private static void record(FlightRecorder.ThreadRecorder recorder, int level, String clazz, String method, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { if (recorder != null) recorder.record(level, makeFlightRecorderMessage(recorder, clazz, method, format, new Object[]{arg1, arg2, arg3, arg4, arg5})); } private static void record(FlightRecorder.ThreadRecorder recorder, int level, String clazz, String method, String format, Object... args) { if (recorder != null) recorder.record(level, makeFlightRecorderMessage(recorder, clazz, method, format, args)); } private static FlightRecorderMessage makeFlightRecorderMessage(FlightRecorder.ThreadRecorder recorder, String clazz, String method, String format, Object[] args) { return new FlightRecorderMessage(clazz, method, format, args); //return ((FlightRecorderMessageFactory) recorder.getAux()).makeFlightRecorderMessage(clazz, method, format, args); } //</editor-fold> }