/*
* Copyright 2003-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrains.mps.project;
import jetbrains.mps.util.ClassType;
import jetbrains.mps.classloading.CustomClassLoadingFacet;
import jetbrains.mps.java.stub.PackageScopeControl;
import jetbrains.mps.library.ModulesMiner;
import jetbrains.mps.module.ReloadableModuleBase;
import jetbrains.mps.project.facets.TestsFacet;
import jetbrains.mps.project.persistence.SolutionDescriptorPersistence;
import jetbrains.mps.project.structure.model.ModelRootDescriptor;
import jetbrains.mps.project.structure.modules.ModuleDescriptor;
import jetbrains.mps.project.structure.modules.SolutionDescriptor;
import jetbrains.mps.project.structure.modules.SolutionKind;
import jetbrains.mps.reloading.CommonPaths;
import jetbrains.mps.smodel.BootstrapLanguages;
import jetbrains.mps.util.MacrosFactory;
import jetbrains.mps.util.annotation.Hack;
import jetbrains.mps.vfs.IFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.module.SModuleReference;
import org.jetbrains.mps.openapi.persistence.Memento;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Igor Alshannikov
* Aug 26, 2005
*/
public class Solution extends ReloadableModuleBase {
private SolutionDescriptor mySolutionDescriptor;
public static final String SOLUTION_MODELS = "models";
// idea plugin wants to turn it off sometimes, when it knows better what jdk is and what platform is
private boolean myUpdateBootstrapSolutions = true;
private static Map<SModuleReference, ClassType> bootstrapCP = initBootstrapSolutions();
private static Map<SModuleReference, ClassType> initBootstrapSolutions() {
Map<SModuleReference, ClassType> result = new HashMap<SModuleReference, ClassType>();
result.put(BootstrapLanguages.jdkRef(), ClassType.JDK);
result.put(BootstrapLanguages.jdkToolsRef(), ClassType.JDK_TOOLS);
result.put(new jetbrains.mps.project.structure.modules.ModuleReference("Annotations",
ModuleId.fromString("3f233e7f-b8a6-46d2-a57f-795d56775243")), ClassType.ANNOTATIONS);
result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.OpenAPI",
ModuleId.fromString("8865b7a8-5271-43d3-884c-6fd1d9cfdd34")), ClassType.OPENAPI);
result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.Core",
ModuleId.fromString("6ed54515-acc8-4d1e-a16c-9fd6cfe951ea")), ClassType.CORE);
result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.Editor",
ModuleId.fromString("1ed103c3-3aa6-49b7-9c21-6765ee11f224")), ClassType.EDITOR);
result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.Platform",
ModuleId.fromString("742f6602-5a2f-4313-aa6e-ae1cd4ffdc61")), ClassType.PLATFORM);
result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.IDEA",
ModuleId.fromString("498d89d2-c2e9-11e2-ad49-6cf049e62fe5")), ClassType.IDEA);
result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.Workbench",
ModuleId.fromString("86441d7a-e194-42da-81a5-2161ec62a379")), ClassType.WORKBENCH);
result.put(new jetbrains.mps.project.structure.modules.ModuleReference("Testbench",
ModuleId.fromString("920eaa0e-ecca-46bc-bee7-4e5c59213dd6")), ClassType.TEST);
return result;
}
/* TODO make package local, move to appropriate package */
public Solution(SolutionDescriptor descriptor, @Nullable IFile file) {
super(file);
mySolutionDescriptor = descriptor;
setModuleReference(descriptor.getModuleReference());
}
private static void populateModelRoot(ClassType classType, ModelRootDescriptor javaStubsModelRoot) {
PackageScopeControl psc = null;
switch (classType) {
case JDK:
PackageScopeControl jdkPackages = new PackageScopeControl();
jdkPackages.setSkipPrivate(true);
jdkPackages.includeWithPrefix("java.");
jdkPackages.includeWithPrefix("javax.");
jdkPackages.includeWithPrefix("org.");
// sun.awt used in mbeddr
jdkPackages.includeWithPrefix("sun.awt.");
psc = jdkPackages;
break;
case JDK_TOOLS:
psc = new PackageScopeControl();
psc.isSkipPrivate();
psc.includeWithPrefix("com.sun.codemodel.");
psc.includeWithPrefix("com.sun.source.");
psc.includeWithPrefix("com.sun.tools.");
psc.includeWithPrefix("com.sun.jarsigner.");
psc.includeWithPrefix("com.sun.javadoc.");
psc.includeWithPrefix("com.sun.jdi.");
psc.includeWithPrefix("org.relaxng.");
psc.includeWithPrefix("sun.jvmstat.");
psc.includeWithPrefix("sun.rmi.rmic.");
psc.includeWithPrefix("sun.tools.");
psc.includeWithPrefix("sun.applet.");
break;
case PLATFORM:
case IDEA:
PackageScopeControl platformPackages = new PackageScopeControl();
// mbeddr uses reflection (though custom dsl) to access MPS internals
// hence we need to expose private methods unless this reflection language and its uses are removed
// platformPackages.setSkipPrivate(true);
psc = platformPackages;
break;
}
if (psc != null) {
final Memento m = javaStubsModelRoot.getMemento().createChild("PackageScope");
psc.save(m);
}
}
@NotNull
@Override
public SolutionDescriptor getModuleDescriptor() {
return mySolutionDescriptor;
}
@Override
protected void doSetModuleDescriptor(ModuleDescriptor moduleDescriptor) {
mySolutionDescriptor = (SolutionDescriptor) moduleDescriptor;
SModuleReference mp;
if (mySolutionDescriptor.getNamespace() != null) {
mp = new jetbrains.mps.project.structure.modules.ModuleReference(mySolutionDescriptor.getNamespace(), mySolutionDescriptor.getId());
} else {
assert myDescriptorFile != null;
mp = new jetbrains.mps.project.structure.modules.ModuleReference(myDescriptorFile.getPath(), mySolutionDescriptor.getId());
}
setModuleReference(mp);
}
public void setUpdateBootstrapSolutions(boolean b) {
myUpdateBootstrapSolutions = b;
}
@Override
public void save() {
super.save();
//do not save stub solutions (otherwise build model generation fails)
SModuleReference ref = this.getModuleReference();
if (isBootstrapSolution(ref)) return;
// in StubSolutions myDescriptorFile is null, so preventing NPE here (MPS-16793)
if (myDescriptorFile == null || isReadOnly()) return;
if (mySolutionDescriptor.getLoadException() != null){
return;
}
SolutionDescriptorPersistence.saveSolutionDescriptor(myDescriptorFile, getModuleDescriptor(), MacrosFactory.forModule(this));
}
public static boolean isBootstrapSolution(SModuleReference ref) {
return bootstrapCP.keySet().contains(ref);
}
@Override
public void updateModelsSet() {
if (myUpdateBootstrapSolutions) {
updateBootstrapSolutionLibraries();
}
super.updateModelsSet();
}
@Hack
private void updateBootstrapSolutionLibraries() {
ModuleDescriptor descriptor = getModuleDescriptor();
ClassType classType = bootstrapCP.get(descriptor.getModuleReference());
if (classType == null) return;
// do it only for first time
if (descriptor.getModelRootDescriptors().isEmpty()) {
for (String path : CommonPaths.getMPSPaths(classType)) {
final Collection<ModelRootDescriptor> modelRootDescriptors = descriptor.getModelRootDescriptors();
IFile pathFile = getFileSystem().getFile(path);
final ModelRootDescriptor javaStubsModelRoot = ModelRootDescriptor.getJavaStubsModelRoot(pathFile, modelRootDescriptors);
if (javaStubsModelRoot != null) {
modelRootDescriptors.add(javaStubsModelRoot);
populateModelRoot(classType, javaStubsModelRoot);
}
if (classType.hasOwnJavaStubs()) {
descriptor.getAdditionalJavaStubPaths().add(path);
}
}
}
}
public String toString() {
return getModuleName() + " [solution]";
}
public SolutionKind getKind() {
return getModuleDescriptor().getKind();
}
@Override
protected void collectMandatoryFacetTypes(Set<String> types) {
super.collectMandatoryFacetTypes(types);
types.add(TestsFacet.FACET_TYPE);
}
@Override
protected SolutionDescriptor loadDescriptor() {
IFile file = getDescriptorFile();
assert file != null;
return (SolutionDescriptor) new ModulesMiner().loadModuleHandle(file).getDescriptor();
}
@Override
public boolean willLoad() {
// TODO mps facet from this [like IDEA plugin facet]
return getKind() != SolutionKind.NONE || getFacet(CustomClassLoadingFacet.class) != null;
}
}