/* * Jajuk * Copyright (C) The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ package org.jajuk.services.reporting; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.base.Artist; import org.jajuk.base.ArtistManager; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.base.Item; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Year; import org.jajuk.services.core.SessionService; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; /** * This class exports music contents to XML. */ public class XMLExporter extends Exporter { /** Private Constants. */ private static final String NEWLINE = "\n"; /** The Constant XML_HEADER. */ private static final String XML_HEADER = "<?xml version='1.0' encoding='UTF-8'?>"; private final BufferedWriter writer; /** Do we want to export tracks ?*. */ private boolean showTracks = true; /** * PUBLIC METHODS. * * @throws IOException Signals that an I/O exception has occurred. */ public XMLExporter() throws IOException { cache = SessionService.getConfFileByPath(Const.FILE_REPORTING_CACHE_FILE + "_XML_" + System.currentTimeMillis()); writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(cache, false), "UTF-8")); } /** * This method will create a tagging of the specified item. * * @param item The item to report (can be an album, a year, an artist, a genre, a * directory or a device) * * @return Returns a string containing the report, or null if an error * occurred. * * @throws Exception the exception */ public void process(Item item) throws Exception { if (item instanceof Album) { process((Album) item); } else if (item instanceof Artist) { process((Artist) item); } else if (item instanceof Genre) { process((Genre) item); } else if (item instanceof Year) { process((Year) item); } else if (item instanceof Directory) { process((Directory) item); } else if (item instanceof Device) { process((Device) item); } } /** * This method will create a tagging of the specified album and its tracks. * * @param album The album to tag. * * @return Returns a string containing the tagging, or null if an error * occurred. * * @throws Exception the exception */ public void process(Album album) throws Exception { // Make sure we have an album. if (album != null) { tagAlbum(album, 0); } } /** * This method will create a reporting of the specified year and its albums * and associated tracks. * * @param year The year to report. * * @return Returns a string containing the report, or null if an error * occurred. * * @throws Exception the exception */ public void process(Year year) throws Exception { if (year != null) { tagYear(year, 0); } } /** * This method will create a tagging of the specified artist and its albums * and associated tracks. * * @param artist The artist to tag. * * @return Returns a string containing the tagging, or null if an error * occurred. * * @throws Exception the exception */ public void process(Artist artist) throws Exception { if (artist != null) { tagArtist(artist, 0); } } /** * This method will create a tagging of the specified genre. * * @param genre The genre to tag. * * @return Returns a string containing the tagging, or null is an error * occurred. * * @throws Exception the exception */ public void process(Genre genre) throws Exception { if (genre != null) { tagGenre(genre, 0); } } /** * This method will create a tagging of a directory and all its children files * and directories. * * @param directory The directory to start from. * * @return Returns a string containing the tagging, or null if an error * occurred. * * @throws Exception the exception */ public void process(Directory directory) throws Exception { if (directory != null) { tagDirectory(directory); } } /** * This method will create a tagging of a device and all its children files * and directories. * * @param device The device to start from. * * @return Returns a string containing the tagging, or null if an error * occurred. * * @throws Exception the exception */ public void process(Device device) throws Exception { if (device != null) { tagDevice(device); } } /** * Process collection. * * @param type * * @throws Exception the exception * * @see Exporter.processColllection */ @Override @SuppressWarnings("unchecked") public void processCollection(int type) throws Exception { // If we are tagging the physical collection... if (type == Exporter.PHYSICAL_COLLECTION) { // Same effect than selecting all devices process((List<Item>) DeviceManager.getInstance().getItems()); } else if (type == LOGICAL_COLLECTION) { // Same effect than selecting all genres process((List<Item>) GenreManager.getInstance().getItems()); } } /** * PRIVATE HELPER METHODS. * * @param level * @param directory * * @throws Exception the exception */ private void exportDirectoryHelper(int level, Directory directory) throws Exception { // Get the children List<Directory> children = new ArrayList<Directory>(directory.getDirectories()); writer.write(addTabs(level) + Tag.openTag(Const.XML_DIRECTORY) + NEWLINE); String sName = UtilString.formatXML(directory.getName()); String sID = UtilString.formatXML(directory.getID()); String sPath = UtilString.formatXML(directory.getAbsolutePath()); // Tag directory data. writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_ID, sID) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_NAME, sName) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_PATH, sPath) + NEWLINE); // Tag children directories for (Directory d : children) { exportDirectoryHelper(level + 1, d); } // Tag children files for (org.jajuk.base.File file : directory.getFiles()) { tagFile(file, level + 1); } writer.write(addTabs(level) + Tag.closeTag(Const.XML_DIRECTORY) + NEWLINE); } /** * Tag file. * * * @param file * @param level * * @throws Exception the exception */ private void tagFile(org.jajuk.base.File file, int level) throws Exception { String sFileID = file.getID(); String sName = UtilString.formatXML(file.getName()); String sPath = UtilString.formatXML(file.getAbsolutePath()); long lSize = file.getSize(); writer.write(addTabs(level) + Tag.openTag(Const.XML_FILE) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_ID, sFileID) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_NAME, sName) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_PATH, sPath) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_SIZE, lSize) + NEWLINE); tagTrack(file.getTrack(), level + 1); writer.write(addTabs(level) + Tag.closeTag(Const.XML_FILE) + NEWLINE); } /** * Tag directory. * * * @param directory * * @throws Exception the exception */ private void tagDirectory(Directory directory) throws Exception { // Make sure we have a directory. if (directory != null) { writer.write(Tag.openTag(Const.XML_DIRECTORY) + NEWLINE); String sName = UtilString.formatXML(directory.getName()); String sPath = UtilString.formatXML(directory.getAbsolutePath()); String sID = directory.getID(); // Tag directory data. writer.write(addTabs(1) + Tag.tagData(Const.XML_ID, sID) + NEWLINE); writer.write(addTabs(1) + Tag.tagData(Const.XML_NAME, sName) + NEWLINE); writer.write(addTabs(1) + Tag.tagData(Const.XML_PATH, sPath) + NEWLINE); // Tag directory children data. for (Directory d : new ArrayList<Directory>(directory.getDirectories())) { exportDirectoryHelper(1, d); } // Tag directory file children data. for (org.jajuk.base.File file : directory.getFiles()) { tagFile(file, 1); } writer.write(Tag.closeTag(Const.XML_DIRECTORY) + NEWLINE); } } /** * Tag device. * * * @param device * * @throws Exception the exception */ private void tagDevice(Device device) throws Exception { String sID = device.getID(); writer.write(Tag.openTag(Const.XML_DEVICE) + NEWLINE); writer.write(addTabs(1) + Tag.tagData(Const.XML_ID, sID) + NEWLINE); writer.write(addTabs(1) + Tag.tagData(Const.XML_NAME, UtilString.formatXML(device.getName())) + NEWLINE); writer.write(addTabs(1) + Tag.tagData(Const.XML_TYPE, UtilString.formatXML(device.getDeviceTypeS())) + NEWLINE); writer.write(addTabs(1) + Tag.tagData(Const.XML_URL, UtilString.formatXML(device.getUrl())) + NEWLINE); Directory dir = DirectoryManager.getInstance().getDirectoryForIO(device.getFIO(), device); // check void devices if (dir != null) { // Tag children directories of device. for (Directory directory : new ArrayList<Directory>(dir.getDirectories())) { exportDirectoryHelper(1, directory); } // Tag children files of device. for (org.jajuk.base.File file : DirectoryManager.getInstance() .getDirectoryForIO(device.getFIO(), device).getFiles()) { tagFile(file, 1); } } writer.write(Tag.closeTag(Const.XML_DEVICE) + NEWLINE); } /** * Tag track. * * * @param track * @param level * * @throws Exception the exception */ private void tagTrack(Track track, int level) throws Exception { String sTrackID = track.getID(); String sTrackName = UtilString.formatXML(track.getName()); String sTrackGenre = UtilString.formatXML(track.getGenre().getName2()); String sTrackArtist = UtilString.formatXML(track.getArtist().getName2()); String sTrackAlbum = UtilString.formatXML(track.getAlbum().getName2()); long lTrackLength = track.getDuration(); long lTrackRate = track.getRate(); String sTrackComment = UtilString.formatXML(track.getComment()); long lTrackOrder = track.getOrder(); long lTrackDiscNumber = track.getDiscNumber(); writer.write(addTabs(level) + Tag.openTag(Const.XML_TRACK) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_ID, sTrackID) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_NAME, sTrackName) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_GENRE, sTrackGenre) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_ARTIST, sTrackArtist) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_LENGTH, UtilString.formatTimeBySec(lTrackLength)) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_RATE, lTrackRate) + NEWLINE); writer .write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_COMMENT, sTrackComment) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_ORDER, UtilString.padNumber(lTrackOrder, 2)) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_ALBUM, sTrackAlbum) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_TRACK_DISC_NUMBER, UtilString.padNumber(lTrackDiscNumber, 2)) + NEWLINE); writer.write(addTabs(level) + Tag.closeTag(Const.XML_TRACK) + NEWLINE); } /** * Tag album. * * * @param album * @param level * * @throws Exception the exception */ private void tagAlbum(Album album, int level) throws Exception { String sAlbumID = album.getID(); String sAlbumName = UtilString.formatXML(album.getName2()); String sGenreName = ""; String sArtistName = ""; String sYear = ""; List<Track> tracks = TrackManager.getInstance().getAssociatedTracks(album, true); if (tracks.size() > 0) { sGenreName = UtilString.formatXML(tracks.iterator().next().getGenre().getName2()); sArtistName = UtilString.formatXML(tracks.iterator().next().getArtist().getName2()); sYear = tracks.iterator().next().getYear().getName2(); } writer.write(addTabs(level) + Tag.openTag(Const.XML_ALBUM) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_ID, sAlbumID) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_NAME, sAlbumName) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_ARTIST, sArtistName) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_GENRE, sGenreName) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_YEAR, sYear) + NEWLINE); // For full collection, we don't show detailed tracks for performance // reasons if (showTracks) { for (Track track : tracks) { tagTrack(track, level + 1); } } writer.write(addTabs(level) + Tag.closeTag(Const.XML_ALBUM) + NEWLINE); } /** * Tag artist. * * * @param artist * @param level * * @throws Exception the exception */ private void tagArtist(Artist artist, int level) throws Exception { String sArtistID = artist.getID(); String sArtistName = UtilString.formatXML(artist.getName2()); writer.write(addTabs(level) + Tag.openTag(Const.XML_ARTIST) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_ID, sArtistID) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_NAME, sArtistName) + NEWLINE); List<Album> albums = AlbumManager.getInstance().getAssociatedAlbums(artist); for (Album album : albums) { tagAlbum(album, level + 1); } writer.write(addTabs(level) + Tag.closeTag(Const.XML_ARTIST) + NEWLINE); } /** * Tag year. * * * @param year * @param level * * @throws Exception the exception */ private void tagYear(Year year, int level) throws Exception { String sYearID = year.getID(); String sYearName = year.getName(); writer.write(addTabs(level) + Tag.openTag(Const.XML_YEAR) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_ID, sYearID) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_NAME, sYearName) + NEWLINE); List<Album> albums = AlbumManager.getInstance().getAssociatedAlbums(year); for (Album album : albums) { tagAlbum(album, level + 1); } writer.write(addTabs(level) + Tag.closeTag(Const.XML_YEAR) + NEWLINE); } /** * Tag genre. * * * @param genre * @param level * * @throws Exception the exception */ private void tagGenre(Genre genre, int level) throws Exception { String sGenreID = genre.getID(); String sGenreName = UtilString.formatXML(genre.getName2()); writer.write(addTabs(level) + Tag.openTag(Const.XML_GENRE) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_ID, sGenreID) + NEWLINE); writer.write(addTabs(level + 1) + Tag.tagData(Const.XML_NAME, sGenreName) + NEWLINE); List<Album> albums = AlbumManager.getInstance().getAssociatedAlbums(genre); for (Album album : albums) { tagAlbum(album, level + 1); } List<Artist> artists = ArtistManager.getInstance().getAssociatedArtists(genre); for (Artist artist : artists) { tagArtist(artist, level + 1); } writer.write(addTabs(level) + Tag.closeTag(Const.XML_GENRE) + NEWLINE); } /** * Adds the tabs. * * * @param num * * @return the string */ private String addTabs(int num) { StringBuilder sb = new StringBuilder(); int i = 0; while (i < num) { sb.append('\t'); i++; } return sb.toString(); } /* * (non-Javadoc) * * @see org.jajuk.reporting.Exporter#process(java.util.List) */ @Override public void process(List<Item> collection) throws Exception { try { writer.write(XML_HEADER + NEWLINE + Tag.openTag(Const.XML_COLLECTION) + NEWLINE); // Sort the collection thanks a tree set (we can't use Collections.sort() // here due to generics) TreeSet<Item> ts = new TreeSet<Item>(); for (Item item : collection) { ts.add(item); } for (Item item : ts) { process(item); } // Add I18N nodes writer.write(Tag.openTag("i18n")); int i = 1; while (Messages.contains("ReportAction." + i)) { writer.write('\t' + Tag.tagData("ReportAction." + i, Messages.getString("ReportAction." + i))); i++; } writer.write('\t' + Tag.tagData("ReportAction.name", Messages.getHumanPropertyName(Const.XML_NAME))); writer.write('\t' + Tag.tagData("ReportAction.artist", Messages.getHumanPropertyName(Const.XML_ARTIST))); writer.write('\t' + Tag.tagData("ReportAction.genre", Messages.getHumanPropertyName(Const.XML_GENRE))); writer.write('\t' + Tag.tagData("ReportAction.order", Messages.getHumanPropertyName(Const.XML_TRACK_ORDER))); writer.write('\t' + Tag.tagData("ReportAction.track", Messages.getHumanPropertyName(Const.XML_TRACK))); writer.write('\t' + Tag.tagData("ReportAction.album", Messages.getHumanPropertyName(Const.XML_ALBUM))); writer.write('\t' + Tag.tagData("ReportAction.length", Messages.getHumanPropertyName(Const.XML_TRACK_LENGTH))); writer.write('\t' + Tag.tagData("ReportAction.year", Messages.getHumanPropertyName(Const.XML_YEAR))); writer.write('\t' + Tag.tagData("ReportAction.rate", Messages.getHumanPropertyName(Const.XML_TRACK_RATE))); writer.write('\t' + Tag.tagData("ReportAction.url", Messages.getHumanPropertyName(Const.XML_URL))); writer.write('\t' + Tag.tagData("ReportAction.type", Messages.getHumanPropertyName(Const.XML_TYPE))); writer.write('\t' + Tag.tagData("ReportAction.comment", Messages.getHumanPropertyName(Const.XML_TRACK_COMMENT))); writer.write(Tag.closeTag("i18n")); writer.write(Tag.closeTag(Const.XML_COLLECTION)); } finally { writer.flush(); writer.close(); } } /** * Sets the show tracks. * * @param showTracks the new show tracks */ protected void setShowTracks(boolean showTracks) { this.showTracks = showTracks; } } /** * This class will create taggings. It will create either open tags, closed * tags, or full tagging with data. */ final class Tag { /** * private constructor to avoid instantiating utility class */ private Tag() { } public static String openTag(String tagname) { return "<" + tagname + ">"; } public static String closeTag(String tagname) { return "</" + tagname + ">"; } public static String tagData(String tagname, String data) { return Tag.openTag(tagname) + data + Tag.closeTag(tagname); } public static String tagData(String tagname, long data) { return Tag.openTag(tagname) + data + Tag.closeTag(tagname); } public static String tagData(String tagname, int data) { return Tag.openTag(tagname) + data + Tag.closeTag(tagname); } public static String tagData(String tagname, double data) { return Tag.openTag(tagname) + data + Tag.closeTag(tagname); } }