/* * JFileSync * Copyright (C) 2002-2007, Jens Heidrich * * 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 * (at your option) 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301, USA */ package jfs.sync; import java.util.ArrayList; import java.util.List; import jfs.conf.JFSConfig; import jfs.conf.JFSConfigObserver; import jfs.conf.JFSSyncMode; import jfs.conf.JFSSyncModes; import jfs.conf.JFSViewMode; import jfs.conf.JFSViewModes; /** * The JFS table object administrates a flat table of all compared JFS elements and deals with the current view on this * table as well corresponding copy and delete statements neccessary in order to synchronize all table elements. During * comparison, the table is filled automatically. Before synchronization, the corresponding copy and delete statements * are computed. The class observes the configuration object. In case of changes, the object is updated accordingly. * * @see jfs.conf.JFSConfig * @see jfs.sync.JFSComparison * @see jfs.sync.JFSSynchronization * @author Jens Heidrich * @version $Id: JFSTable.java,v 1.4 2007/07/20 16:35:36 heidrich Exp $ */ public final class JFSTable implements JFSConfigObserver { /** * Stores the only instance of the class. * * SingletonHolder is loaded on the first execution of JFSTable.getInstance() * or the first access to SingletonHolder.INSTANCE, not before. */ private static class SingletonHolder { public static final JFSTable INSTANCE = new JFSTable(); } /** * The JFS root elements corresponding to the directory pairs. */ private final List<JFSRootElement> roots = new ArrayList<>(); /** * The table containing all compared elements in the right sequence. */ private final List<JFSElement> table = new ArrayList<>(); /** * The current view on the table. */ private final List<JFSElement> view = new ArrayList<>(); /** * The list of copy statements. */ private final List<JFSCopyStatement> copyStatements = new ArrayList<>(); /** * The list of delete statements. */ private final List<JFSDeleteStatement> deleteStatements = new ArrayList<>(); /** * Creates a new table object. */ protected JFSTable() { // Set default values: clean(); } /** * Returns the reference of the only instance. * * @return The only instance. */ public static JFSTable getInstance() { return SingletonHolder.INSTANCE; } /** * Restores the default values. */ public void clean() { table.clear(); view.clear(); copyStatements.clear(); deleteStatements.clear(); } /** * Returns the JFS root element at a given index. * * @param index * The index to return. * @return The element for the index. */ public JFSRootElement getRootElement(int index) { return roots.get(index); } /** * Returns the JFS element for the overall table at a given index. * * @param index * The index to return. * @return The element for the index. */ public JFSElement getTableElement(int index) { return table.get(index); } /** * Returns the JFS element for the current view at a given index. * * @param index * The index to return. * @return The element for the index. */ public JFSElement getViewElement(int index) { return view.get(index); } /** * @return Returns the number of JFS root elements. */ public int getRootsSize() { return roots.size(); } /** * @return Returns the size of the overall table. */ public int getTableSize() { return table.size(); } /** * @return Returns the size of the current view. */ public int getViewSize() { return view.size(); } /** * Adds a certain JFS element and its parent to the current view if it needs to be viewed and is not already viewed. * * @param element * The element to add. */ private void addElementToView(JFSElement element) { JFSViewMode mode = JFSViewModes.getInstance().getCurrentMode(); if (!mode.isViewed(element.getAction())||element.isViewed()) { return; } if (view.size()>0&&!element.isDirectory()) { JFSElement last = view.get(view.size()-1); if (last.getParent()!=element.getParent()&&last!=element.getParent()) { view.add(element.getParent()); element.getParent().setViewed(true); } } view.add(element); element.setViewed(true); } /** * Adds a certain JFS element and its parent to the flat table, computes the synchronization actions according to * the current synchronization mode, and adds it to the current view if it needs to be viewed according to the * current view. The table needs to be filled top town; that is, first a folder and then a contained elements (files * or more folders). * * @param element * The element to add. */ public void addElement(JFSElement element) { JFSSyncModes.getInstance().getCurrentMode().computeAction(element); table.add(element); addElementToView(element); } /** * Adds a JFS root element. * * @param element * The element to add. */ public void addRoot(JFSRootElement element) { roots.add(element); addElement(element); element.setViewed(true); } /** * Removes a certain JFS element and its parent from the current view. * * @param element * The element to remove. */ private void removeElementFromView(JFSElement element) { JFSViewMode mode = JFSViewModes.getInstance().getCurrentMode(); // Remove only, if no children are viewed any more: if (element.isViewed()&&!mode.isViewed(element.getAction())) { if (element.getChildren()!=null) { for (JFSElement child : element.getChildren()) { if (child.isViewed()&&!child.isDirectory()) { return; } } } view.remove(element); element.setViewed(false); } // Check whether parent can be removed, if no children are viewed: JFSElement parent = element.getParent(); if (!parent.isRoot()) { removeElementFromView(parent); } } /** * Removes a certain JFS element and its parent from the table and the current view. * * @param element * The element to remove. */ public void removeElement(JFSElement element) { table.remove(element); removeElementFromView(element); } /** * Updates a certain JFS element and its parent in the current view. If the element was part of the current view and * should not be viewed any more, it is removed from the view. Note, that if it was not viewed before and should be * viewed now, the view is not changed. You have to re-compute the whole view again in this case. * * @param element * The element to update. */ public void updateElement(JFSElement element) { JFSViewMode mode = JFSViewModes.getInstance().getCurrentMode(); if (!mode.isViewed(element.getAction())) { removeElementFromView(element); } } /** * @return Returns all copy statements. */ public List<JFSCopyStatement> getCopyStatements() { return copyStatements; } /** * @return Returns all delete statements. */ public List<JFSDeleteStatement> getDeleteStatements() { return deleteStatements; } /** * @return Returns all failed copy statements. */ public List<JFSCopyStatement> getFailedCopyStatements() { List<JFSCopyStatement> v = new ArrayList<>(); for (JFSCopyStatement cs : copyStatements) { if (!cs.getSuccess()&&cs.getCopyFlag()) { v.add(cs); } } return v; } /** * @return Returns all failed delete statements. */ public List<JFSDeleteStatement> getFailedDeleteStatements() { List<JFSDeleteStatement> v = new ArrayList<>(); for (JFSDeleteStatement ds : deleteStatements) { if (!ds.getSuccess()&&ds.getDeleteFlag()) { v.add(ds); } } return v; } /** * Re-computes the current view for all elements of the comparison table. */ public void recomputeView() { view.clear(); for (JFSElement element : table) { element.setViewed(false); addElementToView(element); } } /** * Re-computes all actions and the current view for all elements of the comparison table. */ public void recomputeActionsAndView() { view.clear(); JFSSyncMode mode = JFSSyncModes.getInstance().getCurrentMode(); for (JFSElement element : table) { mode.computeAction(element); element.setViewed(false); addElementToView(element); } } /** * @see JFSConfigObserver#updateConfig(JFSConfig) */ @Override public void updateConfig(JFSConfig config) { recomputeActionsAndView(); } /** * @see JFSConfigObserver#updateComparison(JFSConfig) */ @Override public void updateComparison(JFSConfig config) { // Clean the object and JFS file producers: clean(); JFSFileProducerManager.getInstance().resetProducers(); // Update config: updateConfig(config); } /** * @see JFSConfigObserver#updateServer(JFSConfig) */ @Override public void updateServer(JFSConfig config) { updateComparison(config); } }