001/* 002 * JGrapes Event Driven Framework 003 * Copyright (C) 2016-2018 Michael N. Lipp 004 * 005 * This program is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Affero General Public License as published by 007 * the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 013 * for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License along 016 * with this program; if not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jgrapes.core.internal; 020 021import java.lang.annotation.Annotation; 022import java.lang.reflect.Method; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.ConcurrentModificationException; 027import java.util.Iterator; 028import java.util.List; 029import java.util.NoSuchElementException; 030import java.util.Stack; 031import java.util.concurrent.ExecutorService; 032import org.jgrapes.core.Channel; 033import org.jgrapes.core.ComponentType; 034import org.jgrapes.core.Components; 035import org.jgrapes.core.Event; 036import org.jgrapes.core.EventPipeline; 037import org.jgrapes.core.HandlerScope; 038import org.jgrapes.core.Manager; 039import org.jgrapes.core.annotation.HandlerDefinition; 040import org.jgrapes.core.annotation.HandlerDefinition.ChannelReplacements; 041import org.jgrapes.core.events.Attached; 042import org.jgrapes.core.events.Detached; 043import org.jgrapes.core.events.Start; 044 045/** 046 * ComponentVertex is the base class for all nodes in the component tree. 047 * ComponentVertex is extended by {@link org.jgrapes.core.Component} 048 * for the use as base class for component implementations. As an 049 * alternative for implementing components with an independent base class, 050 * the derived class {@link org.jgrapes.core.internal.ComponentProxy} can be 051 * used. 052 */ 053@SuppressWarnings({ "PMD.TooManyMethods", "PMD.DataflowAnomalyAnalysis", 054 "PMD.AvoidDuplicateLiterals", "PMD.GodClass" }) 055public abstract class ComponentVertex implements Manager, Channel { 056 057 /** The component's (optional) name. */ 058 private String name; 059 /** Reference to the common properties of the tree nodes. */ 060 private ComponentTree tree; 061 /** Reference to the parent node. */ 062 private ComponentVertex parent; 063 /** All the node's children */ 064 private final List<ComponentVertex> children = new ArrayList<>(); 065 /** The handlers provided by this component. */ 066 private List<HandlerReference> handlers; 067 068 /** 069 * Initialize the ComponentVertex. By default it forms a stand-alone 070 * tree, i.e. the root is set to the component itself. 071 */ 072 protected ComponentVertex() { 073 // Nothing to do, but appropriate for abstract class. 074 } 075 076 /** 077 * Initialize the handler list of this component. May only be called 078 * when {@link #component()} can be relied on to return the 079 * correct value. 080 */ 081 @SuppressWarnings("PMD.AvoidDuplicateLiterals") 082 protected void initComponentsHandlers( 083 ChannelReplacements channelReplacements) { 084 handlers = new ArrayList<>(); 085 // Have a look at all methods. 086 for (Method m : component().getClass().getMethods()) { 087 maybeAddHandler(m, channelReplacements); 088 } 089 handlers = Collections.synchronizedList(handlers); 090 } 091 092 private void maybeAddHandler( 093 Method method, ChannelReplacements channelReplacements) { 094 for (Annotation annotation : method.getDeclaredAnnotations()) { 095 Class<?> annoType = annotation.annotationType(); 096 HandlerDefinition hda = annoType.getAnnotation( 097 HandlerDefinition.class); 098 if (hda == null) { 099 continue; 100 } 101 HandlerDefinition.Evaluator evaluator 102 = CoreUtils.definitionEvaluator(hda); 103 HandlerScope scope = evaluator.scope(component(), method, 104 channelReplacements); 105 if (scope == null) { 106 continue; 107 } 108 handlers.add(HandlerReference.newRef( 109 component(), method, evaluator.priority(annotation), 110 scope)); 111 } 112 } 113 114 /* 115 * (non-Javadoc) 116 * 117 * @see org.jgrapes.core.Manager#setName(java.lang.String) 118 */ 119 @Override 120 public ComponentType setName(String name) { 121 this.name = name; 122 return component(); 123 } 124 125 /* 126 * (non-Javadoc) 127 * 128 * @see org.jgrapes.core.Manager#name() 129 */ 130 @Override 131 public String name() { 132 return name; 133 } 134 135 /* 136 * (non-Javadoc) 137 * 138 * @see org.jgrapes.core.Manager#path() 139 */ 140 @Override 141 public String componentPath() { 142 StringBuilder res = new StringBuilder(); 143 buildPath(res); 144 return res.toString(); 145 } 146 147 private void buildPath(StringBuilder builder) { 148 if (parent != null) { 149 parent.buildPath(builder); 150 } 151 builder.append('/') 152 .append(name == null ? getClass().getSimpleName() : name); 153 } 154 155 /** 156 * Return the component node for a given component. 157 * 158 * @param component the component 159 * @param componentChannel the component's channel 160 * @return the node representing the component in the tree 161 */ 162 public static ComponentVertex componentVertex( 163 ComponentType component, Channel componentChannel) { 164 if (component instanceof ComponentVertex) { 165 return (ComponentVertex) component; 166 } 167 return ComponentProxy.getComponentProxy(component, componentChannel); 168 } 169 170 /** 171 * Returns the component represented by this node in the tree. 172 * 173 * @return the component 174 */ 175 public abstract ComponentType component(); 176 177 /* 178 * (non-Javadoc) 179 * 180 * @see org.jgrapes.core.Manager#getChildren() 181 */ 182 @Override 183 public List<ComponentType> children() { 184 synchronized (this) { 185 List<ComponentType> children = new ArrayList<>(); 186 for (ComponentVertex child : this.children) { 187 children.add(child.component()); 188 } 189 return Collections.unmodifiableList(children); 190 } 191 } 192 193 /* 194 * (non-Javadoc) 195 * 196 * @see org.jgrapes.core.Manager#getParent() 197 */ 198 @Override 199 public ComponentType parent() { 200 synchronized (this) { 201 if (parent == null) { 202 return null; 203 } 204 return parent.component(); 205 } 206 } 207 208 /* 209 * (non-Javadoc) 210 * 211 * @see org.jgrapes.core.Manager#getRoot() 212 */ 213 @Override 214 public ComponentType root() { 215 return tree().root().component(); 216 } 217 218 /** 219 * Return the tree that this node belongs to. If the node does not 220 * belong to a tree yet, a tree is automatically created. 221 * 222 * @return the tree 223 */ 224 /* default */ ComponentTree tree() { 225 if (tree != null) { 226 return tree; 227 } 228 // Build complete tree before assigning it. 229 ComponentTree newTree = new ComponentTree(this); 230 newTree.setEventPipeline(new BufferingEventPipeline(newTree)); 231 tree = newTree; 232 fire(new Attached(component(), null), channel()); 233 return tree; 234 } 235 236 /** 237 * Set the reference to the common properties of this component 238 * and all its children to the given value. 239 * 240 * @param comp the new root 241 */ 242 private void setTree(ComponentTree tree) { 243 synchronized (this) { 244 this.tree = tree; 245 for (ComponentVertex child : children) { 246 child.setTree(tree); 247 } 248 } 249 } 250 251 /* 252 * (non-Javadoc) 253 * 254 * @see org.jgrapes.core.Manager#attach(Component) 255 */ 256 @Override 257 @SuppressWarnings({ "PMD.CyclomaticComplexity", "PMD.NcssCount", 258 "PMD.NPathComplexity", "PMD.CognitiveComplexity" }) 259 public <T extends ComponentType> T attach(T child) { 260 synchronized (this) { 261 ComponentVertex childNode = componentVertex(child, null); 262 List<Channel> attachedAsChannels = new ArrayList<>(); 263 synchronized (childNode) { 264 if (tree != null && tree.isStarted()) { 265 for (TreeIterator itr = new TreeIterator(childNode); 266 itr.hasNext();) { 267 attachedAsChannels.add(itr.next()); 268 } 269 } 270 synchronized (tree()) { 271 if (childNode.tree == null) { 272 // Newly created, stand-alone child node 273 childNode.parent = this; 274 childNode.setTree(tree); 275 children.add(childNode); 276 } else { 277 // Attaching a tree... 278 synchronized (childNode.tree) { 279 if (childNode.parent != null) { 280 throw new IllegalStateException( 281 "Cannot attach a node with a parent."); 282 } 283 if (childNode.tree.isStarted()) { 284 throw new IllegalStateException( 285 "Cannot attach a started subtree."); 286 } 287 childNode.parent = this; 288 ComponentTree childTree = childNode.tree; 289 childNode.setTree(tree); 290 children.add(childNode); 291 tree.mergeEvents(childTree); 292 } 293 } 294 tree.clearHandlerCache(); 295 } 296 } 297 Channel parentChan = channel(); 298 if (parentChan == null) { 299 parentChan = Channel.BROADCAST; 300 } 301 Channel childChan = childNode.channel(); 302 if (childChan == null) { 303 parentChan = Channel.BROADCAST; 304 } 305 Attached evt = new Attached(childNode.component(), component()); 306 if (parentChan.equals(Channel.BROADCAST) 307 || childChan.equals(Channel.BROADCAST)) { 308 fire(evt, Channel.BROADCAST); 309 } else if (parentChan.equals(childChan)) { 310 fire(evt, parentChan); 311 } else { 312 fire(evt, parentChan, childChan); 313 } 314 if (!attachedAsChannels.isEmpty()) { 315 fire(new Start(), attachedAsChannels.toArray(new Channel[0])); 316 } 317 return child; 318 } 319 } 320 321 /* 322 * (non-Javadoc) 323 * 324 * @see org.jgrapes.core.Manager#detach() 325 */ 326 @Override 327 public ComponentType detach() { 328 synchronized (this) { 329 if (parent != null) { 330 ComponentVertex oldParent = parent; 331 synchronized (tree) { 332 if (!tree.isStarted()) { 333 throw new IllegalStateException( 334 "Components may not be detached from a tree before" 335 + " a Start event has been fired on it."); 336 } 337 synchronized (oldParent) { 338 parent.children.remove(this); 339 parent.tree.clearHandlerCache(); 340 parent = null; 341 } 342 ComponentTree newTree = new ComponentTree(this); 343 newTree.setEventPipeline(new FeedBackPipelineFilter( 344 newTree, new EventProcessor(newTree))); 345 setTree(newTree); 346 } 347 Detached evt = new Detached(component(), oldParent.component()); 348 oldParent.fire(evt); 349 evt = new Detached(component(), oldParent.component()); 350 fire(evt); 351 } 352 return component(); 353 } 354 } 355 356 /* 357 * (non-Javadoc) 358 * 359 * @see java.lang.Iterable#iterator() 360 */ 361 @Override 362 public Iterator<ComponentType> iterator() { 363 return new ComponentIterator(new TreeIterator(this)); 364 } 365 366 /** 367 * A simple wrapper that converts a component vertex iterator 368 * to a component (type) iterator. 369 */ 370 private static class ComponentIterator implements Iterator<ComponentType> { 371 372 private final TreeIterator baseIterator; 373 374 /** 375 * @param baseIterator 376 */ 377 public ComponentIterator(TreeIterator baseIterator) { 378 this.baseIterator = baseIterator; 379 } 380 381 @Override 382 public boolean hasNext() { 383 return baseIterator.hasNext(); 384 } 385 386 @Override 387 public ComponentType next() { 388 return baseIterator.next().component(); 389 } 390 391 } 392 393 /** 394 * An iterator for getting all nodes of the tree. 395 */ 396 private static class TreeIterator implements Iterator<ComponentVertex> { 397 398 private final Stack<CurPos> stack = new Stack<>(); 399 private final ComponentTree tree; 400 401 /** 402 * The current position. 403 */ 404 private class CurPos { 405 public ComponentVertex current; 406 public Iterator<ComponentVertex> childIter; 407 408 /** 409 * Instantiates a new current position 410 * 411 * @param vertex the cm 412 */ 413 public CurPos(ComponentVertex vertex) { 414 current = vertex; 415 childIter = current.children.iterator(); 416 } 417 } 418 419 /** 420 * Instantiates a new tree iterator. 421 * 422 * @param root the root 423 */ 424 public TreeIterator(ComponentVertex root) { 425 tree = root.tree(); 426 stack.push(new CurPos(root)); 427 } 428 429 /* 430 * (non-Javadoc) 431 * 432 * @see java.util.Iterator#hasNext() 433 */ 434 @Override 435 public boolean hasNext() { 436 return !stack.empty(); 437 } 438 439 /* 440 * (non-Javadoc) 441 * 442 * @see java.util.Iterator#next() 443 */ 444 @Override 445 @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") 446 public ComponentVertex next() { 447 if (stack.empty()) { 448 throw new NoSuchElementException(); 449 } 450 CurPos pos = stack.peek(); 451 @SuppressWarnings("PMD.PrematureDeclaration") 452 ComponentVertex res = pos.current; 453 while (true) { 454 synchronized (pos.current) { 455 if (pos.current.tree != tree) { 456 throw new ConcurrentModificationException(); 457 } 458 if (pos.childIter.hasNext()) { 459 stack.push(new CurPos(pos.childIter.next())); 460 break; 461 } 462 } 463 stack.pop(); 464 if (stack.empty()) { 465 break; 466 } 467 pos = stack.peek(); 468 } 469 return res; 470 } 471 472 /* 473 * (non-Javadoc) 474 * 475 * @see java.util.Iterator#remove() 476 */ 477 @Override 478 public void remove() { 479 throw new UnsupportedOperationException(); 480 } 481 } 482 483 @Override 484 public void addHandler(Method method, HandlerScope scope, int priority) { 485 handlers.add(HandlerReference.newRef(component(), 486 method, priority, scope)); 487 } 488 489 /* 490 * (non-Javadoc) 491 * 492 * @see org.jgrapes.core.core.Manager#fire 493 * (org.jgrapes.core.Event, org.jgrapes.core.Channel) 494 */ 495 @Override 496 public <T> Event<T> fire(Event<T> event, Channel... channels) { 497 if (channels.length == 0) { 498 channels = event.channels(); 499 if (channels.length == 0) { 500 channels = new Channel[] { channel() }; 501 } 502 } 503 event.setChannels(channels); 504 tree().fire(event, channels); 505 return event; 506 } 507 508 /** 509 * Collects all handlers. Iterates over the tree with this object 510 * as root and for all child components adds the matching handlers to 511 * the result set recursively. 512 * 513 * @param hdlrs the result set 514 * @param event the event to match 515 * @param channels the channels to match 516 */ 517 @SuppressWarnings("PMD.UseVarargs") 518 /* default */ void collectHandlers(Collection<HandlerReference> hdlrs, 519 EventBase<?> event, Channel[] channels) { 520 for (HandlerReference hdlr : handlers) { 521 if (hdlr.handles(event, channels)) { 522 hdlrs.add(hdlr); 523 } 524 } 525 for (ComponentVertex child : children) { 526 child.collectHandlers(hdlrs, event, channels); 527 } 528 } 529 530 /* 531 * (non-Javadoc) 532 * 533 * @see org.jgrapes.core.Manager#activeEventPipeline() 534 */ 535 @Override 536 public EventPipeline activeEventPipeline() { 537 return new CheckingPipelineFilter(tree(), 538 tree().eventPipeline(), channel()); 539 } 540 541 /* 542 * (non-Javadoc) 543 * 544 * @see org.jgrapes.core.Manager#newEventPipeline() 545 */ 546 @Override 547 public EventPipeline newEventPipeline() { 548 return new CheckingPipelineFilter(tree(), new EventProcessor(tree()), 549 channel()); 550 } 551 552 /* 553 * (non-Javadoc) 554 * 555 * @see org.jgrapes.core.Manager#newEventPipeline(java.util.concurrent. 556 * ExecutorService) 557 */ 558 @Override 559 public EventPipeline newEventPipeline(ExecutorService executorService) { 560 return new CheckingPipelineFilter(tree(), 561 new EventProcessor(tree(), executorService), channel()); 562 } 563 564 /** 565 * If a name has been set for this component 566 * (see {@link Manager#setName(String)}), return the name, 567 * else return the object name provided by 568 * {@link Components#objectName(Object)}, using 569 * {@link #component()} as argument. 570 */ 571 @Override 572 public String toString() { 573 if (name != null) { 574 return name; 575 } 576 return Components.objectName(component()); 577 } 578 579 /* 580 * (non-Javadoc) 581 * 582 * @see org.jgrapes.core.Manager#registerAsGenerator() 583 */ 584 @Override 585 public void registerAsGenerator() { 586 GeneratorRegistry.instance().add(component()); 587 } 588 589 /* 590 * (non-Javadoc) 591 * 592 * @see org.jgrapes.core.Manager#unregisterAsGenerator() 593 */ 594 @Override 595 public void unregisterAsGenerator() { 596 GeneratorRegistry.instance().remove(component()); 597 } 598 599}