1 package org.metricshub.jawk.jrt;
2
3 /*-
4 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5 * Jawk
6 * ჻჻჻჻჻჻
7 * Copyright (C) 2006 - 2025 MetricsHub
8 * ჻჻჻჻჻჻
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program. If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23 */
24
25 import java.util.HashSet;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Set;
29 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
30
31 /**
32 * An item which blocks until something useful can be
33 * done with the object. The BlockManager multiplexes
34 * BlockObjects such that unblocking one
35 * BlockObject causes the BlockManager to dispatch
36 * the notifier tag result of the BlockObject.
37 * <p>
38 * BlockObjects are chained. The BlockManager
39 * blocks on all chained BlockObjects until one
40 * is unblocked.
41 * <p>
42 * Subclasses must provide meaningful block()
43 * and getNotifierTag() routines.
44 * <p>
45 * BlockObjects do not actually perform the client
46 * blocking. This is done by the BlockManager at the
47 * AVM (interpreted) or compiled runtime environment.
48 * The AVM/compiled environments make special provision
49 * to return the head block object to the BlockManager
50 * (within _EXTENSION_ keyword processing).
51 *
52 * @see BlockManager
53 * @author Danny Daglas
54 */
55 public abstract class BlockObject {
56
57 private BlockObject nextBlockObject = null;
58
59 /**
60 * <p>
61 * Constructor for BlockObject.
62 * </p>
63 */
64 protected BlockObject() {}
65
66 /**
67 * Construct a meaningful notifier tag for this BlockObject.
68 *
69 * @return a {@link java.lang.String} object
70 */
71 public abstract String getNotifierTag();
72
73 /**
74 * Block until meaningful data is made available for
75 * the client application. This is called by the BlockManager
76 * in a way such that the BlockManager waits for one
77 * BlockObject to unblock.
78 *
79 * @throws java.lang.InterruptedException if any.
80 */
81 public abstract void block() throws InterruptedException;
82
83 /**
84 * Eliminate the rest of the BlockObject chain.
85 */
86 public final void clearNextBlockObject() {
87 this.nextBlockObject = null;
88 }
89
90 /**
91 * Chain this BlockObject to another BlockObject.
92 * The chain is linear and there is no upper bounds on
93 * the number of BlockObjects that can be supported.
94 *
95 * @param bo a {@link org.metricshub.jawk.jrt.BlockObject} object
96 */
97 @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "Block chain uses direct references between block objects")
98 public void setNextBlockObject(BlockObject bo) {
99 this.nextBlockObject = bo;
100 }
101
102 /**
103 * <p>
104 * Getter for the field <code>nextBlockObject</code>.
105 * </p>
106 *
107 * @return a {@link org.metricshub.jawk.jrt.BlockObject} object
108 */
109 protected final BlockObject getNextBlockObject() {
110 return nextBlockObject;
111 }
112
113 /**
114 * Obtain all chained BlockObjects as a List,
115 * including this one.
116 * A BlockObject chain cycle causes a runtime exception
117 * to be thrown.
118 *
119 * @return A List of chained BlockObjects, including
120 * this one.
121 * @throws org.metricshub.jawk.jrt.AwkRuntimeException if the BlockObject
122 * chain contains a cycle.
123 */
124 public List<BlockObject> getBlockObjects() {
125 List<BlockObject> retval = new LinkedList<BlockObject>();
126 Set<BlockObject> blockObjects = new HashSet<BlockObject>();
127 BlockObject ref = this;
128 while (ref != null) {
129 if (blockObjects.contains(ref)) {
130 throw new AwkRuntimeException(
131 "Block chain contains a cycle (duplicate) : " + ref.getClass().getName() + " / " + ref.getNotifierTag());
132 } else {
133 blockObjects.add(ref);
134 }
135 retval.add(ref);
136 ref = ref.getNextBlockObject();
137 }
138 return retval;
139 }
140
141 /**
142 * {@inheritDoc}
143 * Ensure non-evaluation of a BlockObject by throwing an AWK Runtime
144 * exception, in case it leaks into AWK evaluation space.
145 */
146 @Override
147 public final String toString() {
148 throw new AwkRuntimeException("Extension Violation : Cannot AWK-evaluate a BlockObject.");
149 }
150 }