package jetbrains.mps.ide.newModuleDialogs;
/*Generated by MPS */
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import jetbrains.mps.project.MPSProject;
import jetbrains.mps.project.AbstractModule;
import jetbrains.mps.vfs.IFile;
import org.jetbrains.annotations.Nullable;
import jetbrains.mps.project.structure.modules.ModuleDescriptor;
import jetbrains.mps.extapi.persistence.CopyNotSupportedException;
import jetbrains.mps.util.ReferenceUpdater;
import jetbrains.mps.smodel.Language;
import java.util.Collection;
import jetbrains.mps.smodel.Generator;
import java.util.Iterator;
import jetbrains.mps.internal.collections.runtime.CollectionSequence;
import com.intellij.openapi.ui.Messages;
import org.apache.log4j.Level;
import jetbrains.mps.module.ModuleDeleteHelper;
import java.util.Collections;
import org.jetbrains.mps.openapi.module.SModule;
import jetbrains.mps.project.StandaloneMPSProject;
import jetbrains.mps.smodel.ModuleRepositoryFacade;
import jetbrains.mps.library.ModulesMiner;
import java.util.List;
import org.jetbrains.mps.openapi.persistence.ModelRoot;
import java.util.ArrayList;
import jetbrains.mps.extapi.persistence.CopyableModelRoot;
import org.jetbrains.mps.openapi.persistence.PersistenceFacade;
import jetbrains.mps.extapi.persistence.ModelRootBase;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.extapi.model.SModelBase;
import jetbrains.mps.project.structure.model.ModelRootDescriptor;
import org.jetbrains.mps.openapi.persistence.Memento;
import jetbrains.mps.persistence.MementoImpl;
public final class CopyModuleHelper {
private static final Logger LOG = LogManager.getLogger(CopyModuleHelper.class);
private final MPSProject myProject;
private final AbstractModule myOriginal;
private final String myCopyName;
private final IFile myCopyLocation;
private final String myVirtualFolder;
public CopyModuleHelper(MPSProject project, AbstractModule originalModule, String newModuleName, IFile newModuleLocation, String virtualFolder) {
myProject = project;
myOriginal = originalModule;
myCopyName = newModuleName;
myCopyLocation = newModuleLocation;
myVirtualFolder = virtualFolder;
}
@Nullable
public AbstractModule copy() {
if (myOriginal.isPackaged()) {
// Do not handle this case since packaged module may not contain it sources
return null;
}
ModuleDescriptor moduleDescriptor = myOriginal.getModuleDescriptor();
if (moduleDescriptor == null) {
throw new IllegalArgumentException("The module descriptor is null for the " + myOriginal);
}
AbstractModule copy;
ModuleDescriptor copyDescriptor = new DescriptorCopyOrganizer(myOriginal, myCopyName, myCopyLocation).copyDescriptor();
copy = createModule(myCopyLocation, copyDescriptor);
try {
copyModelsAndFacets(copy);
addModuleToProject(copy);
adjustReferences(copy);
} catch (CopyNotSupportedException e) {
return handleException(e, copy);
} catch (ReferenceUpdater.RefUpdateException e) {
return handleException(e, copy);
}
copy.save();
return copy;
}
private void copyModelsAndFacets(AbstractModule copy) throws CopyNotSupportedException {
copyModelRoots(myOriginal, copy);
copyFacets(myOriginal, copy);
if (myOriginal instanceof Language) {
Collection<Generator> copyGenerators = ((Language) copy).getGenerators();
Collection<Generator> originalGenerators = ((Language) myOriginal).getGenerators();
if (copyGenerators.size() != originalGenerators.size()) {
throw new CopyNotSupportedException("Generators number do not match!");
}
{
Iterator<Generator> newGen_it = CollectionSequence.fromCollection(copyGenerators).iterator();
Iterator<Generator> oldGen_it = CollectionSequence.fromCollection(originalGenerators).iterator();
Generator newGen_var;
Generator oldGen_var;
while (newGen_it.hasNext() && oldGen_it.hasNext()) {
newGen_var = newGen_it.next();
oldGen_var = oldGen_it.next();
copyModelRoots(oldGen_var, newGen_var);
copyFacets(oldGen_var, newGen_var);
}
}
}
}
private AbstractModule handleException(Exception e, AbstractModule result) {
Messages.showErrorDialog(myProject.getProject(), "Something went wrong -- operation failed.", "Failure");
if (LOG.isEnabledFor(Level.ERROR)) {
LOG.error(e.getMessage(), e);
}
new ModuleDeleteHelper(myProject).deleteModules(Collections.<SModule>singletonList(result), false, true);
return null;
}
private void addModuleToProject(AbstractModule result) {
myProject.addModule(result);
if (myProject instanceof StandaloneMPSProject) {
((StandaloneMPSProject) myProject).setFolderFor(result, myVirtualFolder);
}
}
/**
* We can exploit polymorphism by moving this code to the individual module [descriptor] classes
* however I could not think of a nice API in that case.
* Should it be a #copy method which returns a Function-like constructor?
* Due to the mix-up in the SModule hierarchy API (descriptors reflect the persistence not the actual module properties)
* I am unable to design it right now. First we solve the module api problem and then we will write this code properly
*/
private AbstractModule createModule(IFile resultFile, ModuleDescriptor copyDescriptor) {
ModuleRepositoryFacade facade = new ModuleRepositoryFacade(myProject);
SModule result = facade.instantiateModule(new ModulesMiner.ModuleHandle(resultFile, copyDescriptor), myProject);
return (AbstractModule) result;
}
private void adjustReferences(AbstractModule copy) throws ReferenceUpdater.RefUpdateException {
ReferenceUpdater referenceUpdater = new ReferenceUpdater();
referenceUpdater.addModuleToAdjust(myOriginal, copy);
referenceUpdater.adjust();
}
private static void copyModelRoots(AbstractModule source, AbstractModule target) throws CopyNotSupportedException {
List<ModelRoot> targetModelRoots = new ArrayList<ModelRoot>();
for (ModelRoot sourceModelRoot : source.getModelRoots()) {
if (!(sourceModelRoot instanceof CopyableModelRoot)) {
throw new CopyNotSupportedException("Can't clone model root " + sourceModelRoot + " : Cloning hasn't implemented for '" + sourceModelRoot.getType() + "' model roots");
}
ModelRoot targetModelRoot = PersistenceFacade.getInstance().getModelRootFactory(sourceModelRoot.getType()).create();
if (targetModelRoot instanceof ModelRootBase) {
((ModelRootBase) targetModelRoot).setModule(target);
}
// noinspection unchecked
((CopyableModelRoot) sourceModelRoot).copyTo((CopyableModelRoot) targetModelRoot);
targetModelRoots.add(targetModelRoot);
}
// hack to synchronize the module descriptor with the new model roots
for (SModel model : ListSequence.fromList(target.getModels())) {
target.unregisterModel((SModelBase) model);
}
ModuleDescriptor targetDescriptor = target.getModuleDescriptor();
if (targetDescriptor != null) {
Collection<ModelRootDescriptor> modelRootDescriptors = targetDescriptor.getModelRootDescriptors();
for (ModelRoot targetModelRoot : targetModelRoots) {
Memento targetMemento = new MementoImpl();
targetModelRoot.save(targetMemento);
modelRootDescriptors.add(new ModelRootDescriptor(targetModelRoot.getType(), targetMemento));
}
target.setModuleDescriptor(targetDescriptor);
}
}
/**
* TODO formally facets need to be copied in the same way model roots are now.
* However facets are going to become totally independent from the module
*/
public static void copyFacets(AbstractModule source, AbstractModule target) throws CopyNotSupportedException {
// nop
}
}