/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.fps; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Vector; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.netbeans.lib.cvsclient.admin.Entry; import org.netbeans.lib.cvsclient.admin.StandardAdminHandler; import org.netbeans.lib.cvsclient.command.CommandAbortedException; import org.netbeans.lib.cvsclient.command.CommandException; import org.netbeans.lib.cvsclient.command.GlobalOptions; import org.netbeans.lib.cvsclient.command.checkout.CheckoutCommand; import org.netbeans.lib.cvsclient.command.importcmd.ImportCommand; import org.netbeans.lib.cvsclient.command.status.StatusCommand; import org.netbeans.lib.cvsclient.command.update.UpdateCommand; import org.netbeans.lib.cvsclient.connection.AuthenticationException; import org.netbeans.lib.cvsclient.event.CVSAdapter; import org.netbeans.lib.cvsclient.event.FileInfoEvent; import org.netbeans.lib.cvsclient.util.DefaultIgnoreFileFilter; import org.netbeans.lib.cvsclient.util.IgnoreFileFilter; import org.openflexo.foundation.FlexoEditor; import org.openflexo.foundation.Inspectors; import org.openflexo.foundation.utils.FlexoProgress; import org.openflexo.foundation.xml.FlexoXMLMappings; import org.openflexo.fps.CVSFile.RevisionRetrieverListener; import org.openflexo.fps.action.CommitFiles; import org.openflexo.fps.dm.CVSStatusChanged; import org.openflexo.fps.dm.CVSStructureUpdated; import org.openflexo.localization.FlexoLocalization; import org.openflexo.toolbox.FileUtils; import org.openflexo.toolbox.FlexoRunnable; public class SharedProject extends CVSAbstractFile implements CVSContainer { private static final Logger logger = Logger.getLogger(SharedProject.class.getPackage().getName()); private static final int THREAD_POOL_SIZE = 10; private CVSRepository _cvsRepository; private CVSModule _module; private File _localDirectory; private String _localName; private FlexoXMLMappings _mappings; // used by xml diff algo // private GlobalOptions _globalOptions; private StandardAdminHandler _adminHandler; private CVSConsole _consoleHandler; private CVSListener _cvsHandler; private ThreadPoolExecutor connectionThreadPool; private SharedProject(CVSRepository cvsRepository, CVSModule module, File localDirectory, final String localName) { super(new File(localDirectory, localName), null); _sharedProject = this; _directories = new Vector<CVSDirectory>(); _files = new Vector<CVSFile>(); _cvsRepository = cvsRepository; _module = module; _localDirectory = localDirectory; _localName = localName; // _globalOptions = new GlobalOptions(); _adminHandler = new StandardAdminHandler(); _consoleHandler = CVSConsole.getCVSConsole(); _cvsHandler = new CVSListener(this); connectionThreadPool = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() { private int threadCount = 0; @Override public Thread newThread(Runnable r) { threadCount++; Thread t = null; if (r instanceof FlexoRunnable) { t = new Thread(r, ((FlexoRunnable) r).getName()); } else { t = new Thread(r, "Thread-" + threadCount + " in pool for " + localName); } if (t.isDaemon()) { t.setDaemon(false); } if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); } return t; } }); } public File getModuleDirectory() { return getFile(); } public static final transient String CVS_REPOSITORY_LOCATION_FILE = ".cvsrepository"; /** * Create an instance of SharedProject by checkouting a CVSModule * * @param cvsRepository * @param module * @param localDirectory * @param localName * @return * @throws IOException * @throws CommandException * @throws AuthenticationException */ public static SharedProject checkoutProject(CVSRepository cvsRepository, CVSModule module, File localDirectory, String localName, CVSAdapter listener) throws IOException, CommandException, AuthenticationException { SharedProject returned = new SharedProject(cvsRepository, module, localDirectory, localName); CVSConnection connection = returned.openConnection(); connection.getClient().getEventManager().addCVSListener(listener); CheckoutCommand command = new CheckoutCommand(); command.setModule(module.getFullQualifiedModuleName()); command.setCheckoutDirectory(localName/*returned.getModuleDirectory().getCanonicalPath()*/); try { connection.executeCommand(command); } catch (CommandAbortedException e) { throw e; } catch (CommandException e) { throw e; } catch (AuthenticationException e) { throw e; } /*if (module.isSubModule()) { // We have here to handle move File targetDirectory = new File(localDirectory,module.getModuleName()); File checkoutDirectory = new File(localDirectory,module.getFullQualifiedModuleName()); logger.info("Rename from "+checkoutDirectory+" to "+targetDirectory); if (!checkoutDirectory.renameTo(targetDirectory)) { logger.warning("Could to rename from "+checkoutDirectory+" to "+targetDirectory); } File originalCheckoutDirectory = (new File(localDirectory,module.getFullQualifiedModuleName())).getParentFile(); logger.info("Delete "+originalCheckoutDirectory); if (!FileUtils.recursiveDeleteFile(originalCheckoutDirectory)) { logger.warning("Could to delete "+originalCheckoutDirectory); } }*/ File cvsRepositoryFile = new File(returned.getModuleDirectory(), CVS_REPOSITORY_LOCATION_FILE); cvsRepository.saveCVSRepositoryLocation(cvsRepositoryFile); logger.info("Checkout project DONE"); returned.rebuildStructureFromFS(); return returned; } public static SharedProject openProject(CVSRepositoryList repositoryList, File projectDirectory, CVSRepository repository, FlexoEditor editor) { if (projectDirectory == null || !projectDirectory.exists()) { return null; } boolean isFound = false; for (CVSRepository rep : repositoryList.getCVSRepositories()) { if (rep.equals(repository)) { isFound = true; repository = rep; } } if (!isFound) { repositoryList.addToCVSRepositories(repository); repository.getCVSExplorer(null).explore(); // SwingUtilities.invokeLater(new CVSRepositoryList.RetrieveModuleRunnable(repository,editor)); } CVSModule module = null; ; File cvsRepFile = new File(projectDirectory, "CVS/Repository"); if (cvsRepFile.exists()) { String moduleName; try { moduleName = FileUtils.fileContents(cvsRepFile).trim(); module = repository.getModuleNamed(moduleName); } catch (IOException e) { e.printStackTrace(); } } if (module == null) { logger.warning("Could not find " + cvsRepFile.getAbsolutePath()); module = repository.getModuleNamed(projectDirectory.getName()); } SharedProject returned = new SharedProject(repository, module, projectDirectory.getParentFile(), projectDirectory.getName()); returned.rebuildStructureFromFS(); logger.info("Open project DONE"); File cvsRepositoryFile = new File(returned.getModuleDirectory(), CVS_REPOSITORY_LOCATION_FILE); repository.saveCVSRepositoryLocation(cvsRepositoryFile); return returned; } public static SharedProject openProject(CVSRepositoryList repositoryList, File projectDirectory, FlexoEditor editor) { if (projectDirectory == null || !projectDirectory.exists()) { return null; } File cvsRepositoryLocation = new File(projectDirectory, SharedProject.CVS_REPOSITORY_LOCATION_FILE); CVSRepository relatedCVSRepository = new CVSRepository(cvsRepositoryLocation); return openProject(repositoryList, projectDirectory, relatedCVSRepository, editor); } public static SharedProject shareProject(CVSRepositoryList repositoryList, File projectDirectory, CVSRepository repository, String moduleName, // Full qualified String vendorTag, String releaseTag, String logMessage, FlexoEditor editor) throws IOException, CommandException, AuthenticationException { if (projectDirectory == null || !projectDirectory.exists()) { return null; } long start = System.currentTimeMillis(); boolean isFound = false; for (CVSRepository rep : repositoryList.getCVSRepositories()) { if (rep.equals(repository)) { isFound = true; repository = rep; } } if (!isFound) { repositoryList.addToCVSRepositories(repository); repository.getCVSExplorer(null).explore(); } // CVSModule module = repository.getModuleNamed(projectDirectory.getName()); logger.info("Module name: " + moduleName); CVSModule module = repository.getModuleNamed(moduleName); logger.info("Module: " + module.getModuleName() + " " + module.getFullQualifiedModuleName()); SharedProject returned = new SharedProject(repository, module, projectDirectory.getParentFile(), projectDirectory.getName()); CVSConnection connection = returned.openConnection(); ImportCommand command = new ImportCommand(); command.setModule(module.getFullQualifiedModuleName()); command.setLogMessage(logMessage); command.setVendorTag(vendorTag); command.setReleaseTag(releaseTag); for (String binaryFilePattern : CVSConstants.binaryFilesPatterns) { command.addIgnoredFile(binaryFilePattern); } connection.getClient().setLocalPath(projectDirectory.getCanonicalPath()); try { connection.executeCommand(command); } catch (CommandAbortedException e) { throw e; } catch (CommandException e) { throw e; } catch (AuthenticationException e) { throw e; } // Now, do a checkout in a temp directory in order to get CVS tree // Create an empty temporary folder File aTempFile = File.createTempFile("TemporaryCheckout", "").getCanonicalFile(); String aTempFileName = aTempFile.getAbsolutePath(); aTempFile.delete(); File aTempDir = new File(aTempFileName); aTempDir.mkdir(); CVSConnection coConnection = returned.openConnection(); CheckoutCommand coCommand = new CheckoutCommand(); coCommand.setModule(module.getFullQualifiedModuleName()); coConnection.getClient().setLocalPath(aTempDir.getAbsolutePath()); try { // No need to notify file adding (temporary folder) returned.getCVSHandler().disableFileAddingNotification(); coConnection.executeCommand(coCommand); returned.getCVSHandler().enableFileAddingNotification(); } catch (CommandAbortedException e) { throw e; } catch (CommandException e) { throw e; } catch (AuthenticationException e) { throw e; } // And copy CVS folders to initial copyCVSFolders(new File(aTempDir, module.getFullQualifiedModuleName()), returned.getModuleDirectory()); // Dont forget to delete temp checkout FileUtils.recursiveDeleteFile(aTempDir); returned.rebuildStructureFromFS(); File cvsRepositoryFile = new File(returned.getModuleDirectory(), CVS_REPOSITORY_LOCATION_FILE); repository.saveCVSRepositoryLocation(cvsRepositoryFile); logger.info("Now lets handle binary files"); Vector<FPSObject> binaryFiles = new Vector<FPSObject>(); for (CVSFile f : returned.getAllCVSFiles()) { if (f.isBinary()) { binaryFiles.add(f); } } if (binaryFiles.size() > 0) { CommitFiles commitBinaryFiles = CommitFiles.actionType.makeNewAction(null, binaryFiles, editor); commitBinaryFiles.setCommitMessage(logMessage); commitBinaryFiles.doAction(); } long end = System.currentTimeMillis(); logger.info("Project sharing DONE in " + (end - start) / 1000 + " seconds."); return returned; } public void shutdownThreadPool() { if (connectionThreadPool != null) { if (!connectionThreadPool.isShutdown()) { connectionThreadPool.shutdownNow(); } connectionThreadPool = null; } } @Override protected void finalize() throws Throwable { shutdownThreadPool(); super.finalize(); } public static void copyCVSFolders(File source, File destination) { // logger.info("copyCVSFolders() from "+source.getAbsolutePath()+" to "+destination.getAbsolutePath()); File sourceCVSDir = new File(source, "CVS"); if (sourceCVSDir.exists()) { File destCVSDir = new File(destination, "CVS"); try { FileUtils.copyContentDirToDir(sourceCVSDir, destCVSDir); } catch (IOException e) { logger.warning("Unexpected IOException: " + e.getMessage()); e.printStackTrace(); } } File[] allFiles = source.listFiles(new CVSNotIgnoredFileFilter(source)); if (allFiles == null) { if (logger.isLoggable(Level.SEVERE)) { logger.severe("listFiles() returned null for path: " + source.getAbsolutePath()); } if (logger.isLoggable(Level.INFO)) { logger.info("source exists? " + source.exists() + "\n" + "source is file? " + source.isFile() + "\n" + "source is directory? " + source.isDirectory()); } } else { for (File f : allFiles) { if (f.isDirectory()) { copyCVSFolders(f, new File(destination, f.getName())); } } } } protected CVSConnection openConnection() throws IOException { return CVSConnection.initCVSConnection(this); } public CVSRepository getCVSRepository() { return _cvsRepository; } public void setCVSRepository(CVSRepository cvsRepository) { _cvsRepository = cvsRepository; } /*public GlobalOptions getGlobalOptions() { return _globalOptions; }*/ public File getLocalDirectory() { return _localDirectory; } public void setLocalDirectory(File localDirectory) { _localDirectory = localDirectory; } public String getLocalName() { return _localName; } public CVSModule getCVSModule() { return _module; } public void setCVSModule(CVSModule module) { _module = module; } public StandardAdminHandler getAdminHandler() { return _adminHandler; } public CVSConsole getConsoleHandler() { return _consoleHandler; } public CVSListener getCVSHandler() { return _cvsHandler; } @Override public String getInspectorName() { return Inspectors.FPS.SHARED_PROJECT_INSPECTOR; } @Override public String getClassNameKey() { return "shared_project"; } private void rebuildStructureFromFS() { clear(); try { rebuildStructureFor(this, getModuleDirectory()); } catch (IOException e) { e.printStackTrace(); logger.warning("Error while building CVS structure: " + e.getMessage()); } // Check for changes in local version checkModifiedFiles(this, getModuleDirectory()); checkNewFilesAndDirectories(this, getModuleDirectory()); checkDeletedFiles(this, getModuleDirectory()); checkIgnoredFiles(this, getModuleDirectory()); } private void rebuildStructureFor(CVSContainer container, File directory) throws IOException { Iterator allEntries = getAdminHandler().getEntries(directory); // logger.info("Rebuild structure for "+directory.getAbsolutePath()+" for "+container); for (Iterator it = allEntries; it.hasNext();) { Entry entry = (Entry) it.next(); // logger.info("Entry: "+entry.toString()); File file = new File(directory, entry.getName()); if (entry.isDirectory()) { CVSDirectory newDirectory = new CVSDirectory(file, entry, this); container.addToDirectories(newDirectory); rebuildStructureFor(newDirectory, file); } else { CVSFile newFile = new CVSFile(file, entry, this); container.addToFiles(newFile); } } setChanged(); notifyObservers(new CVSStructureUpdated(this)); } private Vector<CVSDirectory> _directories; @Override public Vector<CVSDirectory> getDirectories() { return _directories; } @Override public void setDirectories(Vector<CVSDirectory> directories) { _directories = directories; } @Override public void addToDirectories(CVSDirectory aDirectory) { _directories.add(aDirectory); aDirectory.setContainer(this); } @Override public void removeFromDirectories(CVSDirectory aDirectory) { _directories.remove(aDirectory); aDirectory.setContainer(null); } private Vector<CVSFile> _files; @Override public Vector<CVSFile> getFiles() { return _files; } @Override public void setFiles(Vector<CVSFile> files) { _files = files; } @Override public void addToFiles(CVSFile aFile) { _files.add(aFile); aFile.setContainer(this); } @Override public void removeFromFiles(CVSFile aFile) { _files.remove(aFile); aFile.setContainer(null); } public Vector<CVSFile> getAllCVSFiles() { Vector<CVSFile> returned = new Vector<CVSFile>(); appendAllCVSFiles(returned, this); return returned; } private void appendAllCVSFiles(Vector<CVSFile> files, CVSContainer container) { for (CVSFile f : container.getFiles()) { files.add(f); } for (CVSDirectory d : container.getDirectories()) { appendAllCVSFiles(files, d); } } @Override public boolean isRegistered(File aFile) { for (CVSFile f : getFiles()) { if (f.getFile().equals(aFile)) { return true; } } for (CVSDirectory d : getDirectories()) { if (d.getFile().equals(aFile)) { return true; } } return false; } public void clear() { // TODO remove properly (think about observers) for (CVSDirectory d : getDirectories()) { d.clear(); } conflictingFiles.clear(); _directories.clear(); _files.clear(); locallyModifiedCount = 0; remotelyModifiedCount = 0; conflictsCount = 0; } private static class CVSNotIgnoredFileFilter implements FileFilter { private File _directory; private IgnoreFileFilter ignoreFileFilter = new DefaultIgnoreFileFilter(); private CVSNotIgnoredFileFilter(File directory) { _directory = directory; } @Override public boolean accept(File file) { if (file.getName().equals("CVS")) { return false; } if (file.getName().equals(CVS_REPOSITORY_LOCATION_FILE)) { return false; } return !ignoreFileFilter.shouldBeIgnored(_directory, file.getName()); } } private static class CVSIgnoredFileFilter implements FileFilter { private File _directory; private IgnoreFileFilter ignoreFileFilter = new DefaultIgnoreFileFilter(); private CVSIgnoredFileFilter(File directory) { _directory = directory; } @Override public boolean accept(File file) { if (!file.isFile()) { return false; } return ignoreFileFilter.shouldBeIgnored(_directory, file.getName()); } } private static void checkNewFilesAndDirectories(CVSContainer container, final File directory) { if (logger.isLoggable(Level.FINE)) { logger.fine("checkNewFilesAndDirectories() for " + directory.getAbsolutePath() + " for " + container); } File[] allUnignoredFiles = directory.listFiles(new CVSNotIgnoredFileFilter(directory)); for (File f : allUnignoredFiles) { if (!container.isRegistered(f)) { if (f.isDirectory()) { CVSDirectory newDir = new CVSDirectory(f, container.getSharedProject()); container.addToDirectories(newDir); } else { CVSFile newFile = new CVSFile(f, container.getSharedProject()); container.addToFiles(newFile); newFile.setStatus(CVSStatus.LocallyAdded); } } } for (File f : directory.listFiles(new CVSNotIgnoredFileFilter(directory))) { if (f.isDirectory()) { CVSDirectory cvsDir = (CVSDirectory) container.getCVSAbstractFile(f); if (cvsDir == null) { logger.warning("Cannot find cvs dir " + f); } else { checkNewFilesAndDirectories(cvsDir, f); } } } } private static void checkDeletedFiles(CVSContainer container, final File directory) { // logger.info("checkDeletedFiles() for "+directory.getAbsolutePath()+" for "+container); for (CVSFile f : container.getFiles()) { if (!f.getFile().exists()) { f.setStatus(CVSStatus.LocallyRemoved); } } for (CVSDirectory d : container.getDirectories()) { checkDeletedFiles(d, d.getFile()); } } private static void checkModifiedFiles(CVSContainer container, final File directory) { // logger.info("checkModifiedFiles "+directory.getAbsolutePath()); for (CVSFile f : container.getFiles()) { f.checkLocallyModified(); } for (CVSDirectory d : container.getDirectories()) { checkModifiedFiles(d, d.getFile()); } } private static void checkIgnoredFiles(CVSContainer container, final File directory) { // logger.info("checkNewFilesAndDirectories() for "+directory.getAbsolutePath()+" for "+container); File[] allIgnoredFiles = directory.listFiles(new CVSIgnoredFileFilter(directory)); for (File f : allIgnoredFiles) { if (!container.isRegistered(f)) { CVSFile newFile = new CVSFile(f, container.getSharedProject()); newFile.setStatus(CVSStatus.CVSIgnored); container.addToFiles(newFile); } } for (File f : directory.listFiles(new CVSNotIgnoredFileFilter(directory))) { if (f.isDirectory()) { CVSDirectory cvsDir = (CVSDirectory) container.getCVSAbstractFile(f); if (cvsDir == null) { logger.warning("Cannot find cvs dir " + f); } else { checkIgnoredFiles(cvsDir, f); } } } } public void refresh() { rebuildStructureFromFS(); } public void synchronizeWithRepository() { synchronizeWithRepository(null); } private boolean _isSynchronizing = false; protected boolean isSynchronizing() { return _isSynchronizing; } public void synchronizeWithRepository(final FlexoProgress progress) { if (logger.isLoggable(Level.FINE)) { logger.fine("Synchronize with repository " + getModuleDirectory().getAbsolutePath()); } if (progress != null) { progress.setProgress(FlexoLocalization.localizedForKey("check_changes_on_local_file_system")); } rebuildStructureFromFS(); // Check for changes in remote location _isSynchronizing = true; if (progress != null) { progress.setProgress(FlexoLocalization.localizedForKey("check_changes_on_cvs_repository")); progress.resetSecondaryProgress(getAllCVSFiles().size()); } getCVSHandler().setReceiveRemoteUpdateRequest(true); if (logger.isLoggable(Level.FINE)) { logger.fine("[" + Thread.currentThread().getName() + "] Perform update command"); } UpdateCommand updateCommand = new UpdateCommand(); updateCommand.setRecursive(true); File[] moduleDir = new File[1]; moduleDir[0] = getModuleDirectory(); updateCommand.setFiles(moduleDir); GlobalOptions options = new GlobalOptions(); options.setDoNoChanges(true); // no changes on files '-n' try { CVSConnection connection = openConnection(); connection.getClient().getEventManager().addCVSListener(new CVSAdapter() { @Override public void fileInfoGenerated(FileInfoEvent e) { if (progress != null) { progress.setSecondaryProgress(FlexoLocalization.localizedForKey("received_info_for") + " " + e.getInfoContainer().getFile().getName()); } if (logger.isLoggable(Level.FINER)) { logger.finer("[" + Thread.currentThread().getName() + "] synchronizeWithRepository: Received update info for file " + e.getInfoContainer().getFile() + " " + e.getInfoContainer().getClass().getSimpleName()); } } }); connection.executeCommand(updateCommand, options); } catch (CommandAbortedException e) { e.printStackTrace(); } catch (CommandException e) { e.printStackTrace(); } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } getCVSHandler().setReceiveRemoteUpdateRequest(false); // Finally perform a status command if (logger.isLoggable(Level.FINE)) { logger.fine("[" + Thread.currentThread().getName() + "] Now perform a status command"); } if (progress != null) { progress.setProgress(FlexoLocalization.localizedForKey("retrieving_status")); progress.resetSecondaryProgress(getAllCVSFiles().size()); // logger.info("Files nb="+getAllCVSFiles().size()); } StatusCommand statusCommand = new StatusCommand(); // statusCommand.setRecursive(true); try { CVSConnection connection = openConnection(); connection.getClient().setLocalPath(getModuleDirectory().getAbsolutePath()); connection.getClient().getEventManager().addCVSListener(new CVSAdapter() { @Override public void fileInfoGenerated(FileInfoEvent e) { if (logger.isLoggable(Level.FINER)) { logger.finer("[" + Thread.currentThread().getName() + "] synchronizeWithRepository: Received status for file " + e.getInfoContainer().getFile() + " " + e.getInfoContainer().getClass().getSimpleName()); } if (progress != null) { progress.setSecondaryProgress(FlexoLocalization.localizedForKey("received_status_info_for") + " " + e.getInfoContainer().getFile().getName()); } } }); connection.executeCommand(statusCommand); } catch (CommandAbortedException e) { e.printStackTrace(); } catch (CommandException e) { e.printStackTrace(); } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (logger.isLoggable(Level.FINE)) { logger.fine("[" + Thread.currentThread().getName() + "] Now retrieve all necessary versions to compute merges"); } _isSynchronizing = false; // Now retrieve all necessary versions to compute merges int conflictingFileNumber = 0; for (CVSFile f : getAllCVSFiles()) { if (f.getStatus().isConflicting()) { conflictingFileNumber++; } } if (conflictingFileNumber > 0) { if (progress != null) { progress.setProgress(FlexoLocalization.localizedForKey("retrieving_remote_versions_for_conflicting_files")); progress.resetSecondaryProgress(conflictingFileNumber * 2); } originalContentRevisionRetrieverListener = new ContentRevisionRetrieverListener(progress); contentOnRepositoryRevisionRetrieverListener = new ContentRevisionRetrieverListener(progress); for (CVSFile f : getAllCVSFiles()) { if (f.getStatus().isConflicting()) { if (logger.isLoggable(Level.FINER)) { logger.finer("[" + Thread.currentThread().getName() + "] Start obtaining necessary revisions for " + f.getFileName()); } f.getContentOnDisk(); originalContentRevisionRetrieverListener.addFileToWait(f); contentOnRepositoryRevisionRetrieverListener.addFileToWait(f); f.getOriginalContent(originalContentRevisionRetrieverListener); f.getContentOnRepository(contentOnRepositoryRevisionRetrieverListener); } } waitRevisionRetrievingResponses(progress); } setChanged(); notifyObservers(new CVSStructureUpdated(this)); if (logger.isLoggable(Level.FINE)) { logger.fine("[" + Thread.currentThread().getName() + "] Synchronize with repository DONE"); } } protected Map<CVSFile, CVSRevisionIdentifier> filesToNotify = Collections .synchronizedMap(new HashMap<CVSFile, CVSRevisionIdentifier>()); private long lastReception; private static final long TIME_OUT = CVSConstants.TIME_OUT; // 60 s private boolean timeOutReceived = false; private ContentRevisionRetrieverListener originalContentRevisionRetrieverListener; private ContentRevisionRetrieverListener contentOnRepositoryRevisionRetrieverListener; protected class ContentRevisionRetrieverListener implements RevisionRetrieverListener { private Vector<CVSFile> filesToWait = new Vector<CVSFile>(); private FlexoProgress _progress; protected ContentRevisionRetrieverListener(FlexoProgress progress) { _progress = progress; } @Override public void notifyRevisionRetrieved(CVSFile file, CVSRevisionIdentifier revision) { filesToWait.remove(file); if (_progress != null) { filesToNotify.put(file, revision); if (revision == null) { } else { } } lastReception = System.currentTimeMillis(); } public void addFileToWait(CVSFile file) { filesToWait.add(file); } public int getNumberOfFileToWait() { return filesToWait.size(); } } private synchronized void waitRevisionRetrievingResponses(FlexoProgress progress) { lastReception = System.currentTimeMillis(); int filesToWait = originalContentRevisionRetrieverListener.getNumberOfFileToWait() + contentOnRepositoryRevisionRetrieverListener.getNumberOfFileToWait(); while (filesToWait > 0 && System.currentTimeMillis() - lastReception < TIME_OUT) { synchronized (this) { try { wait(100); } catch (InterruptedException e) { e.printStackTrace(); } } filesToWait = originalContentRevisionRetrieverListener.getNumberOfFileToWait() + contentOnRepositoryRevisionRetrieverListener.getNumberOfFileToWait(); synchronized (filesToNotify) { if (progress != null) { Iterator<CVSFile> i = filesToNotify.keySet().iterator(); while (i.hasNext()) { CVSFile key = i.next(); CVSRevisionIdentifier revision = filesToNotify.get(key); if (revision == null) { progress.setSecondaryProgress(FlexoLocalization.localizedForKeyWithParams( "received_repository_revision_for_file_($0)", key.getFileName())); } else { progress.setSecondaryProgress(FlexoLocalization.localizedForKeyWithParams( "received_revision_($0)_for_file_($1)", revision.versionAsString(), key.getFileName())); } } } filesToNotify.clear(); } } if (filesToWait > 0) { timeOutReceived = true; logger.warning("Synchronize with repository finished with time-out expired: still waiting for " + filesToWait + " files"); } } /** * * @param aPath * : might be absolute or relative to module directory * @return */ public CVSAbstractFile getCVSAbstractFile(String aPath) { // First look if absolute path File searchedFile = new File(aPath); CVSAbstractFile returned = getCVSAbstractFile(searchedFile); if (returned != null) { return returned; } // Then look if relative path searchedFile = new File(getModuleDirectory(), aPath); return getCVSAbstractFile(searchedFile); } public CVSFile getCVSFile(String aPath) { CVSAbstractFile returned = getCVSAbstractFile(aPath); if (returned instanceof CVSFile) { return (CVSFile) returned; } return null; } public CVSAbstractFile createCVSFile(File file) { try { // Retrieve cannonical file to be sure to work on same FS-tree (think about symb links!) file = file.getCanonicalFile(); } catch (IOException e) { logger.warning("Could not retrieve cannonical file for " + file); e.printStackTrace(); } if (!FileUtils.isFileContainedIn(file, getModuleDirectory())) { logger.warning("createCVSFile() requested for " + file + " which is not contained in " + getModuleDirectory() + ". Something strange happened !"); return null; } CVSAbstractFile returned; if (getCVSAbstractFile(file) != null) { return getCVSAbstractFile(file); } CVSContainer cvsParent = (CVSContainer) getCVSAbstractFile(file.getParentFile()); if (cvsParent == null) { cvsParent = (CVSDirectory) createCVSFile(file.getParentFile()); } if (file.isDirectory()) { returned = new CVSDirectory(file, this); cvsParent.addToDirectories((CVSDirectory) returned); } else { returned = new CVSFile(file, this); cvsParent.addToFiles((CVSFile) returned); } return returned; } private int locallyModifiedCount = 0; private int remotelyModifiedCount = 0; private int conflictsCount = 0; public int getLocallyModifiedCount() { return locallyModifiedCount; } protected void incLocallyModifiedCount() { locallyModifiedCount++; setChanged(); notifyObservers(new CVSStatusChanged(null, null, null)); } protected void decLocallyModifiedCount() { locallyModifiedCount--; setChanged(); notifyObservers(new CVSStatusChanged(null, null, null)); } public int getRemotelyModifiedCount() { return remotelyModifiedCount; } protected void incRemotelyModifiedCount() { remotelyModifiedCount++; setChanged(); notifyObservers(new CVSStatusChanged(null, null, null)); } protected void decRemotelyModifiedCount() { remotelyModifiedCount--; setChanged(); notifyObservers(new CVSStatusChanged(null, null, null)); } public int getConflictsCount() { return conflictsCount; } // TODO: performance issue // Please implement this better public int getResolvedConflictsCount() { int returned = 0; for (CVSFile f : conflictingFiles) { if (f.getMerge() != null && f.getMerge().isResolved()) { returned++; } } return returned; } protected void incConflictsCount(CVSFile file) { conflictsCount++; conflictingFiles.add(file); setChanged(); notifyObservers(new CVSStatusChanged(null, null, null)); } protected void decConflictsCount(CVSFile file) { conflictsCount--; conflictingFiles.remove(file); setChanged(); notifyObservers(new CVSStatusChanged(null, null, null)); } private Vector<CVSFile> conflictingFiles = new Vector<CVSFile>(); /************************* * Thread pool management *************************/ public void addToThreads(Runnable runnable) { addToThreadPool(runnable); } /************************* * Thread pool management *************************/ public void addToThreadPool(Runnable runnable) { connectionThreadPool.execute(runnable); if (logger.isLoggable(Level.FINE)) { logger.fine("Thread pool size " + connectionThreadPool.getPoolSize() + " there are " + connectionThreadPool.getQueue().size() + " threads waiting"); } } public FlexoXMLMappings getFlexoXMLMappings() { if (_mappings == null) { _mappings = new FlexoXMLMappings(); } return _mappings; } }