/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.ide.ext.java.client.newsourcefile; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.project.gwt.client.ProjectServiceClient; import org.eclipse.che.api.project.shared.dto.ItemReference; import org.eclipse.che.api.promises.client.Function; import org.eclipse.che.api.promises.client.FunctionException; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.project.node.HasStorablePath; import org.eclipse.che.ide.api.project.node.HasStorablePath.StorablePath; import org.eclipse.che.ide.api.project.node.Node; import org.eclipse.che.ide.ext.java.client.project.node.PackageNode; import org.eclipse.che.ide.part.explorer.project.ProjectExplorerPresenter; import org.eclipse.che.ide.project.node.FileReferenceNode; import org.eclipse.che.ide.project.node.FolderReferenceNode; import org.eclipse.che.ide.rest.AsyncRequestCallback; import org.eclipse.che.ide.rest.DtoUnmarshallerFactory; import org.eclipse.che.ide.rest.Unmarshallable; import org.eclipse.che.ide.ui.dialogs.DialogFactory; import javax.validation.constraints.NotNull; import java.util.Arrays; import java.util.List; import static org.eclipse.che.ide.ext.java.client.JavaUtils.checkCompilationUnitName; import static org.eclipse.che.ide.ext.java.client.JavaUtils.checkPackageName; import static org.eclipse.che.ide.ext.java.client.JavaUtils.isValidCompilationUnitName; import static org.eclipse.che.ide.ext.java.client.JavaUtils.isValidPackageName; import static org.eclipse.che.ide.ext.java.client.newsourcefile.JavaSourceFileType.ANNOTATION; import static org.eclipse.che.ide.ext.java.client.newsourcefile.JavaSourceFileType.CLASS; import static org.eclipse.che.ide.ext.java.client.newsourcefile.JavaSourceFileType.ENUM; import static org.eclipse.che.ide.ext.java.client.newsourcefile.JavaSourceFileType.INTERFACE; /** * Presenter for creating Java source file. * * @author Artem Zatsarynnyi */ @Singleton public class NewJavaSourceFilePresenter implements NewJavaSourceFileView.ActionDelegate { private static final String DEFAULT_CONTENT = " {\n}\n"; private final ProjectExplorerPresenter projectExplorer; private final NewJavaSourceFileView view; private final ProjectServiceClient projectServiceClient; private final DtoUnmarshallerFactory dtoUnmarshaller; private final List<JavaSourceFileType> sourceFileTypes; private final DialogFactory dialogFactory; private final String workspaceId; @Inject public NewJavaSourceFilePresenter(NewJavaSourceFileView view, ProjectExplorerPresenter projectExplorer, AppContext appContext, ProjectServiceClient projectServiceClient, DtoUnmarshallerFactory dtoUnmarshaller, DialogFactory dialogFactory) { this.dialogFactory = dialogFactory; sourceFileTypes = Arrays.asList(CLASS, INTERFACE, ENUM, ANNOTATION); this.view = view; this.projectExplorer = projectExplorer; this.projectServiceClient = projectServiceClient; this.dtoUnmarshaller = dtoUnmarshaller; this.view.setDelegate(this); this.workspaceId = appContext.getWorkspace().getId(); } public void showDialog() { view.setTypes(sourceFileTypes); view.showDialog(); } @Override public void onCancelClicked() { view.close(); } @Override public void onNameChanged() { try { final String fileNameWithExtension = getFileNameWithExtension(view.getName()); if (!fileNameWithExtension.trim().isEmpty()) { checkCompilationUnitName(fileNameWithExtension); } final String packageName = getPackageFragment(view.getName()); if (!packageName.trim().isEmpty()) { checkPackageName(packageName); } view.hideErrorHint(); } catch (IllegalStateException e) { view.showErrorHint(e.getMessage()); } } @Override public void onOkClicked() { final String fileNameWithExtension = getFileNameWithExtension(view.getName()); final String fileNameWithoutExtension = fileNameWithExtension.substring(0, fileNameWithExtension.lastIndexOf(".java")); final String packageFragment = getPackageFragment(view.getName()); if (!packageFragment.isEmpty() && !isValidPackageName(packageFragment)) { return; } if (isValidCompilationUnitName(fileNameWithExtension)) { view.close(); FolderReferenceNode parent = (FolderReferenceNode)projectExplorer.getSelection().getHeadElement(); switch (view.getSelectedType()) { case CLASS: createClass(fileNameWithoutExtension, parent, packageFragment); break; case INTERFACE: createInterface(fileNameWithoutExtension, parent, packageFragment); break; case ENUM: createEnum(fileNameWithoutExtension, parent, packageFragment); break; case ANNOTATION: createAnnotation(fileNameWithoutExtension, parent, packageFragment); break; } } } private String getFileNameWithExtension(String name) { if (name.endsWith(".java")) { name = name.substring(0, name.lastIndexOf(".java")); } final int lastDotPos = name.lastIndexOf('.'); name = name.substring(lastDotPos + 1); return name + ".java"; } private String getPackageFragment(String name) { if (name.endsWith(".java")) { name = name.substring(0, name.lastIndexOf(".java")); } final int lastDotPos = name.lastIndexOf('.'); if (lastDotPos >= 0) { return name.substring(0, lastDotPos); } return ""; } private void createClass(String name, FolderReferenceNode parent, String packageFragment) { String content = getPackageQualifier(parent, packageFragment) + "public class " + name + DEFAULT_CONTENT; createSourceFile(name, parent, packageFragment, content); } private void createInterface(String name, FolderReferenceNode parent, String packageFragment) { String content = getPackageQualifier(parent, packageFragment) + "public interface " + name + DEFAULT_CONTENT; createSourceFile(name, parent, packageFragment, content); } private void createEnum(String name, FolderReferenceNode parent, String packageFragment) { String content = getPackageQualifier(parent, packageFragment) + "public enum " + name + DEFAULT_CONTENT; createSourceFile(name, parent, packageFragment, content); } private void createAnnotation(String name, FolderReferenceNode parent, String packageFragment) { String content = getPackageQualifier(parent, packageFragment) + "public @interface " + name + DEFAULT_CONTENT; createSourceFile(name, parent, packageFragment, content); } private String getPackageQualifier(FolderReferenceNode parent, String packageFragment) { String packageFQN = ""; if (parent instanceof PackageNode) { packageFQN = ((PackageNode)parent).getPackage(); } if (!packageFragment.isEmpty()) { packageFQN = packageFQN.isEmpty() ? packageFragment : packageFQN + '.' + packageFragment; } if (!packageFQN.isEmpty()) { return "package " + packageFQN + ";\n\n"; } return "\n"; } private void createSourceFile(final String nameWithoutExtension, final FolderReferenceNode parent, String packageFragment, final String content) { final String path = parent.getStorablePath() + (packageFragment.isEmpty() ? "" : '/' + packageFragment.replace('.', '/')); getOrCreateFolder(path).thenPromise(createFile(nameWithoutExtension, content)) .thenPromise(navigateToNode()) .then(selectNode()) .then(openNode()) .catchError(onFailedFileCreation()); } private Operation<PromiseError> onFailedFileCreation() { return new Operation<PromiseError>() { @Override public void apply(PromiseError arg) throws OperationException { dialogFactory.createMessageDialog("Cannot create java file", arg.getMessage(), null).show(); } }; } private Function<ItemReference, Promise<Node>> navigateToNode() { return new Function<ItemReference, Promise<Node>>() { @Override public Promise<Node> apply(ItemReference createdItem) throws FunctionException { final HasStorablePath path = new StorablePath(createdItem.getPath()); return projectExplorer.getNodeByPath(path, true); } }; } private Function<ItemReference, Promise<ItemReference>> createFile(final String nameWithoutExtension, final String content) { return new Function<ItemReference, Promise<ItemReference>>() { @Override public Promise<ItemReference> apply(ItemReference folder) throws FunctionException { return AsyncPromiseHelper.createFromAsyncRequest(createFileRC(folder, nameWithoutExtension, content)); } }; } private AsyncPromiseHelper.RequestCall<ItemReference> createFileRC(final ItemReference folder, final String nameWithoutExtension, final String content) { return new AsyncPromiseHelper.RequestCall<ItemReference>() { @Override public void makeCall(AsyncCallback<ItemReference> callback) { projectServiceClient.createFile(workspaceId, folder.getPath(), nameWithoutExtension + ".java", content, _callback(callback, dtoUnmarshaller.newUnmarshaller(ItemReference.class))); } }; } private Promise<ItemReference> getOrCreateFolder(String path) { return AsyncPromiseHelper.createFromAsyncRequest(getFolderRC(path)) .catchErrorPromise(catchAndCreateFolder(path)); } private AsyncPromiseHelper.RequestCall<ItemReference> getFolderRC(final String path) { return new AsyncPromiseHelper.RequestCall<ItemReference>() { @Override public void makeCall(AsyncCallback<ItemReference> callback) { projectServiceClient.getItem(workspaceId, path, _callback(callback, dtoUnmarshaller.newUnmarshaller(ItemReference.class))); } }; } @NotNull protected <T> AsyncRequestCallback<T> _callback(@NotNull final AsyncCallback<T> callback, @NotNull Unmarshallable<T> u) { return new AsyncRequestCallback<T>(u) { @Override protected void onSuccess(T result) { callback.onSuccess(result); } @Override protected void onFailure(Throwable e) { callback.onFailure(e); } }; } private Function<PromiseError, Promise<ItemReference>> catchAndCreateFolder(final String path) { return new Function<PromiseError, Promise<ItemReference>>() { @Override public Promise<ItemReference> apply(PromiseError arg) throws FunctionException { return createFolder(path); } }; } private Promise<ItemReference> createFolder(String path) { return AsyncPromiseHelper.createFromAsyncRequest(createFolderRC(path)); } private AsyncPromiseHelper.RequestCall<ItemReference> createFolderRC(final String path) { return new AsyncPromiseHelper.RequestCall<ItemReference>() { @Override public void makeCall(AsyncCallback<ItemReference> callback) { projectServiceClient.createFolder(workspaceId, path, _callback(callback, dtoUnmarshaller.newUnmarshaller(ItemReference.class))); } }; } protected Function<Node, Node> selectNode() { return new Function<Node, Node>() { @Override public Node apply(Node node) throws FunctionException { projectExplorer.select(node, false); return node; } }; } protected Function<Node, Node> openNode() { return new Function<Node, Node>() { @Override public Node apply(Node node) throws FunctionException { if (node instanceof FileReferenceNode) { ((FileReferenceNode)node).actionPerformed(); } return node; } }; } }