/* * Copyright 2013 SciFY NPO <info@scify.org>. * * This product is part of the NewSum Free Software. * For more information about NewSum visit * * http://www.scify.gr/site/en/our-projects/completed-projects/newsum-menu-en * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * If this code or its output is used, extended, re-engineered, integrated, * or embedded to any extent in another software or hardware, there MUST be * an explicit attribution to this work in the resulting source code, * the packaging (where such packaging exists), or user interface * (where such an interface exists). * The attribution must be of the form "Powered by NewSum, SciFY" */ package org.scify.NewSumServer.Server.Sources; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.logging.Level; import java.util.logging.Logger; import org.scify.NewSumServer.Server.Storage.IDataStorage; import org.scify.NewSumServer.Server.Structures.User; import org.scify.NewSumServer.Server.Utils.Main; import org.scify.NewSumServer.Server.Utils.Utilities; /** * A Class describing the default Sources or for each * user specifically. * @author George K. <gkiom@scify.org> */ public class RSSSources { private static final Logger LOGGER = Main.getLogger(); /** * The Structure that maps each RSS link to its relative Category. */ private HashMap<String, String> hmRssSources = new HashMap<String, String>(); // <sLink, sCategory> /** * The Collection of the Categories */ private Collection<String> sCategories; /** * The User that maybe connected to the specified Sources */ private User uUser; /** * The string used for loading the common sources */ private final static String sGeneric = "generic"; /** * The Path to the file where the Sources (RSS feeds) are stored */ private String sPathToSources; /** * Default constructor. * @param sSourcesPath the path where the sources should be read from */ public RSSSources(String sSourcesPath) { this.sPathToSources = sSourcesPath; } /** * Initializes the RSS Sources taking into account their categories, * using a default collection of sources. * @param ids The data storage module for file IO operations */ public void initialize(IDataStorage ids) { try { LOGGER.log(Level.INFO, "Acquiring Sources From {0}", this.sPathToSources); //load sources from the text file initializeSources(); } catch (Exception ex) {//if cannot load sources from the text file, //try to load from the stored (from last session) LOGGER.log(Level.SEVERE, ex.getMessage()); if (ids.objectExists(ids.getLinksName(), sGeneric)) { //load the generic map LOGGER.log(Level.INFO, "Could not initialise Sources. Loading the generic map stored from previous runs"); this.hmRssSources = ids.readSources(sGeneric); this.sCategories = getCurrentCategories(); // save stuff saveCurrentCategories(ids, null); //save generic categories to file saveLinks(ids); saveLinkLabels(ids); saveSourceLabels(ids); } else { LOGGER.log(Level.SEVERE, "Cannot Load Sources.\nI don't know how to continue...\n\n" + "Perhaps you should try adding an NewSum.sources file under /data/Sources/, please?"); System.exit(0); } } finally { // get our beautifull categories this.sCategories = getCurrentCategories(); // save stuff saveCurrentCategories(ids, null); //save generic categories to file saveLinks(ids); // save links and labels (will be FeedSources soon) i.e. (rss.url = BBC-world) saveLinkLabels(ids); // save sources, i.e. (rss.url=in.gr) saveSourceLabels(ids); } } /** * Initializes the RSS Sources taking into account their categories, * according to each User's likings. * @param ids The data storage module for file IO operations * @param sSourcesPath The full path to the file where the sources are declared * @param uUser the user connected to the specified sources */ public RSSSources(IDataStorage ids, String sSourcesPath, User uUser) { this.sPathToSources = sSourcesPath; this.uUser = uUser; //Get the user ID String sUserID = this.uUser.getUserID(); // Check if Sources file exists for that user if (ids.objectExists(ids.getLinksName(), sUserID)) { //load it this.hmRssSources = ids.readSources(sUserID); } else { // give the guy some default sources initializeSources(); } sCategories = getCurrentCategories(); saveCurrentCategories(ids, uUser); //save user categories to file saveLinks(ids); saveLinkLabels(ids); } /** * Appends an RSS link to the link collection, unless the link already exists. * If it exists, then it is assigned a new category. * @param sURLLink a string containing the RSS link to add to the list * @param sCategory The category that this link belongs to */ public void appendRssLink(String sURLLink, String sCategory) { // If the map already contains the key, then the value is replaced this.hmRssSources.put(sURLLink, sCategory); } /** * Removes the given RSS link from the list * @param sURLLink a String containing the RSS link to be removed * @return The previous value associated with key, * or null if there was no mapping for key. */ public String removeRssLink(String sURLLink) { return this.hmRssSources.remove(sURLLink); } /** * Removes All the Links of the specified Category * @param sCategory The Category to remove. */ public void removeCategory(String sCategory) { this.hmRssSources.values().removeAll(Collections.singleton(sCategory)); } /** * * @return The map containing the RSS links of the object, each link * mapped to its category. */ public HashMap<String, String> getRssLinks() { return this.hmRssSources; } /** * Saves the Sources to file * @param ids The Data Storage framework * @param uUser The User for whom the Sources will be saved */ public void saveLinks(IDataStorage ids, User uUser) { ids.writeSources(this.hmRssSources, uUser.getUserID()); } /** * Saves the generic Sources to file * @param ids The Data Storage framework */ private void saveLinks(IDataStorage ids) { //save the generic file ids.writeSources(this.hmRssSources, sGeneric); //Save Sources File for each category for (String each: getCurrentCategories()) { HashSet<String> tmpSet = new HashSet<String>( (HashSet<String>) Utilities.getKeysByValue(this.hmRssSources, each)); ids.writeLinksByCategory(tmpSet, each); } } /** * Replaces the Sources Map with the saved one, for the specified user * @param ids The Data Storage framework * @param uUser The User from whom the file will be loaded. If null, the * generic Sources will be loaded */ public void loadLinks(IDataStorage ids, User uUser) { this.hmRssSources = (uUser != null) ? ids.readSources(uUser.getUserID()) : ids.readSources(sGeneric); } /** * Updates the Sources Map with the ones loaded from the file * @param ids The Data Storage framework * @param uUser The User from who's file the links will be loaded. * If null, the generic Sources will be loaded */ public void updateAllLinks(IDataStorage ids, User uUser) { HashMap<String, String> hmNewRssSources = (uUser != null) ? ids.readSources(uUser.getUserID()) : ids.readSources(sGeneric); this.hmRssSources.putAll(hmNewRssSources); } /** * * @return the Sources that the program uses */ public HashMap<String, String> getRssSources() { return this.hmRssSources; } /** * * @return The Categories */ public Collection<String> getCategories() { return this.sCategories; } /** * Use this method to get the Categories if the map already exists. * @return A collection of the categories as string */ private Collection<String> getCurrentCategories() { // Get a collection of Categories, eliminating Duplicates Collection<String> cCategories = new HashSet<String>(this.hmRssSources.values()); this.sCategories = cCategories; return this.sCategories; } /** * Save the User categories to file. If user is null, saves the * generic categories. * @param ids The Data storage module * @param uUser The user for whom the categories are about. */ private void saveCurrentCategories(IDataStorage ids, User uUser) { if (uUser == null) { ids.writeCategories(this.sCategories, sGeneric); } else { ids.writeCategories(this.sCategories, uUser.getUserID()); } } /** * Reads the provided sources file and updates the {@link #hmRssSources} * map accordingly. */ private void initializeSources() { if (!this.hmRssSources.isEmpty()) { this.hmRssSources.clear(); } try { this.hmRssSources = Utilities.getSourcesFromFile(this.sPathToSources); } catch (FileNotFoundException ex) { LOGGER.log(Level.SEVERE, "File not found ", ex.getMessage()); } catch (IOException ex) { LOGGER.log(Level.SEVERE, "IO Error ", ex.getMessage()); } } /** * Reads the specified sources file, and saves the (URL, label) * map using the storage module provided. * @param ids The storage module */ private void saveLinkLabels(IDataStorage ids) { try { HashMap<String, String> hsLinkLabels = Utilities.getLinkLabelsFromFile(this.sPathToSources); if (ids.objectExists("LinkLabels", "generic")) { ids.deleteObject("LinkLabels", "generic"); } ids.SaveObject(hsLinkLabels, "LinkLabels", "generic"); } catch (FileNotFoundException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } catch (IOException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } } /** * Reads the specified sources file, and saves the (URL, SourceLabel) * map using the storage module provided. * @param ids The storage module */ private void saveSourceLabels(IDataStorage ids) { try { HashMap<String, String> hsSourceLabels = Utilities.getSourceLabelsFromFile(this.sPathToSources); if (ids.objectExists("SourceLabels", "generic")) { ids.deleteObject("SourceLabels", "generic"); } ids.SaveObject(hsSourceLabels, "SourceLabels", "generic"); } catch (FileNotFoundException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } catch (IOException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } } }