com.nextep.designer.vcs.services.impl.WorkspaceService.java Source code

Java tutorial

Introduction

Here is the source code for com.nextep.designer.vcs.services.impl.WorkspaceService.java

Source

/*******************************************************************************
 * Copyright (c) 2011 neXtep Software and contributors.
 * All rights reserved.
 *
 * This file is part of neXtep designer.
 *
 * NeXtep designer 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 any later version.
 *
 * NeXtep designer 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     neXtep Softwares - initial API and implementation
 *******************************************************************************/
package com.nextep.designer.vcs.services.impl;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.map.MultiValueMap;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import com.nextep.datadesigner.Designer;
import com.nextep.datadesigner.exception.ErrorException;
import com.nextep.datadesigner.hibernate.HibernateUtil;
import com.nextep.datadesigner.model.IElementType;
import com.nextep.datadesigner.model.IReference;
import com.nextep.datadesigner.model.IReferenceContainer;
import com.nextep.datadesigner.model.IReferenceable;
import com.nextep.datadesigner.model.IReferencer;
import com.nextep.datadesigner.model.ITypedObject;
import com.nextep.datadesigner.model.UID;
import com.nextep.datadesigner.vcs.impl.ImportPolicyAddOnly;
import com.nextep.datadesigner.vcs.impl.RepositoryUser;
import com.nextep.datadesigner.vcs.impl.VersionBranch;
import com.nextep.designer.core.CorePlugin;
import com.nextep.designer.core.factories.ControllerFactory;
import com.nextep.designer.core.helpers.NameHelper;
import com.nextep.designer.core.model.IReferenceManager;
import com.nextep.designer.vcs.VCSMessages;
import com.nextep.designer.vcs.model.IRepositoryUser;
import com.nextep.designer.vcs.model.ITargetSet;
import com.nextep.designer.vcs.model.IVersionContainer;
import com.nextep.designer.vcs.model.IVersionable;
import com.nextep.designer.vcs.model.IWorkspace;
import com.nextep.designer.vcs.model.IWorkspaceListener;
import com.nextep.designer.vcs.model.impl.Activity;
import com.nextep.designer.vcs.model.impl.Workspace;
import com.nextep.designer.vcs.services.IDependencyService;
import com.nextep.designer.vcs.services.IVersioningService;
import com.nextep.designer.vcs.services.IWorkspaceService;

/**
 * @author Christophe Fondacci
 * @author Bruno Gautier
 */
public class WorkspaceService implements IWorkspaceService {

    /** Max number of dependencies displayed in an error message */
    private final static int MAX_DISPLAYED_DEPENDENCIES = 10;

    private IWorkspace currentView;
    private ITargetSet currentTargetSet;
    private List<IWorkspaceListener> listeners;
    private IRepositoryUser currentUser;
    private IVersioningService versioningService;
    private IDependencyService dependencyService;

    public WorkspaceService() {
        listeners = new ArrayList<IWorkspaceListener>();
    }

    @Override
    public IWorkspace createWorkspace() {
        return new Workspace("", ""); //$NON-NLS-1$//$NON-NLS-2$
    }

    @Override
    public IWorkspace getCurrentWorkspace() {
        return currentView;
    }

    @Override
    public ITargetSet getCurrentViewTargets() {
        if (currentTargetSet == null || currentTargetSet.getView() != currentView) {
            Collection<ITypedObject> targets = CorePlugin.getPersistenceAccessor()
                    .load(IElementType.getInstance(ITargetSet.TYPE_ID), getCurrentWorkspace());
            if (targets != null && targets.size() > 0) {
                currentTargetSet = (ITargetSet) targets.iterator().next();
            }
        }
        return currentTargetSet;
    }

    @Override
    public void setCurrentWorkspace(IWorkspace currentView) {
        this.currentView = currentView;
    }

    @Override
    public void addWorkspaceListener(IWorkspaceListener listener) {
        listener.setWorkspaceService(this);
        listeners.add(listener);
        Collections.sort(listeners, new Comparator<IWorkspaceListener>() {

            @Override
            public int compare(IWorkspaceListener o1, IWorkspaceListener o2) {
                return o1.getPriority() - o2.getPriority();
            }
        });
    }

