1 /***
2 * MultiplexedProducer.java
3 *
4 * This file is part of the creme library.
5 * The creme library intends to ease the development effort of large
6 * applications by providing easy to use support classes.
7 *
8 * Copyright (C) 2002 Denis Bregeon
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * contact information: dbregeon@sourceforge.net
25 */
26 package org.jcreme.processing;
27
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
32
33 /***
34 * This class enables to multiply the output of a single producer so that it can
35 * be used in different production lines.
36 *
37 * @author $Author: dbregeon $
38 * @revision $Revision: 1.6 $
39 */
40 public class ProducerMultiplexer extends DefaultConsumer {
41 /***
42 * The multiplexed items queues. There should be one for each of the client
43 * producers.
44 */
45 private final HashMap itemsLists = new HashMap();
46
47 /***
48 * The reference counts on the consumed items so that they can be validated
49 * to the producer once they've been consumed by all the client producers.
50 */
51 private final HashMap referenceCounts = new HashMap();
52
53 /***
54 * Creates a new instance of ProducerMultiplexer
55 *
56 * @param provider
57 * the Producer that provides values.
58 */
59 public ProducerMultiplexer(Producer provider) {
60
61 super(provider);
62 }
63
64 /***
65 * Consumes a new item.
66 *
67 * @return The object produced by the consumption of a new item.
68 * @see Consumer#consumeItem
69 */
70 public Object consumeItem() {
71 synchronized (this.itemsLists) {
72 final Object theItem = super.consumeItem();
73 final Iterator iter = this.itemsLists.values().iterator();
74 List current = null;
75 int count = 0;
76 while (iter.hasNext()) {
77 current = (List) iter.next();
78 synchronized (current) {
79 current.add(theItem);
80 current.notifyAll();
81 }
82 count++;
83 }
84 if (theItem != null) {
85 this.referenceCounts.put(theItem, new Integer(count));
86 }
87 return theItem;
88 }
89 }
90
91 /***
92 * This method enables to consume the data associated to one of the
93 * Producers that are multiplexed.
94 *
95 * @param producer
96 * the producer to feed.
97 * @return the item to feed to producer.
98 */
99 public Object consumeItem(final MultiplexedProducer producer) {
100 Object result = null;
101 List current = null;
102 synchronized (this.itemsLists) {
103 current = (List) this.itemsLists.get(producer);
104 }
105 if (current != null) {
106 synchronized (current) {
107 while (current.isEmpty()) {
108 consumeItem();
109 }
110 result = current.remove(0);
111 }
112 }
113 return result;
114 }
115
116 /***
117 * @see Consumer#validateItem(Object)
118 */
119 public boolean validateItem(final Object theItem) {
120 boolean result = false;
121 synchronized (this.referenceCounts) {
122 final Integer refCount = (Integer) this.referenceCounts.get(theItem);
123 if (refCount != null) {
124 if (refCount.intValue() > 1) {
125 this.referenceCounts.put(theItem, new Integer(refCount
126 .intValue() - 1));
127 result = true;
128 } else {
129 this.referenceCounts.remove(theItem);
130 result = super.validateItem(theItem);
131 }
132 }
133 }
134 return result;
135 }
136
137 /***
138 * Provides a new MultiplexedProducer.
139 *
140 * @return a new empty MutliplexedProducer.
141 */
142 public MultiplexedProducer getMultiplexedProducer() {
143 final MultiplexedProducer newProducer = new MultiplexedProducer(0, 0, this);
144 synchronized (this.itemsLists) {
145 this.itemsLists.put(newProducer, new ArrayList());
146 }
147 return newProducer;
148 }
149
150 /***
151 * Unregisters a MultiplexedProducer from the Multiplexer.
152 *
153 * @param producer
154 * the producer to remove.
155 */
156 public void removeMultiplexedProducer(final MultiplexedProducer producer) {
157 synchronized (this.itemsLists) {
158 final Iterator iter = this.itemsLists.keySet().iterator();
159 boolean toRemove = false;
160 while ((!toRemove) && (iter.hasNext())) {
161 toRemove = (iter.next() == producer);
162 }
163 if (toRemove) {
164 final List items = (List) this.itemsLists.remove(producer);
165 if (items != null) {
166 final Iterator itemsIterator = items.iterator();
167 while (itemsIterator.hasNext()) {
168 validateItem(itemsIterator.next());
169 }
170 }
171 }
172 }
173 }
174 }