/** * Copyright 2014 Microsoft Open Technologies Inc. * * 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.microsoftopentechnologies.intellij.wizards.activityConfiguration; import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.project.ProjectData; import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode; import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback; import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; import com.intellij.openapi.externalSystem.util.DisposeAwareProjectChange; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ex.ProjectRootManagerEx; import com.intellij.ui.wizard.WizardNavigationState; import com.intellij.ui.wizard.WizardStep; import com.microsoft.directoryservices.Application; import com.microsoft.services.odata.ODataException; import com.microsoft.services.odata.interfaces.ODataResponse; import com.microsoftopentechnologies.intellij.helpers.ServiceCodeReferenceHelper; import com.microsoftopentechnologies.intellij.helpers.UIHelper; import com.microsoftopentechnologies.intellij.helpers.o365.Office365Manager; import com.microsoftopentechnologies.intellij.helpers.o365.Office365RestAPIManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.util.GradleConstants; import javax.swing.*; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import java.awt.*; import java.util.Collections; import java.util.concurrent.ExecutionException; public class SummaryStep extends WizardStep<AddServiceWizardModel> { private final AddServiceWizardModel model; private JPanel rootPanel; private JEditorPane editorSummary; public SummaryStep(final String title, AddServiceWizardModel model) { super(title, null, null); this.model = model; this.editorSummary.addHyperlinkListener(new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { try { Desktop.getDesktop().browse(e.getURL().toURI()); } catch (Exception ex) { UIHelper.showException("Unable to follow link.", ex); } } } }); } @Override public JComponent prepare(WizardNavigationState state) { rootPanel.revalidate(); StringBuilder summary = new StringBuilder(); summary.append("<html> <head> </head> <body style=\"font-family: sans serif;\"> <p style=\"margin-top: 0\">" + "<b>Summary:</b></p> <ol> "); if (this.model.getService() != null || this.model.getHubName() != null) { if (this.model.getService() != null) { summary.append("<li>Added a reference to the Azure Mobile Services library in project <b>"); summary.append(this.model.getProject().getName()); summary.append("</b>.</li> "); summary.append("<li>Added a static method to instantiate MobileServiceClient, connecting to <b>"); summary.append(this.model.getService().getName()); summary.append("</b>.</li> "); } if (this.model.getHubName() != null) { summary.append("<li>Added <a href=\"https://go.microsoft.com/fwLink/?LinkID=280126&clcid=0x409\">" + "Notification Hub</a> library to project <b>"); summary.append(this.model.getProject().getName()); summary.append("</b>.</li> "); summary.append("<li>Added a helper class extending NotificationsHandler, using Notification Hub <b>"); summary.append(this.model.getHubName()); summary.append("</b>.</li> "); summary.append("<li>Added a static method to handle notifications using NotificationHubsHelper.</li> "); } summary.append("<li>Configured the Azure Services Activity referencing the mentioned static methods.</li> "); if (this.model.getService() != null) { summary.append("<li>You can follow the link to <a href=\"https://github.com/Azure/azure-mobile-services/\">" + "Azure Mobile Services SDK</a> to learn more about the referenced libraries.</li> "); } } else if (this.model.isOutlookServices() || this.model.isFileServices() || this.model.isListServices()) { if (this.model.isOutlookServices()) { summary.append("<li>Added a reference to the Outlook Services library in project <b>"); summary.append(this.model.getProject().getName()); summary.append("</b>.</li> "); summary.append("<li>Added a static method to instantiate OutlookClient and list messages.</li> "); } if (this.model.isFileServices()) { summary.append("<li>Added a reference to the File Services library in project <b>"); summary.append(this.model.getProject().getName()); summary.append("</b>.</li> "); summary.append("<li>Added a static method to instantiate SharePointClient and list files.</li> "); } if (this.model.isListServices()) { summary.append("<li>Added a reference to the SharePoint Lists library in project <b>"); summary.append(this.model.getProject().getName()); summary.append("</b>.</li> "); summary.append("<li>Added a static method to instantiate SharepointListsClient and enumerate lists.</li> "); } summary.append("<li>Configured the Office 365 Activity referencing the mentioned static methods.</li> "); summary.append("<li>You can follow the link to <a href=\"https://github.com/OfficeDev/Office-365-SDK-for-Android\">" + "Office 365 SDK for Android</a> to learn more about the referenced libraries.</li> "); } summary.append("</ol> <p style=\"margin-top: 0\">After clicking Finish, it might take a few seconds to " + "complete set up.</p> </body> </html>"); editorSummary.setText(summary.toString()); return rootPanel; } @Override public boolean onFinish() { final SummaryStep summaryStep = this; ProgressManager.getInstance().run(new Task.Backgroundable(this.model.getProject(), "Setting up project for Microsoft services...", false) { @Override public void run(@NotNull ProgressIndicator progressIndicator) { try { progressIndicator.setFraction(0.1d); double totalSteps = model.getServiceTypes().size(); double steps = 0d; if (summaryStep.model.getService() != null) { progressIndicator.setText("Setting up Azure Mobile Services"); summaryStep.associateMobileService(); steps++; progressIndicator.setFraction(steps / totalSteps); } if (summaryStep.model.getHubName() != null) { progressIndicator.setText("Setting up Azure Notification Hubs"); summaryStep.associateNotificationHub(); steps++; progressIndicator.setFraction(steps / totalSteps); } if (summaryStep.model.isOutlookServices() || summaryStep.model.isFileServices() || summaryStep.model.isListServices()) { progressIndicator.setText("Setting up Office 365 Services"); summaryStep.associateOffice365(); steps++; progressIndicator.setFraction(steps / totalSteps); } // just for Notification Hubs. Mobile Services and Office 365 already triggered gradle sync - avoid conflict if (summaryStep.model.getHubName() != null) { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { try { //scheduled a gradle sync project action from the android/gradle plugin final ProjectDataManager projectDataManager = ServiceManager.getService(ProjectDataManager.class); ExternalSystemUtil.refreshProject(myProject, GradleConstants.SYSTEM_ID, myProject.getBaseDir().getCanonicalPath() != null ? myProject.getBaseDir().getCanonicalPath() : myProject.getBaseDir().getPath(), new ExternalProjectRefreshCallback() { @Override public void onSuccess(@Nullable final DataNode<ProjectData> externalProject) { if (externalProject == null) { return; } ExternalSystemApiUtil.executeProjectChangeAction(true, new DisposeAwareProjectChange(myProject) { @Override public void execute() { ProjectRootManagerEx.getInstanceEx(myProject).mergeRootsChangesDuring(new Runnable() { @Override public void run() { projectDataManager.importData(externalProject.getKey(), Collections.singleton(externalProject), myProject, true); } }); } }); } @Override public void onFailure(@NotNull String errorMessage, @Nullable String errorDetails) { } }, false, ProgressExecutionMode.IN_BACKGROUND_ASYNC); } catch (Throwable ex) { UIHelper.showException("Error invoking Gradle build", ex); } } }, ModalityState.NON_MODAL); } } catch (Throwable ex) { UIHelper.showException("Error setting up Microsoft services", ex); } } }); return super.onFinish(); } private void associateMobileService() { final Project project = this.model.getProject(); final Module module = this.model.getModule(); final String activityName = this.model.getActivityName(); final String appUrl = this.model.getService().getAppUrl(); final String appKey = this.model.getService().getAppKey(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { try { ServiceCodeReferenceHelper scrh = new ServiceCodeReferenceHelper(project, module); scrh.fillMobileServiceResource(activityName, appUrl, appKey); } catch (Throwable ex) { UIHelper.showException("Error creating Service helper", ex); } } }); } }, ModalityState.NON_MODAL); } private void associateNotificationHub() { final Project project = this.model.getProject(); final Module module = this.model.getModule(); final String activityName = this.model.getActivityName(); final String senderId = this.model.getSenderId(); final String connStr = this.model.getConnectionString(); final String hubName = this.model.getHubName(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { try { ServiceCodeReferenceHelper scrh = new ServiceCodeReferenceHelper(project, module); scrh.addNotificationHubsLibs(); scrh.fillNotificationHubResource(activityName, senderId, connStr, hubName); } catch (Throwable ex) { UIHelper.showException("Error:", ex); } } }); } }, ModalityState.NON_MODAL); } private void associateOffice365() { final Project project = this.model.getProject(); final Module module = this.model.getModule(); final String activityName = this.model.getActivityName(); final String appId = this.model.getOfficeApp().getappId(); final String name = this.model.getOfficeApp().getdisplayName(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { try { ServiceCodeReferenceHelper scrh = new ServiceCodeReferenceHelper(project, module); scrh.fillOffice365Resource(activityName, appId, name); } catch (Throwable ex) { UIHelper.showException("Error:", ex); } } }); } }, ModalityState.NON_MODAL); updateO365Permission(); } private void updateO365Permission() { try { // update graph api final Office365Manager manager = Office365RestAPIManager.getManager(); ListenableFuture<Application> future = manager.setO365PermissionsForApp(model.getOfficeApp(), model.getOfficePermissions()); future.get(); } catch (ExecutionException ex) { String message = ""; if (ex.getCause() instanceof ODataException) { message = parseODataException((ODataException) ex.getCause()); } if (!message.isEmpty()) { UIHelper.showException("An error occurred while trying to associate the Office 365 application - " + message, ex.getCause(), "Error associating Office 365 application", false, false); } else { UIHelper.showException("An error occurred while trying to associate the Office 365 application", ex.getCause(), "Error associating Office 365 application"); } } catch (Throwable ex) { UIHelper.showException("An error occurred while trying to associate the Office 365 application", ex, "Error associating Office 365 application"); } } @NotNull private static String parseODataException(@NotNull ODataException oDataException) { String result = ""; ODataResponse oDataResponse = oDataException.getODataResponse(); if (oDataResponse != null) { if (oDataResponse.getPayload() != null) { try { String json = new String(oDataResponse.getPayload(), "UTF-8"); JsonObject errorJson = new JsonParser().parse(json).getAsJsonObject(); result = errorJson.get("odata.error").getAsJsonObject() .get("message").getAsJsonObject() .get("value").getAsString(); } catch (Throwable ignored) { } } else if (oDataResponse.getResponse() != null) { int status = oDataResponse.getResponse().getStatus(); switch (status) { case 403: result = "Authorization error - Status 403"; break; default: break; } } } return result; } }