/* * (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.action; import java.io.File; import java.io.IOException; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.netbeans.lib.cvsclient.command.CommandException; import org.netbeans.lib.cvsclient.connection.AuthenticationException; import org.netbeans.lib.cvsclient.event.CVSAdapter; import org.netbeans.lib.cvsclient.event.FileAddedEvent; import org.openflexo.foundation.FlexoEditor; import org.openflexo.foundation.FlexoModelObject; import org.openflexo.foundation.IOFlexoException; import org.openflexo.foundation.action.FlexoActionType; import org.openflexo.fps.CVSConstants; import org.openflexo.fps.CVSExplorable; import org.openflexo.fps.CVSExplorer; import org.openflexo.fps.CVSExplorerListener; import org.openflexo.fps.CVSFile; import org.openflexo.fps.CVSModule; import org.openflexo.fps.FPSObject; import org.openflexo.fps.FlexoAuthentificationException; import org.openflexo.fps.SharedProject; import org.openflexo.localization.FlexoLocalization; import org.openflexo.toolbox.FileUtils; public class CheckoutProject extends CVSAction<CheckoutProject, CVSModule> { protected static final Logger logger = Logger.getLogger(CheckoutProject.class.getPackage().getName()); public static FlexoActionType<CheckoutProject, CVSModule, FPSObject> actionType = new FlexoActionType<CheckoutProject, CVSModule, FPSObject>( "checkout_project", FlexoActionType.defaultGroup, FlexoActionType.NORMAL_ACTION_TYPE) { /** * Factory method */ @Override public CheckoutProject makeNewAction(CVSModule focusedObject, Vector<FPSObject> globalSelection, FlexoEditor editor) { return new CheckoutProject(focusedObject, globalSelection, editor); } @Override public boolean isVisibleForSelection(CVSModule object, Vector<FPSObject> globalSelection) { return true; } @Override public boolean isEnabledForSelection(CVSModule object, Vector<FPSObject> globalSelection) { return true; } }; static { FlexoModelObject.addActionForClass(actionType, CVSModule.class); } @Override public String getLocalizedName() { if (getFocusedObject() != null && getFocusedObject().getModuleName().endsWith(".prj")) { return FlexoLocalization.localizedForKey("checkout_project"); } else { return FlexoLocalization.localizedForKey("checkout_directory"); } } private SharedProject _checkoutedProject; CheckoutProject(CVSModule focusedObject, Vector<FPSObject> globalSelection, FlexoEditor editor) { super(actionType, focusedObject, globalSelection, editor); } @Override protected void doAction(Object context) throws IOFlexoException, FlexoAuthentificationException { CheckoutProgressController progressController = new CheckoutProgressController(); logger.info("ProjectCheckout to " + getLocalDirectory()); progressController.start(); try { _checkoutedProject = SharedProject.checkoutProject(getFocusedObject().getCVSRepository(), getFocusedObject(), getLocalDirectory(), getLocalName(), progressController); } catch (IOException e) { e.printStackTrace(); } catch (CommandException e) { e.printStackTrace(); } catch (AuthenticationException e) { throw new FlexoAuthentificationException(getFocusedObject().getCVSRepository()); } finally { progressController.stop(); } } public SharedProject getCheckoutedProject() { return _checkoutedProject; } private File _localDirectory; private String _localName; public File getLocalDirectory() { return _localDirectory; } public void setLocalDirectory(File localDirectory) { _localDirectory = localDirectory; } public String getLocalName() { if (_localName == null) { _localName = getFocusedObject().getModuleName(); } return _localName; } public void setLocalName(String localName) { _localName = localName; } protected class CheckoutProgressController extends CVSAdapter { private Hashtable<FPSObject, Vector<FPSObject>> projectHierarchy; private long lastReception; private Hashtable<CVSModule, Boolean> _hierarchyHasBeenRetrieved; protected CheckoutProgressController() { if (logger.isLoggable(Level.FINE)) { logger.fine("Retrieving project hierarchy..."); } projectHierarchy = retrieveProjectHerarchy(); if (logger.isLoggable(Level.FINE)) { for (FPSObject o : projectHierarchy.keySet()) { if (o instanceof CVSModule) { logger.fine(((CVSModule) o).getFullQualifiedModuleName()); for (FPSObject o2 : projectHierarchy.get(o)) { if (o2 instanceof CVSModule) { logger.fine(((CVSModule) o2).getFullQualifiedModuleName()); } else if (o2 instanceof CVSFile) { logger.fine(((CVSModule) o).getFullQualifiedModuleName() + '/' + ((CVSFile) o2).getFileName()); } } } else if (o instanceof CVSFile) { logger.fine(((CVSFile) o).getFileName()); } } } if (logger.isLoggable(Level.FINE)) { logger.fine("Retrieving project hierarchy...Done"); } } private FPSObject _currentCheckoutedObject = null; private Vector<FPSObject> _alreadyCheckouted = new Vector<FPSObject>(); private FPSObject objectForString(String name) { for (FPSObject o : projectHierarchy.keySet()) { if (o instanceof CVSModule && ((CVSModule) o).getModuleName().equals(name)) { return o; } if (o instanceof CVSFile && ((CVSFile) o).getFileName().equals(name)) { return o; } } return null; } @Override public void fileAdded(FileAddedEvent e) { String relativePath; try { relativePath = FileUtils.makeFilePathRelativeToDir(new File(e.getFilePath()), getLocalDirectory()); if (logger.isLoggable(Level.FINE)) { logger.fine("FileAdded: " + e.getFilePath() + " relative path=" + relativePath); } StringTokenizer st = new StringTokenizer(relativePath, "/" + "\\"); if (st.hasMoreTokens()) { st.nextToken(); // Skip root location } else { return; } if (st.hasMoreTokens()) { String current = st.nextToken(); FPSObject currentCheckoutedObject = objectForString(current); if (currentCheckoutedObject != _currentCheckoutedObject) { _currentCheckoutedObject = currentCheckoutedObject; setProgress(FlexoLocalization.localizedForKeyWithParams("checkouting_($0)", current)); resetSecondaryProgress(projectHierarchy.get(currentCheckoutedObject).size() + 1); } else { setSecondaryProgress(FlexoLocalization.localizedForKeyWithParams("checkouting_($0)", relativePath)); } } else { return; } } catch (IOException e1) { e1.printStackTrace(); } } public void start() { makeFlexoProgress(FlexoLocalization.localizedForKeyWithParams("checkouting_($0)_to_($1)", getFocusedObject() .getFullQualifiedModuleName(), getLocalDirectory().getAbsolutePath()), projectHierarchy.keySet().size() + 1); setProgress(FlexoLocalization.localizedForKey("sending_checkout_request")); } public void stop() { hideFlexoProgress(); } private Hashtable<FPSObject, Vector<FPSObject>> retrieveProjectHerarchy() { makeFlexoProgress(FlexoLocalization.localizedForKey("preparing_checkout"), 4); setProgress(FlexoLocalization.localizedForKey("explore_cvs_module")); final Hashtable<FPSObject, Vector<FPSObject>> response = new Hashtable<FPSObject, Vector<FPSObject>>(); _hierarchyHasBeenRetrieved = new Hashtable<CVSModule, Boolean>(); exploreModule(getFocusedObject(), response); waitProjectHierarchyRetrievingResponses(); hideFlexoProgress(); return response; } private void exploreModule(final CVSModule module, final Hashtable<FPSObject, Vector<FPSObject>> response) { if (logger.isLoggable(Level.FINE)) { logger.fine("Exploring module " + module.getFullyQualifiedName() + " parent=" + module.getParent()); } _hierarchyHasBeenRetrieved.put(module, false); module.exploreModule(new CVSExplorerListener() { @Override public void exploringFailed(CVSExplorable explorable, CVSExplorer explorer, Exception exception) { lastReception = System.currentTimeMillis(); if (logger.isLoggable(Level.FINE)) { logger.fine("exploring FAILED"); } _hierarchyHasBeenRetrieved.put(module, true); } @Override public void exploringSucceeded(CVSExplorable explorable, CVSExplorer explorer) { lastReception = System.currentTimeMillis(); setProgress(FlexoLocalization.localizedForKey("explore_sub_modules")); if (logger.isLoggable(Level.FINE)) { logger.fine(module.getFullQualifiedModuleName() + " : exploring SUCCEEDED " + module.getCVSModules()); } if (module == getFocusedObject()) { modulesToNotify.add(module); for (CVSFile f : module.getCVSFiles()) { response.put(f, new Vector<FPSObject>()); } for (CVSModule m : module.getCVSModules()) { response.put(m, new Vector<FPSObject>()); exploreModule(m, response); } } else if (response.get(module) != null) { for (CVSFile f : module.getCVSFiles()) { response.get(module).add(f); } for (CVSModule m : module.getCVSModules()) { response.get(module).add(m); } modulesToNotify.add(module); } _hierarchyHasBeenRetrieved.put(module, true); } }); } private boolean someModulesAreStillToWait() { for (Boolean receivedResponse : _hierarchyHasBeenRetrieved.values()) { if (!receivedResponse) { return true; } } return false; } private static final long TIME_OUT = CVSConstants.TIME_OUT; // 60 s protected Vector<CVSModule> modulesToNotify = new Vector<CVSModule>(); private synchronized void waitProjectHierarchyRetrievingResponses() { lastReception = System.currentTimeMillis(); while (someModulesAreStillToWait() && System.currentTimeMillis() - lastReception < TIME_OUT) { synchronized (this) { try { wait(100); } catch (InterruptedException e) { e.printStackTrace(); } } while (modulesToNotify.size() > 0) { CVSModule module = modulesToNotify.firstElement(); modulesToNotify.removeElementAt(0); if (module == getFocusedObject()) { resetSecondaryProgress(module.getCVSModules().size() + 1); } else { setSecondaryProgress(FlexoLocalization.localizedForKey("explored") + " " + module.getFullQualifiedModuleName()); } } } if (someModulesAreStillToWait()) { // timeOutReceived = true; logger.warning("Module exploring finished with time-out expired"); } } } }