/** * Copyright 2012-2013 Maciej Jaworski, Mariusz Kapcia, Paweł Kędzia, Mateusz Kubuszok * * <p>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</p> * * <p>http://www.apache.org/licenses/LICENSE-2.0</p> * * <p>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.</p> */ package com.autoupdater.client.environment; import static com.autoupdater.client.models.Models.addPrefixToEachLine; import static com.google.common.base.Predicates.equalTo; import static com.google.common.collect.Iterables.find; import static net.jsdpu.logger.Logger.getLogger; import java.io.IOException; import java.util.SortedSet; import java.util.TreeSet; import net.jsdpu.EOperatingSystem; import net.jsdpu.IOperatingSystem; import net.jsdpu.logger.Logger; import com.autoupdater.client.environment.settings.ClientSettings; import com.autoupdater.client.environment.settings.ProgramSettings; import com.autoupdater.client.models.Package; import com.autoupdater.client.models.Program; import com.autoupdater.client.models.ProgramBuilder; import com.autoupdater.client.models.Update; import com.google.common.base.Objects; /** * Class containing all information used by Client. It is used as a source of * information by virtually all classes that require Client's or Programs' * settings as well as information about installed Programs and Packages. * * <p> * Should be created and saved only by EnvironmentDataManager. * </p> * * @see com.autoupdater.client.environment.EnvironmentDataManager * @see com.autoupdater.client.environment.settings.ClientSettings * @see com.autoupdater.client.environment.settings.ProgramSettings * @see com.autoupdater.client.environment.AvailabilityFilter * @see com.autoupdater.client.models.Program */ public class EnvironmentData { private static final Logger logger = getLogger(EnvironmentData.class); private EnvironmentDataManager environmentDataManager; private final IOperatingSystem system; private final ClientSettings clientSettings; private final SortedSet<ProgramSettings> programsSettings; private SortedSet<Program> installationsData; private SortedSet<Program> legacyInstallationData; /** * Creates EnvironmentData instance. * * @param clientSettings * ClientSettins instance * @param programsSettings * ProgramSettings instance */ public EnvironmentData(ClientSettings clientSettings, SortedSet<ProgramSettings> programsSettings) { this.clientSettings = clientSettings; this.programsSettings = programsSettings; this.system = EOperatingSystem.currentOperatingSystem(); setInstallationsData(null); } /** * Sets EnvironmentDataManager. * * <p> * Should be used only by EnvironmentDataManager that created * EnvironmentData. * </p> * * @param environmentDataManager * parent of this object * @return this object (used for chaining) */ EnvironmentData setEnvironmentDataManager(EnvironmentDataManager environmentDataManager) { this.environmentDataManager = environmentDataManager; return this; } /** * Saves current state of EnvironmentData. * * <p> * Particularly useful when saving current state if installation data * changed (e.g. when some update was successfully installed). * </p> * * @throws IOException * thrown if some settings couldn't be saved * @throws ClientEnvironmentException * thrown if EnvironmentDataManager wasn't set in constructor, * yet setting were tried to be saved */ public void save() throws IOException, ClientEnvironmentException { if (environmentDataManager == null) { logger.error("Failed to save settings (no EnvironmentDataManager set)"); throw new ClientEnvironmentException("EnvironmentDataManager was not set"); } environmentDataManager.setEnvironmentData(this); } /** * Returns ClientSettings currently used by EnvironmentData. * * @return ClientSettings instance */ public ClientSettings getClientSettings() { return clientSettings; } /** * Returns set of ProgramSettings currently defined in EnvironmentData. * * @return ProgramSettings set */ public SortedSet<ProgramSettings> getProgramsSettings() { return programsSettings; } /** * Gets information about installations. * * <p> * Installations data contains information about all programs that are * considered updatable - which means it will contains all of Programs that * have ProgramSettings defined, and only those. * </p> * * <p> * Programs that are actually installed but doesn't have their * ProgramSettings will be ignored. * </p> * * <p> * Programs that are not installed according to installation data, but have * </p> * * @return installed programs */ public SortedSet<Program> getInstallationsData() { return installationsData; } /** * Sets set of Programs that are installed. * * <p> * Passed data will be complimented with information from ProgramsSettings. * Also all programs that do not have ProgramSettings will be removed. * </p> * * <p> * Exact copy of installationsData will be stored in * legacyInstallationsData, so that during save information about previously * installed programs that no longer have settings won't be lost. * </p> * * @see #complimentInstallationsDataWithInstalledProgramsWithSettings(SortedSet, * SortedSet) * @see #complimentInstallationsDataWithNotInstalledButDefinedBySettings(SortedSet, * SortedSet) * * @param installationsData * set of Programs installed locally */ void setInstallationsData(SortedSet<Program> installationsData) { (this.installationsData = this.installationsData == null ? new TreeSet<Program>() : this.installationsData).clear(); legacyInstallationData = (installationsData == null) ? new TreeSet<Program>() : new TreeSet<Program>(installationsData); SortedSet<Program> programsDefinedBySettings = getMockProgramsDefinedBySettings(); complimentInstallationsDataWithInstalledProgramsWithSettings(programsDefinedBySettings, legacyInstallationData); complimentInstallationsDataWithNotInstalledButDefinedBySettings(programsDefinedBySettings, legacyInstallationData); } /** * Returns information about all Programs that installed earlier. If some * Program has its settings removed it can still be found here. * * @return previously installed programs */ SortedSet<Program> getLegacyInstallationData() { return legacyInstallationData; } /** * Returns used Operating System. * * @return operating system */ public IOperatingSystem getSystem() { return system; } /** * Returns AvailabilityFilter for this EnvironmentData. * * @return AvailabilityFilter instance */ public AvailabilityFilter getAvailabilityFilter() { return new AvailabilityFilter(this); } /** * Returns list containing one ProgramSettings instance for each server. * Used for listing repositories (each server would be queried only once). * * @return list of ProgramSettings with unique server address' */ public SortedSet<ProgramSettings> getProgramsSettingsForEachServer() { SortedSet<String> alreadyFoundServers = new TreeSet<String>(); SortedSet<ProgramSettings> programsSettings = new TreeSet<ProgramSettings>(); for (ProgramSettings programSettings : this.programsSettings) { String serverAddress = programSettings.getServerAddress(); if (serverAddress != null && !alreadyFoundServers.contains(serverAddress)) { programsSettings.add(programSettings); alreadyFoundServers.add(serverAddress); } } return programsSettings; } /** * Returns ProgramSettings for Program. * * @param program * Program for which ProgramSettings will be searched * @return ProgramSettings instance * @throws ProgramSettingsNotFoundException * thrown if ProgramSettings couldn't be found */ public ProgramSettings findProgramSettingsForProgram(Program program) throws ProgramSettingsNotFoundException { if (program != null) for (ProgramSettings programSettings : programsSettings) { if (Objects.equal(programSettings.getProgramName(), program.getName()) && Objects.equal(programSettings.getPathToProgramDirectory(), program.getPathToProgramDirectory()) && Objects.equal(programSettings.getServerAddress(), program.getServerAddress())) return programSettings; } logger.warning("Attempt to get ProgramSettings for not existing Program: " + program); throw new ProgramSettingsNotFoundException("Could not find settings for program: " + program); } /** * Returns ProgramSettings for Program by Package belonging to it. * * @param _package * Package for which ProgramSettings will be searched * @return ProgramSettings instance * @throws ProgramSettingsNotFoundException * thrown if ProgramSettings couldn't be found */ public ProgramSettings findProgramSettingsForPackage(Package _package) throws ProgramSettingsNotFoundException { if (_package != null) return findProgramSettingsForProgram(_package.getProgram()); logger.warning("Attempt to get ProgramSettings for not existing Package: " + _package); throw new ProgramSettingsNotFoundException("Could not find settings for package: " + _package); } /** * Returns ProgramSettings for Program by Update belonging to it. * * @param update * Update for which ProgramSettings will be searched * @return ProgramSettings instance * @throws ProgramSettingsNotFoundException * thrown if ProgramSettings couldn't be found */ public ProgramSettings findProgramSettingsForUpdate(Update update) throws ProgramSettingsNotFoundException { if (update != null) return findProgramSettingsForPackage(update.getPackage()); logger.warning("Attempt to get ProgramSettings for not existing Update: " + update); throw new ProgramSettingsNotFoundException("Could not find settings for update: " + update); } /** * Returns set of Programs created from ProgramsSettings. Can be used both * as base of defined but not installed programs and to comparison with * actual installed programs (e.g. to check existence of such installation). * * <p> * Created mocks have filled all important fields: * <ul> * <li>program's name,</li> * <li>program's directory,</li> * <li>repository's address,</li> * <li>whether or not program is development version.</li> * </ul> * </p> * * @return set of Programs */ public SortedSet<Program> getMockProgramsDefinedBySettings() { SortedSet<Program> programsDefinedBySettings = new TreeSet<Program>(); if (programsSettings != null) for (ProgramSettings programSettings : programsSettings) programsDefinedBySettings.add(ProgramBuilder.builder() .setName(programSettings.getProgramName()) .setPathToProgramDirectory(programSettings.getPathToProgramDirectory()) .setServerAddress(programSettings.getServerAddress()) .setDevelopmentVersion(programSettings.isDevelopmentVersion()).build()); return programsDefinedBySettings; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("[EnvironmentData]").append('\n'); builder.append("[OparatingSystem]").append('\n'); builder.append(addPrefixToEachLine(system, "\t")); builder.append('\n'); builder.append("[ClientSettings]").append('\n'); builder.append(addPrefixToEachLine(clientSettings, "\t")); builder.append('\n'); builder.append("[ProgramsSettings]").append('\n'); for (ProgramSettings programSettings : programsSettings) builder.append(addPrefixToEachLine(programSettings, "\t")); builder.append('\n'); builder.append("[InstallationData]").append('\n'); for (Program program : installationsData) builder.append(addPrefixToEachLine(program, "\t")); builder.append('\n'); return builder.toString(); } /** * Compliments installation data passed into EnvironmentData with installed * Programs (according to passed parameter) that have defined settings. * * <p> * Ensures that such programs are present even if they are not installed * (they will be listed as installed with no Packages). * </p> * * <p> * Programs are also automatically filled with information about whether * they use development version. * </p> * * @see #setInstallationsData(SortedSet) * @see #complimentInstallationsDataWithNotInstalledButDefinedBySettings(SortedSet, * SortedSet) * * @param programsDefinedBySettings * set of Programs present in settings definitions * @param programsDefinedByInstallationsData * set of Programs defined in installation data */ private void complimentInstallationsDataWithInstalledProgramsWithSettings( SortedSet<Program> programsDefinedBySettings, SortedSet<Program> programsDefinedByInstallationsData) { for (Program installedProgram : programsDefinedByInstallationsData) if (programsDefinedBySettings.contains(installedProgram)) { installedProgram.setDevelopmentVersion(find(programsDefinedBySettings, equalTo(installedProgram)).isDevelopmentVersion()); this.installationsData.add(installedProgram); } } /** * Compliments installation data with Programs that are not installed * (according to passed parameters) but have defined settings (and as such * can be installed). * * <p> * Second param's Programs should have all important information defined, as * they will be used for filling gaps. * </p> * * @see #setInstallationsData(SortedSet) * @see #complimentInstallationsDataWithInstalledProgramsWithSettings(SortedSet, * SortedSet) * * @param programsDefinedBySettings * Programs defined by ProgramSettings' * @param programsDefinedByInstallationsData * Programs defined by installation data (actually installed * Programs) */ private void complimentInstallationsDataWithNotInstalledButDefinedBySettings( SortedSet<Program> programsDefinedBySettings, SortedSet<Program> programsDefinedByInstallationsData) { for (Program definedProgram : programsDefinedBySettings) if (!this.installationsData.contains(definedProgram)) this.installationsData.add(definedProgram); } }