2 * DemosceneMusic - DataManager.java - Copyright © 2012 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.demoscenemusic.data;
20 import java.sql.ResultSet;
21 import java.sql.SQLException;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.concurrent.Callable;
26 import net.pterodactylus.util.collection.Memoizer;
27 import net.pterodactylus.util.database.Database;
28 import net.pterodactylus.util.database.DatabaseException;
29 import net.pterodactylus.util.database.Field;
30 import net.pterodactylus.util.database.Join;
31 import net.pterodactylus.util.database.Join.JoinType;
32 import net.pterodactylus.util.database.ObjectCreator;
33 import net.pterodactylus.util.database.OrderField;
34 import net.pterodactylus.util.database.Parameter.StringParameter;
35 import net.pterodactylus.util.database.Query;
36 import net.pterodactylus.util.database.Query.Type;
37 import net.pterodactylus.util.database.ValueField;
38 import net.pterodactylus.util.database.ValueFieldWhereClause;
41 * Interface between the database and the application.
43 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
45 public class DataManager {
47 /** The artist object creator. */
48 @SuppressWarnings("synthetic-access")
49 private final ObjectCreator<Artist> artistCreator = new ArtistCreator();
51 /** The group object creator. */
52 @SuppressWarnings("synthetic-access")
53 private final ObjectCreator<Group> groupCreator = new GroupCreator();
55 /** The track object creator. */
56 @SuppressWarnings("synthetic-access")
57 private final ObjectCreator<Track> trackCreator = new TrackCreator();
59 /** The style object creator. */
60 @SuppressWarnings("synthetic-access")
61 private final ObjectCreator<Style> styleCreator = new StyleCreator();
64 private final Database database;
67 * Creates a new data manager.
70 * The database to operate on
72 public DataManager(Database database) {
73 this.database = database;
77 * Returns all artists.
80 * @throws DatabaseException
81 * if a database error occurs
83 public Collection<Artist> getAllArtists() throws DatabaseException {
84 Query query = new Query(Type.SELECT, "ARTISTS");
85 query.addField(new Field("ARTISTS.*"));
86 return database.getMultiple(query, artistCreator);
90 * Returns the artist with the given ID.
93 * The ID of the artist
94 * @return The artist with the given ID, or {@code null} if there is no
95 * artist with the given ID
96 * @throws DatabaseException
97 * if a database error occurs
99 public Artist getArtistById(String id) throws DatabaseException {
100 Query query = new Query(Type.SELECT, "ARTISTS");
101 query.addField(new Field("ARTISTS.*"));
102 query.addWhereClause(new ValueFieldWhereClause(new ValueField("ARTISTS.ID", new StringParameter(id))));
103 return database.getSingle(query, artistCreator);
107 * Returns all artists that belong to the group with the given ID.
110 * The ID of the group
111 * @return All artists belonging to the given group
112 * @throws DatabaseException
113 * if a database error occurs
115 public Collection<Artist> getArtistsByGroup(String groupId) throws DatabaseException {
116 Query query = new Query(Type.SELECT, "ARTISTS");
117 query.addField(new Field("ARTISTS.*"));
118 query.addJoin(new Join(JoinType.INNER, "GROUP_ARTISTS", new Field("ARTISTS.ID"), new Field("GROUP_ARTISTS.ARTIST")));
119 query.addWhereClause(new ValueFieldWhereClause(new ValueField("GROUP_ARTISTS.GROUP_", new StringParameter(groupId))));
120 return database.getMultiple(query, artistCreator);
124 * Returns all artists involved in the track with the given ID.
127 * The ID of the track
128 * @return All artists involved in the track, in preferred order
129 * @throws DatabaseException
130 * if a database error occurs
132 public List<Artist> getArtistsByTrack(String trackId) throws DatabaseException {
133 Query query = new Query(Type.SELECT, "ARTISTS");
134 query.addField(new Field("ARTISTS.*"));
135 query.addJoin(new Join(JoinType.INNER, "TRACK_ARTISTS", new Field("TRACK_ARTISTS.ARTIST"), new Field("ARTISTS.ID")));
136 query.addWhereClause(new ValueFieldWhereClause(new ValueField("TRACK_ARTISTS.TRACK", new StringParameter(trackId))));
137 query.addOrderField(new OrderField(new Field("TRACK_ARTISTS.DISPLAY_ORDER")));
138 return database.getMultiple(query, artistCreator);
142 * Returns the track with the given ID.
145 * The ID of the track
146 * @return The track with the given ID, or {@code null} if there is no such
148 * @throws DatabaseException
149 * if a database error occurs
151 public Track getTrackById(String id) throws DatabaseException {
152 Query query = new Query(Type.SELECT, "TRACKS");
153 query.addField(new Field("TRACKS.*"));
154 query.addWhereClause(new ValueFieldWhereClause(new ValueField("TRACKS.ID", new StringParameter(id))));
155 return database.getSingle(query, trackCreator);
159 * Returns all tracks by the artist with the given ID.
162 * The ID of the artist
163 * @return All tracks by the given artist
164 * @throws DatabaseException
165 * if a database error occurs
167 public Collection<Track> getTracksByArtist(String artistId) throws DatabaseException {
168 Query query = new Query(Type.SELECT, "TRACKS");
169 query.addField(new Field("TRACKS.*"));
170 query.addJoin(new Join(JoinType.INNER, "TRACK_ARTISTS", new Field("TRACKS.ID"), new Field("TRACK_ARTISTS.TRACK")));
171 query.addWhereClause(new ValueFieldWhereClause(new ValueField("TRACK_ARTISTS.ARTIST", new StringParameter(artistId))));
172 return database.getMultiple(query, trackCreator);
176 * Returns all groups the artist with the given ID belongs to.
179 * The ID of the artist
180 * @return All groups the artist belongs to
181 * @throws DatabaseException
182 * if a database error occurs
184 public Collection<Group> getGroupsByArtist(String artistId) throws DatabaseException {
185 Query query = new Query(Type.SELECT, "GROUPS");
186 query.addField(new Field("GROUPS.*"));
187 query.addJoin(new Join(JoinType.INNER, "GROUP_ARTISTS", new Field("GROUPS.ID"), new Field("GROUP_ARTISTS.GROUP_")));
188 query.addWhereClause(new ValueFieldWhereClause(new ValueField("GROUP_ARTISTS.ARTIST", new StringParameter(artistId))));
189 return database.getMultiple(query, groupCreator);
193 * Returns all styles for the track with the given ID.
196 * The ID of the track
197 * @return All styles for the given track
198 * @throws DatabaseException
199 * if a database error occurs
201 public Collection<Style> getStylesByTrack(String trackId) throws DatabaseException {
202 Query query = new Query(Type.SELECT, "STYLES");
203 query.addField(new Field("STYLES.*"));
204 query.addJoin(new Join(JoinType.INNER, "TRACK_STYLES", new Field("STYLES.ID"), new Field("TRACK_STYLES.STYLE")));
205 query.addWhereClause(new ValueFieldWhereClause(new ValueField("TRACK_STYLES.TRACK", new StringParameter(trackId))));
206 return database.getMultiple(query, styleCreator);
210 * {@link Artist} implementation that retrieves some attributes (such as
211 * {@link #getGroups()}, and {@link #getTracks()}) from the
212 * {@link DataManager} on demand.
214 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
216 private class LazyArtist extends DefaultArtist {
218 /** Memoizer for the tracks by this artist. */
219 private final Memoizer<Void> tracksMemoizer = new Memoizer<Void>(new Callable<Void>() {
221 public Void call() throws DatabaseException {
222 if (!hasValue("tracks")) {
223 getValue("tracks", Collection.class).set(getTracksByArtist(getId()));
229 /** Memoizer for the groups of this artist. */
230 private final Memoizer<Void> groupsMemoizer = new Memoizer<Void>(new Callable<Void>() {
233 public Void call() throws Exception {
234 if (!hasValue("groups")) {
235 getValue("groups", Collection.class).set(getGroupsByArtist(getId()));
243 * Creates a new lazy artist.
246 * The ID of the artist
248 public LazyArtist(String id) {
253 // DEFAULTARTIST METHODS
260 public Collection<Group> getGroups() {
261 groupsMemoizer.get();
262 return super.getGroups();
269 public Collection<Track> getTracks() {
270 tracksMemoizer.get();
271 return super.getTracks();
277 * {@link ObjectCreator} implementation that can create {@link Artist}
278 * objects. This specific class actually creates {@link LazyArtist}
281 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
283 private class ArtistCreator implements ObjectCreator<Artist> {
289 public Artist createObject(ResultSet resultSet) throws SQLException {
290 return new LazyArtist(resultSet.getString("ARTISTS.ID")).setName(resultSet.getString("ARTISTS.NAME"));
296 * {@link Group} implementation that retrieves some attributes (such as
297 * {@link #getArtists()}) from the {@link DataManager} on demand.
299 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
301 private class LazyGroup extends DefaultGroup {
303 /** Memoizer for the artist. */
304 private final Memoizer<Void> artistsMemoizer = new Memoizer<Void>(new Callable<Void>() {
307 public Void call() throws Exception {
308 if (!hasValue("artists")) {
309 getValue("artists", Collection.class).set(getArtistsByGroup(getId()));
317 * Creates a new lazy group.
320 * The ID of the group
322 public LazyGroup(String id) {
327 // DEFAULTGROUP METHODS
334 public Collection<Artist> getArtists() {
335 artistsMemoizer.get();
336 return super.getArtists();
342 * {@link ObjectCreator} implementation that can create {@link Group}
343 * objects. This specific implementation creates {@link LazyGroup}
346 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
348 private class GroupCreator implements ObjectCreator<Group> {
354 public Group createObject(ResultSet resultSet) throws SQLException {
355 return new LazyGroup(resultSet.getString("GROUPS.ID")).setName(resultSet.getString("GROUPS.NAME")).setUrl(resultSet.getString("GROUPS.URL"));
361 * {@link Track} implementation that retrieves some attributes (such as
362 * {@link #getArtists()}, and {@link #getStyles()}) from the
363 * {@link DataManager} on demand.
365 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
367 private class LazyTrack extends DefaultTrack {
369 /** Memoizer for the artists. */
370 private final Memoizer<Void> artistsMemoizer = new Memoizer<Void>(new Callable<Void>() {
373 public Void call() throws Exception {
374 if (!hasValue("artists")) {
375 getValue("artists", List.class).set(getArtistsByTrack(getId()));
382 /** Memoizer for the styles. */
383 private final Memoizer<Void> stylesMemoizer = new Memoizer<Void>(new Callable<Void>() {
386 public Void call() throws Exception {
387 if (!hasValue("styles")) {
388 getValue("styles", Collection.class).set(getStylesByTrack(getId()));
396 * Creates a new track.
399 * The ID of the track
401 public LazyTrack(String id) {
406 // DEFAULTTRACK METHODS
413 public List<Artist> getArtists() {
414 artistsMemoizer.get();
415 return super.getArtists();
422 public Collection<Style> getStyles() {
423 stylesMemoizer.get();
424 return super.getStyles();
430 * {@link ObjectCreator} implementation that can create {@link Track}
431 * objects. This specific implementation creates {@link LazyTrack}
434 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
436 private class TrackCreator implements ObjectCreator<Track> {
442 public Track createObject(ResultSet resultSet) throws SQLException {
443 return new LazyTrack(resultSet.getString("TRACKS.ID")).setName(resultSet.getString("TRACKS.NAME"));
449 * {@link ObjectCreator} implementation that can create {@link Style}
452 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
454 private class StyleCreator implements ObjectCreator<Style> {
460 public Style createObject(ResultSet resultSet) throws SQLException {
461 return new DefaultStyle(resultSet.getString("STYLES.ID")).setName(resultSet.getString("STYLES.NAME"));