blob: 0fb96f210eaa57816dec3e76c19dcb412f2da4d6 [file] [log] [blame]
/*
* Copyright 2000-2013 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 com.intellij.appengine.facet;
import com.intellij.appengine.sdk.AppEngineSdk;
import com.intellij.appengine.sdk.impl.AppEngineSdkUtil;
import com.intellij.appengine.util.AppEngineUtil;
import com.intellij.facet.ui.FacetBasedFrameworkSupportProvider;
import com.intellij.facet.ui.ValidationResult;
import com.intellij.icons.AllIcons;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.util.frameworkSupport.*;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.artifacts.ArtifactManager;
import com.intellij.packaging.artifacts.ArtifactType;
import com.intellij.packaging.elements.ArtifactRootElement;
import com.intellij.packaging.elements.PackagingElementFactory;
import com.intellij.packaging.impl.artifacts.ArtifactUtil;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.HyperlinkLabel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.appengine.model.PersistenceApi;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author nik
*/
public class AppEngineSupportProvider extends FacetBasedFrameworkSupportProvider<AppEngineFacet> {
private static final Logger LOG = Logger.getInstance("#com.intellij.appengine.facet.AppEngineSupportProvider");
private static final String JPA_PROVIDER_ID = "facet:jpa";
private static final String WEB_PROVIDER_ID = "facet:web";
public AppEngineSupportProvider() {
super(AppEngineFacet.getFacetType());
}
@Override
public String[] getPrecedingFrameworkProviderIds() {
return new String[]{JPA_PROVIDER_ID, WEB_PROVIDER_ID};
}
protected void setupConfiguration(AppEngineFacet facet, ModifiableRootModel rootModel, FrameworkVersion version) {
}
@Nullable
private VirtualFile createFileFromTemplate(final String templateName, final VirtualFile parent, final String fileName) {
parent.refresh(false, false);
final FileTemplate template = FileTemplateManager.getInstance().getJ2eeTemplate(templateName);
try {
final String text = template.getText(FileTemplateManager.getInstance().getDefaultProperties());
VirtualFile file = parent.findChild(fileName);
if (file == null) {
file = parent.createChildData(this, fileName);
}
VfsUtil.saveText(file, text);
return file;
}
catch (IOException e) {
LOG.error(e);
return null;
}
}
private void addSupport(final Module module, final ModifiableRootModel rootModel, String sdkPath, @Nullable PersistenceApi persistenceApi) {
super.addSupport(module, rootModel, null, null);
final AppEngineFacet appEngineFacet = AppEngineFacet.getAppEngineFacetByModule(module);
LOG.assertTrue(appEngineFacet != null);
final AppEngineFacetConfiguration facetConfiguration = appEngineFacet.getConfiguration();
facetConfiguration.setSdkHomePath(sdkPath);
final AppEngineSdk sdk = appEngineFacet.getSdk();
final Artifact artifact = findOrCreateArtifact(appEngineFacet);
AppEngineWebIntegration webIntegration = AppEngineWebIntegration.getInstance();
final VirtualFile descriptorDir = webIntegration.suggestParentDirectoryForAppEngineWebXml(module, rootModel);
if (descriptorDir != null) {
VirtualFile descriptor = createFileFromTemplate(AppEngineTemplateGroupDescriptorFactory.APP_ENGINE_WEB_XML_TEMPLATE, descriptorDir,
AppEngineUtil.APP_ENGINE_WEB_XML_NAME);
if (descriptor != null) {
webIntegration.addDescriptor(artifact, module.getProject(), descriptor);
}
}
final Project project = module.getProject();
webIntegration.setupRunConfiguration(sdk, artifact, project);
webIntegration.addDevServerToModuleDependencies(rootModel, sdk);
final Library apiJar = addProjectLibrary(module, "AppEngine API", sdk.getUserLibraryPaths(), VirtualFile.EMPTY_ARRAY);
rootModel.addLibraryEntry(apiJar);
webIntegration.addLibraryToArtifact(apiJar, artifact, project);
if (persistenceApi != null) {
facetConfiguration.setRunEnhancerOnMake(true);
facetConfiguration.setPersistenceApi(persistenceApi);
facetConfiguration.getFilesToEnhance().addAll(AppEngineUtil.getDefaultSourceRootsToEnhance(rootModel));
try {
final VirtualFile[] sourceRoots = rootModel.getSourceRoots();
final VirtualFile sourceRoot;
if (sourceRoots.length > 0) {
sourceRoot = sourceRoots[0];
}
else {
sourceRoot = findOrCreateChildDirectory(rootModel.getContentRoots()[0], "src");
}
VirtualFile metaInf = findOrCreateChildDirectory(sourceRoot, "META-INF");
if (persistenceApi == PersistenceApi.JDO || persistenceApi == PersistenceApi.JDO3) {
createFileFromTemplate(AppEngineTemplateGroupDescriptorFactory.APP_ENGINE_JDO_CONFIG_TEMPLATE, metaInf, AppEngineUtil.JDO_CONFIG_XML_NAME);
}
else {
final VirtualFile file = createFileFromTemplate(AppEngineTemplateGroupDescriptorFactory.APP_ENGINE_JPA_CONFIG_TEMPLATE, metaInf, AppEngineUtil.JPA_CONFIG_XML_NAME);
if (file != null) {
webIntegration.setupJpaSupport(module, file);
}
}
}
catch (IOException e) {
LOG.error(e);
}
final Library library = addProjectLibrary(module, "AppEngine ORM", Collections.singletonList(sdk.getOrmLibDirectoryPath()), sdk.getOrmLibSources());
rootModel.addLibraryEntry(library);
webIntegration.addLibraryToArtifact(library, artifact, project);
}
}
@NotNull
private static Artifact findOrCreateArtifact(AppEngineFacet appEngineFacet) {
Module module = appEngineFacet.getModule();
ArtifactType artifactType = AppEngineWebIntegration.getInstance().getAppEngineTargetArtifactType();
final Collection<Artifact> artifacts = ArtifactUtil.getArtifactsContainingModuleOutput(module);
for (Artifact artifact : artifacts) {
if (artifactType.equals(artifact.getArtifactType())) {
return artifact;
}
}
ArtifactManager artifactManager = ArtifactManager.getInstance(module.getProject());
PackagingElementFactory elementFactory = PackagingElementFactory.getInstance();
ArtifactRootElement<?> root = elementFactory.createArtifactRootElement();
elementFactory.getOrCreateDirectory(root, "WEB-INF/classes").addOrFindChild(elementFactory.createModuleOutput(module));
return artifactManager.addArtifact(module.getName(), artifactType, root);
}
private static Library addProjectLibrary(final Module module, final String name, final List<String> jarDirectories, final VirtualFile[] sources) {
return new WriteAction<Library>() {
protected void run(final Result<Library> result) {
final LibraryTable libraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(module.getProject());
Library library = libraryTable.getLibraryByName(name);
if (library == null) {
library = libraryTable.createLibrary(name);
final Library.ModifiableModel model = library.getModifiableModel();
for (String path : jarDirectories) {
String url = VfsUtilCore.pathToUrl(path);
VirtualFileManager.getInstance().refreshAndFindFileByUrl(url);
model.addJarDirectory(url, false);
}
for (VirtualFile sourceRoot : sources) {
model.addRoot(sourceRoot, OrderRootType.SOURCES);
}
model.commit();
}
result.setResult(library);
}
}.execute().getResultObject();
}
private VirtualFile findOrCreateChildDirectory(VirtualFile parent, final String name) throws IOException {
VirtualFile child = parent.findChild(name);
if (child != null) {
return child;
}
return parent.createChildDirectory(this, name);
}
@NotNull
@Override
public FrameworkSupportConfigurableBase createConfigurable(@NotNull FrameworkSupportModel model) {
return new AppEngineSupportConfigurable(model);
}
private class AppEngineSupportConfigurable extends FrameworkSupportConfigurableBase implements FrameworkSupportModelListener {
private JPanel myMainPanel;
private final AppEngineSdkEditor mySdkEditor;
private JComboBox myPersistenceApiComboBox;
private JPanel mySdkPanel;
private final HyperlinkLabel myErrorLabel;
private JPanel myErrorPanel;
private AppEngineSupportConfigurable(FrameworkSupportModel model) {
super(AppEngineSupportProvider.this, model);
mySdkEditor = new AppEngineSdkEditor(model.getProject());
mySdkPanel.add(LabeledComponent.create(mySdkEditor.getMainComponent(), "Google App Engine SDK:"), BorderLayout.CENTER);
PersistenceApiComboboxUtil.setComboboxModel(myPersistenceApiComboBox, true);
if (model.isFrameworkSelected(JPA_PROVIDER_ID)) {
myPersistenceApiComboBox.setSelectedItem(PersistenceApi.JPA.getDisplayName());
}
model.addFrameworkListener(this);
myErrorLabel = new HyperlinkLabel();
myErrorLabel.setIcon(AllIcons.RunConfigurations.ConfigurationWarning);
myErrorLabel.setVisible(false);
myErrorLabel.setHyperlinkTarget(AppEngineSdkUtil.APP_ENGINE_DOWNLOAD_URL);
myErrorPanel.add(BorderLayout.CENTER, myErrorLabel);
final Component component = mySdkEditor.getComboBox().getEditor().getEditorComponent();
if (component instanceof JTextComponent) {
((JTextComponent)component).getDocument().addDocumentListener(new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
checkSdk();
}
});
}
checkSdk();
}
private void checkSdk() {
final String path = mySdkEditor.getPath();
if (StringUtil.isEmptyOrSpaces(path)) {
myErrorLabel.setVisible(true);
myErrorLabel.setHyperlinkText("App Engine SDK path not specified. ", "Download", "");
myMainPanel.repaint();
return;
}
final ValidationResult result = AppEngineSdkUtil.checkPath(path);
myErrorLabel.setVisible(!result.isOk());
if (!result.isOk()) {
myErrorLabel.setText("App Engine SDK path is not correct");
}
myMainPanel.repaint();
}
public void frameworkSelected(@NotNull FrameworkSupportProvider provider) {
if (provider.getId().equals(JPA_PROVIDER_ID)) {
myPersistenceApiComboBox.setSelectedItem(PersistenceApi.JPA.getDisplayName());
}
}
public void frameworkUnselected(@NotNull FrameworkSupportProvider provider) {
if (provider.getId().equals(JPA_PROVIDER_ID)) {
myPersistenceApiComboBox.setSelectedItem(PersistenceApiComboboxUtil.NONE_ITEM);
}
}
@Override
public void wizardStepUpdated() {
}
@Override
public void addSupport(@NotNull Module module, @NotNull ModifiableRootModel rootModel, @Nullable Library library) {
AppEngineSupportProvider.this.addSupport(module, rootModel, mySdkEditor.getPath(), PersistenceApiComboboxUtil.getSelectedApi(myPersistenceApiComboBox));
}
@Override
public JComponent getComponent() {
return myMainPanel;
}
}
}