View Javadoc

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  		// Simply call super.
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 }