View Javadoc

1   package org.musicontroller.songselection;
2   
3   import java.util.ArrayList;
4   import java.util.HashSet;
5   import java.util.List;
6   import java.util.Set;
7   
8   import org.apache.log4j.Logger;
9   import org.musicontroller.core.Song;
10  import org.musicontroller.dao.Dao;
11  import org.varienaja.util.DenseSet;
12  import org.varienaja.util.RandomNumberGenerator;
13  
14  /**
15   * Randomly selects a preset number of songs from the song collection.
16   * 
17   * @author drexler
18   * @version $Id: RandomCandidateSelector.java,v 1.1 2010/03/16 18:55:42 varienaja Exp $
19   */
20  public class RandomCandidateSelector implements CandidateSelector {
21  	private static final Logger LOG = Logger.getLogger(RandomCandidateSelector.class);
22  	
23  	/**
24  	 * The amount of candidates to select
25  	 */
26  	private int _candidatecount;
27  	
28  	/**
29  	 * The Data access object.
30  	 */
31  	private Dao _dao;
32  	
33  	/**
34  	 * The Set of song-IDs, from which to select candidates.
35  	 */
36  	private DenseSet _songIDs;
37  	
38  	/**
39  	 * Whether or not to play requested songs in the order they were requested.
40  	 */
41  	private boolean _playRequestInOrder;
42  
43  	/**
44  	 * Default constructor sets the playRequestInOrder property to false.
45  	 */
46  	public RandomCandidateSelector() {
47  		_playRequestInOrder = false;
48  		_candidatecount = 20;
49  	}
50  	
51  	/**
52  	 * Sets the Dao and initializes the internal set of songIDs.
53  	 * @param dao The Dao.
54  	 */
55  	public void setDao(Dao dao) {
56  		_dao = dao;
57  		_songIDs = new DenseSet();
58  		initializeSongSet();
59  	}
60  	
61  	public Dao getDao() {
62  		return _dao;
63  	}
64  	
65  	/*
66  	 * (non-Javadoc)
67  	 * @see org.musicontroller.songselection.CandidateSelector#playRequestsInOrder()
68  	 */
69  	public void playRequestsInOrder() {
70  		this._playRequestInOrder = true;
71  	}
72  	
73  	/*
74  	 * (non-Javadoc)
75  	 * @see org.musicontroller.songselection.CandidateSelector#playRequestsAtRandom()
76  	 */
77  	public void playRequestsAtRandom() {
78  		this._playRequestInOrder = false;
79  	}
80  	
81  	/*
82  	 * (non-Javadoc)
83  	 * @see org.musicontroller.songselection.CandidateSelector#selectCandidates(java.util.List)
84  	 */
85  	public List<Song> selectCandidates(List<Long> requests) {
86  		List<Song> candidates = new ArrayList<Song>();
87  
88  		// Return the requested songs if there are any.
89  		if (requests!=null && requests.size()!=0) {
90  			// If the requests are to be played in order, return
91  			// only the first entry in the request set.
92  			if (requestsPlayedInOrder()) {
93  				long nextRequest = requests.remove(0);
94  				Song song = getDao().getSongById(nextRequest);
95  				if (song!=null) candidates.add(song);
96  			} else {
97  				//Order doesn't matter, so we can use the bulk-query to get all
98  				//songs.
99  				candidates.addAll(getDao().getSongsById(requests));
100 			}
101 			return candidates;
102 		}
103 		// There are no requests. Get a random selection.
104 		candidates.addAll(selectCandidates(_candidatecount-candidates.size()));
105 		return candidates;
106 	}
107 
108 	/*
109 	 * (non-Javadoc)
110 	 * @see org.musicontroller.songselection.CandidateSelector#selectCandidates(int)
111 	 */
112 	public List<Song> selectCandidates(int count) {
113 		// If there are no songs left then re-initialize the song list with all
114 		// songs. Return empty candidate set if there aren't any songs in the
115 		// database.
116 		if(_songIDs.size()<1) {
117 			initializeSongSet();
118 		}
119 		
120 		// Create a collection of ids to query from the database in one query
121 		Set<Long> ids = new HashSet<Long>();
122 		if (_songIDs.size()>count) { //We have plenty of songs in the pool, make a subselection
123 			while (ids.size() != count) {
124 				int index = RandomNumberGenerator.nextInt(_songIDs.size()); 
125 				ids.add(_songIDs.get(index));
126 			}
127 		} else { //We don't have 'count' songs, we'll just return all we have
128 			for (int i=0; i<_songIDs.size(); i++) {
129 				ids.add(_songIDs.get(i));
130 			}
131 		}
132 		return getDao().getSongsById(ids);
133 	}
134 	
135 	
136 	/*
137 	 * (non-Javadoc)
138 	 * @see org.musicontroller.songselection.CandidateSelector#removeFromCandidates(org.musicontroller.core.Song)
139 	 */
140 	public void removeFromCandidates(Song song) {
141 		if(song==null) {
142 			return;
143 		}
144 		_songIDs.remove(song.getId());
145 	}
146 
147 	/**
148 	 * Initializes the internal Song-pool. All id's of all Songs are loaded.
149 	 * These are the id's from which Songs can be selected.
150 	 */
151 	private void initializeSongSet() {
152 		LOG.debug("Reading songids from database...");
153 		for (Long l:_dao.getSongIds()) {
154 			_songIDs.add(l);
155 		}
156 		LOG.debug("Done reading songids, "+_songIDs.size()+" songs added.");
157 	}
158 
159 	/*
160 	 * (non-Javadoc)
161 	 * @see org.musicontroller.songselection.CandidateSelector#requestsPlayedAtRandom()
162 	 */
163 	public boolean requestsPlayedAtRandom() {
164 		return !_playRequestInOrder;
165 	}
166 
167 	/*
168 	 * (non-Javadoc)
169 	 * @see org.musicontroller.songselection.CandidateSelector#requestsPlayedInOrder()
170 	 */
171 	public boolean requestsPlayedInOrder() {
172 		return _playRequestInOrder;
173 	}
174 
175 	/*
176 	 * (non-Javadoc)
177 	 * @see org.musicontroller.songselection.CandidateSelector#getCandidateCount()
178 	 */
179 	public int getCandidateCount() {
180 		return _candidatecount;
181 	}
182 
183 	/**
184 	 * Setter for the number of candidates in the candidate set.
185 	 * @param candidatecount The size of the candidate set.
186 	 */
187 	public void setCandidateCount(int candidatecount) {
188 		_candidatecount = candidatecount;
189 	}
190 
191 	/*
192 	 * (non-Javadoc)
193 	 * @see org.musicontroller.songselection.CandidateSelector#addToCandidates(org.musicontroller.core.Song)
194 	 */
195 	public void addToCandidates(Song song) {
196 		_songIDs.add(song.getId());
197 	}
198 
199 }