    @Override
    public void removeWorkspaceListener(IWorkspaceListener listener) {
        if (listeners.remove(listener)) {
            listener.setWorkspaceService(null);
        }
    }

    @Override
    public void changeWorkspace(UID viewId, IProgressMonitor parentMonitor) {
        SubMonitor monitor = SubMonitor.convert(parentMonitor, VCSMessages.getString("loadView"), 5000); //$NON-NLS-1$

        for (IWorkspaceListener listener : listeners) {
            listener.workspaceClosed(currentView);
        }
        // We clear our hibernate session and reload our view
        HibernateUtil.getInstance().clearAllSessions(); // getSession().clear();
        CorePlugin.getService(IReferenceManager.class).flush();
        VersionBranch.reset();
        Activity.reset();
        monitor.worked(200);

        // Loading root branch
        CorePlugin.getIdentifiableDao().load(VersionBranch.class, new UID(1));
        monitor.worked(100);
        IRepositoryUser user = (IRepositoryUser) CorePlugin.getIdentifiableDao().load(RepositoryUser.class,
                getCurrentUser().getUID());
        setCurrentUser(user);
        monitor.worked(100);

        // Reloading user
        HibernateUtil.setMonitor(monitor.newChild(1000));
        IWorkspace refreshedView = null;
        try {
            CorePlugin.getService(IReferenceManager.class).startWorkspaceLoad();
            // Loading view
            refreshedView = (IWorkspace) CorePlugin.getIdentifiableDao().load(Workspace.class, viewId);
        } finally {
            HibernateUtil.setMonitor(null);
            CorePlugin.getService(IReferenceManager.class).endWorkspaceLoad();
        }
        monitor.setWorkRemaining(600);
        Designer.getInstance().setContext(refreshedView.getDBVendor().name());
        // Keeping reference to old view
        final IWorkspace oldView = getCurrentWorkspace();
        // Setting new view
        setCurrentWorkspace(refreshedView);
        // Notifying listeners
        int childSize = listeners.isEmpty() ? 600 : 600 / listeners.size();
        for (IWorkspaceListener listener : listeners) {
            listener.workspaceChanged(oldView, currentView, monitor.newChild(Math.max(childSize, 1)));
        }
        monitor.done();
    }

    @Override
    public IRepositoryUser getCurrentUser() {
        return currentUser;
    }

    @Override
    public void setCurrentUser(IRepositoryUser user) {
        currentUser = user;
    }

    @Override
    public void move(Collection<IVersionable<?>> versionToMove, IVersionContainer targetContainer,
            IProgressMonitor monitor) {
        monitor.beginTask(MessageFormat.format(VCSMessages.getString("movingVersionableCmdGlobal"), //$NON-NLS-1$
                targetContainer.getName()), versionToMove.size());
        if (targetContainer == null) {
            targetContainer = getCurrentWorkspace();
        }
        Collection<IVersionable<?>> toUnlock = new ArrayList<IVersionable<?>>(versionToMove);
        // If target container is versionable, we need to unlock as well
        if (targetContainer instanceof IVersionable<?>) {
            targetContainer = versioningService.ensureModifiable(targetContainer);
        }
        // Requesting unlock if needed (cancellation would raise here)
        versioningService.unlock(true, toUnlock.toArray(new IVersionable<?>[toUnlock.size()]));
        // Everything is ok, moving
        for (IVersionable<?> v : versionToMove) {
            monitor.subTask(MessageFormat.format(VCSMessages.getString("movingVersionableCmd"), v.getName(), v //$NON-NLS-1$
                    .getContainer().getName(), targetContainer.getName()));
            v.getContainer().removeVersionable(v);
            targetContainer.addVersionable(v, new ImportPolicyAddOnly());
            CorePlugin.getPersistenceAccessor().save(v);
            monitor.worked(1);
        }
        monitor.done();
    }

    public void setVersioningService(IVersioningService versioningService) {
        this.versioningService = versioningService;
    }

    public void setDependencyService(IDependencyService dependencyService) {
        this.dependencyService = dependencyService;
    }

