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 } }