1 /* 2 * ************************************************************************************************************************************************************* 3 * 4 * TheseFoolishThings: Miscellaneous utilities 5 * http://tidalwave.it/projects/thesefoolishthings 6 * 7 * Copyright (C) 2009 - 2024 by Tidalwave s.a.s. (http://tidalwave.it) 8 * 9 * ************************************************************************************************************************************************************* 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 12 * You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * 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 17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 18 * 19 * ************************************************************************************************************************************************************* 20 * 21 * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src 22 * git clone https://github.com/tidalwave-it/thesefoolishthings-src 23 * 24 * ************************************************************************************************************************************************************* 25 */ 26 package it.tidalwave.actor.spi; 27 28 import java.lang.reflect.InvocationTargetException; 29 import javax.annotation.Nonnegative; 30 import javax.annotation.Nonnull; 31 import it.tidalwave.actor.annotation.Actor; 32 import it.tidalwave.actor.impl.CollaborationAwareMessageBusAdapter; 33 import it.tidalwave.actor.impl.ExecutorWithPriority; 34 import it.tidalwave.actor.impl.MBeansManager; 35 import it.tidalwave.actor.impl.PostConstructInvoker; 36 import it.tidalwave.actor.impl.PreDestroyInvoker; 37 import lombok.Getter; 38 import lombok.extern.slf4j.Slf4j; 39 import static it.tidalwave.messagebus.spi.ReflectionUtils.*; 40 41 /*************************************************************************************************************************************************************** 42 * 43 * This class is used to activate and deactivate an actor. 44 * 45 * @author Fabrizio Giudici 46 * 47 **************************************************************************************************************************************************************/ 48 @Slf4j 49 public class ActorActivator 50 { 51 @Nonnull 52 private final Class<?> actorClass; 53 54 @Nonnegative @Getter 55 private final int poolSize; 56 57 @Getter 58 private Object actorObject; 59 60 private ExecutorWithPriority executor; 61 62 private CollaborationAwareMessageBusAdapter messageBusAdapter; 63 64 private MBeansManager mBeansManager; 65 66 /*********************************************************************************************************************************************************** 67 * Creates an instance for the given actor class. 68 * 69 * @param actorClass the actor class 70 * @return the instance 71 **********************************************************************************************************************************************************/ 72 public static ActorActivator activatorFor (@Nonnull final Class<?> actorClass) 73 { 74 return new ActorActivator(actorClass, 1); 75 } 76 77 /*********************************************************************************************************************************************************** 78 * Specifies the pool size for this activator. 79 * 80 * @param poolSize the pool size 81 * @return the activator 82 **********************************************************************************************************************************************************/ 83 @Nonnull 84 public ActorActivator withPoolSize (@Nonnegative final int poolSize) 85 { 86 return new ActorActivator(actorClass, poolSize); 87 } 88 89 /*********************************************************************************************************************************************************** 90 * 91 **********************************************************************************************************************************************************/ 92 private ActorActivator (@Nonnull final Class<?> actorClass, @Nonnegative final int poolSize) 93 { 94 this.actorClass = actorClass; 95 this.poolSize = poolSize; 96 } 97 98 /*********************************************************************************************************************************************************** 99 * Activates the managed actor. 100 **********************************************************************************************************************************************************/ 101 public void initialize() 102 { 103 try 104 { 105 final var actor = actorClass.getAnnotation(Actor.class); 106 validate(actor); 107 actorObject = actorClass.getDeclaredConstructor().newInstance(); 108 executor = new ExecutorWithPriority(poolSize, actorClass.getSimpleName(), actor.initialPriority()); 109 mBeansManager = new MBeansManager(actorObject, poolSize); 110 messageBusAdapter = new CollaborationAwareMessageBusAdapter(actorObject, executor, mBeansManager.getStats()); 111 } 112 catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) 113 { 114 throw new RuntimeException(e); 115 } 116 117 forEachMethodInTopDownHierarchy(actorObject, messageBusAdapter); 118 forEachMethodInTopDownHierarchy(actorObject, new PostConstructInvoker(actorObject)); 119 mBeansManager.register(); 120 } 121 122 /*********************************************************************************************************************************************************** 123 * Deactivates the managed actor and releases resources. 124 **********************************************************************************************************************************************************/ 125 public void dispose() 126 { 127 mBeansManager.unregister(); 128 forEachMethodInBottomUpHierarchy(actorObject, new PreDestroyInvoker(actorObject)); 129 messageBusAdapter.unsubscribe(); 130 } 131 132 /*********************************************************************************************************************************************************** 133 * 134 **********************************************************************************************************************************************************/ 135 private void validate (@Nonnull final Actor actor) 136 { 137 //noinspection ConstantConditions 138 if (actor == null) 139 { 140 throw new IllegalArgumentException("Actor class must be annotated with @Actor: " + actorClass); 141 } 142 143 if (!actor.threadSafe() && (poolSize != 1)) 144 { 145 throw new IllegalArgumentException("Actors that aren't thread safe can't have pool size > 1"); 146 } 147 } 148 }