    @Override
    public void remove(IProgressMonitor m, IReferenceable... elementsToRemove) {
        IProgressMonitor monitor = SubMonitor.convert(m);
        monitor.beginTask(VCSMessages.getString("service.view.removeElementsTask"), elementsToRemove.length + 1); //$NON-NLS-1$
        final MultiValueMap invRefMap = CorePlugin.getService(IReferenceManager.class).getReverseDependenciesMap();
        // We are at the root level of dependency computation, so no dependency is deleted so far
        List<IReferencer> deletedDependencies = Collections.emptyList();
        monitor.subTask(VCSMessages.getString("service.view.computeDependenciesTask")); //$NON-NLS-1$
        // Computing all dependencies which would remain in the chain of deletion
        List<IReferencer> remainingDependencies = getRemainingDependencies(deletedDependencies, invRefMap,
                elementsToRemove);
        if (!remainingDependencies.isEmpty()) {
            StringBuilder buf = new StringBuilder();
            int count = 0;
            for (IReferencer r : remainingDependencies) {
                if (count++ < MAX_DISPLAYED_DEPENDENCIES) {
                    buf.append("  - " + NameHelper.getQualifiedName(r) + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
                }
            }
            throw new ErrorException(
                    MessageFormat.format(VCSMessages.getString("service.view.remainindDependenciesError"), //$NON-NLS-1$
                            remainingDependencies.size(), buf.toString()));
        }
        monitor.worked(1);
        for (IReferenceable r : elementsToRemove) {
            ControllerFactory.getController(r).modelDeleted(r);
            monitor.worked(1);
        }
        monitor.done();

    }

    @SuppressWarnings("unchecked")
    public List<IReferencer> getRemainingDependencies(List<IReferencer> initialDeletedReferencers,
            MultiValueMap invRefMap, IReferenceable... elementsToRemove) {
        // Building deleted referencers list
        List<IReferencer> deletedReferencers = new ArrayList<IReferencer>(initialDeletedReferencers);
        for (IReferenceable obj : elementsToRemove) {
            if (obj instanceof IReferencer) {
                deletedReferencers.add((IReferencer) obj);
            }
            if (obj instanceof IReferenceContainer) {
                final Map<IReference, IReferenceable> refMap = ((IReferenceContainer) obj).getReferenceMap();
                for (IReferenceable child : refMap.values()) {
                    if (child instanceof IReferencer) {
                        deletedReferencers.add((IReferencer) child);
                    }
                }
            }
        }
        // Checking items removal
        Set<IReferencer> remainingDependencies = new HashSet<IReferencer>();
        for (IReferenceable obj : elementsToRemove) {
            // Retrieving this object's reverse dependencies
            Collection<IReferencer> revDeps = (Collection<IReferencer>) invRefMap.getCollection(obj.getReference());
            if (revDeps == null) {
                revDeps = Collections.emptySet();
            }
            // Getting remaining elements which reference the current object, which will not be
            // deleted
            Collection<IReferencer> objRemainingDependencies = dependencyService.getReferencersAfterDeletion(obj,
                    revDeps, deletedReferencers);
            // We add them to the global remaining dependencies set
            remainingDependencies.addAll(objRemainingDependencies);
        }
        // Now listing elements, because ordering matters here (resursive dependencies must be
        // placed first)
        List<IReferencer> remainingDependencyList = new ArrayList<IReferencer>(remainingDependencies);
        // For remaining dependencies which are themselves referenceable, we recursively compute
        // dependencies which would remain after deletion to build an exhaustive list of elements
        // to remove
        for (IReferencer referencer : remainingDependencies) {
            if (referencer instanceof IReferenceable) {
                remainingDependencyList.addAll(0,
                        getRemainingDependencies(deletedReferencers, invRefMap, (IReferenceable) referencer));
            }
        }
        return remainingDependencyList;
    }

    @SuppressWarnings("unchecked")
    @Override
    public UID findWorkspaceId(String name) {
        List<Number> idList = (List<Number>) HibernateUtil.getInstance().getSandBoxSession()
                .createSQLQuery("SELECT vv.view_id " //$NON-NLS-1$
                        + "FROM {h-schema}rep_version_views vv " //$NON-NLS-1$
                        + "WHERE LOWER(REPLACE(vv.view_name,' ','_')) = LOWER(REPLACE(?,' ','_')) ") //$NON-NLS-1$
                .setString(0, name).list();

        if (idList != null && idList.size() == 1) {
            return new UID(idList.iterator().next().longValue());
        }
        return null;
    }

}