/**
* 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;
import com.intellij.ide.plugins.cl.PluginClassLoader;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.util.PlatformUtilsCore;
import com.interopbridges.tools.windowsazure.WindowsAzureProjectManager;
import com.microsoftopentechnologies.azurecommons.deploy.DeploymentEventArgs;
import com.microsoftopentechnologies.azurecommons.deploy.DeploymentEventListener;
import com.microsoftopentechnologies.azurecommons.wacommonutil.FileUtil;
import com.microsoftopentechnologies.intellij.ui.messages.AzureBundle;
import com.microsoftopentechnologies.intellij.util.WAHelper;
import javax.swing.event.EventListenerList;
import java.io.*;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static com.microsoftopentechnologies.intellij.ui.messages.AzureBundle.message;
public class AzurePlugin extends AbstractProjectComponent {
private static final Logger LOG = Logger.getInstance("#com.microsoftopentechnologies.intellij.AzurePlugin");
public static final String PLUGIN_ID = "msopentech-tools-for-intellij";
private static final String COMPONENTSETS_VERSION = "2.5.2"; // todo: temporary fix!
private static final String PREFERENCESETS_VERSION = "2.5.1";
public final static int REST_SERVICE_MAX_RETRY_COUNT = 7;
public static boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().indexOf("win") >= 0;
public static boolean IS_ANDROID_STUDIO = "AndroidStudio".equals(PlatformUtilsCore.getPlatformPrefix());
private static final String COMPONENTSETS_TYPE = "COMPONENTSETS";
private static final String PREFERENCESETS_TYPE = "PREFERENCESETS";
public static File cmpntFile = new File(WAHelper.getTemplateFile(message("cmpntFileName")));
public static String prefFilePath = WAHelper.getTemplateFile(message("prefFileName"));
public static String pluginFolder = String.format("%s%s%s", PathManager.getPluginsPath(), File.separator, AzurePlugin.PLUGIN_ID);
private static final EventListenerList DEPLOYMENT_EVENT_LISTENERS = new EventListenerList();
public static List<DeploymentEventListener> depEveList = new ArrayList<DeploymentEventListener>();
private final AzureSettings azureSettings;
public AzurePlugin(Project project) {
super(project);
this.azureSettings = AzureSettings.getSafeInstance(project);
}
public void projectOpened() {
}
public void projectClosed() {
}
/**
* Method is called after plugin is already created and configured. Plugin can start to communicate with
* other plugins only in this method.
*/
public void initComponent() {
if (!IS_ANDROID_STUDIO && IS_WINDOWS) {
LOG.info("Starting Azure Plugin");
try {
azureSettings.loadStorage();
//this code is for copying componentset.xml in plugins folder
copyPluginComponents();
} catch (Exception e) {
/* This is not a user initiated task
So user should not get any exception prompt.*/
LOG.error(AzureBundle.message("expErlStrtUp"), e);
}
}
}
public String getComponentName() {
return "MSOpenTechTools.AzurePlugin";
}
/**
* Copies all Eclipse plugin for Azure
* related files in eclipse plugins folder at startup.
*/
private void copyPluginComponents() {
try {
String pluginInstLoc = String.format("%s%s%s", PathManager.getPluginsPath(), File.separator, PLUGIN_ID);
String cmpntFile = String.format("%s%s%s", pluginInstLoc,
File.separator, AzureBundle.message("cmpntFileName"));
String starterKit = String.format("%s%s%s", pluginInstLoc,
File.separator, AzureBundle.message("starterKitFileName"));
String enctFile = String.format("%s%s%s", pluginInstLoc,
File.separator, message("encFileName"));
String prefFile = String.format("%s%s%s", pluginInstLoc,
File.separator, AzureBundle.message("prefFileName"));
// upgrade component sets and preference sets
upgradePluginComponent(cmpntFile, AzureBundle.message("cmpntFileEntry"), AzureBundle.message("oldCmpntFileEntry"), COMPONENTSETS_TYPE);
upgradePluginComponent(prefFile, AzureBundle.message("prefFileEntry"), AzureBundle.message("oldPrefFileEntry"), PREFERENCESETS_TYPE);
// Check for WAStarterKitForJava.zip
if (new File(starterKit).exists()) {
new File(starterKit).delete();
}
// Check for encutil.exe
if (new File(enctFile).exists()) {
new File(enctFile).delete();
}
copyResourceFile(message("starterKitEntry"), starterKit);
copyResourceFile(message("encFileName"), enctFile);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
/**
* Checks for pluginComponent file.
* If exists checks its version.
* If it has latest version then no upgrade action is needed,
* else checks with older componentsets.xml,
* if identical then deletes existing and copies new one
* else renames existing and copies new one.
* @param pluginComponentPath
* @param resource
* @param componentType
* @throws Exception
*/
private void upgradePluginComponent(String pluginComponentPath, String resource,
String oldResource, String componentType) throws Exception {
File pluginComponentFile = new File(pluginComponentPath);
if (pluginComponentFile.exists()) {
String pluginComponentVersion = null;
String resourceFileVersion = null;
// File resourceFile = new File(((PluginClassLoader)AzurePlugin.class.getClassLoader()).findResource(resource).toURI());
try {
if (COMPONENTSETS_TYPE.equals(componentType)) {
pluginComponentVersion = WindowsAzureProjectManager.getComponentSetsVersion(pluginComponentFile);
resourceFileVersion = COMPONENTSETS_VERSION; //WindowsAzureProjectManager.getComponentSetsVersion(resourceFile);
} else {
pluginComponentVersion = WindowsAzureProjectManager.getPreferenceSetsVersion(pluginComponentFile);
resourceFileVersion = PREFERENCESETS_VERSION; //WindowsAzureProjectManager.getPreferenceSetsVersion(resourceFile);
}
} catch(Exception e ) {
LOG.error("Error occured while getting version of plugin component " + componentType + ", considering version as null");
}
if ((pluginComponentVersion != null
&& !pluginComponentVersion.isEmpty())
&& pluginComponentVersion.equals(resourceFileVersion)) {
// Do not do anything
} else {
// Check with old plugin component for upgrade scenarios
URL oldPluginComponentUrl = ((PluginClassLoader)AzurePlugin.class.getClassLoader()).findResource(oldResource);
// InputStream oldPluginComponentIs = AzurePlugin.class.getResourceAsStream(oldResourceFile);
boolean isIdenticalWithOld = WAHelper.isFilesIdentical(oldPluginComponentUrl, pluginComponentFile);
if (isIdenticalWithOld) {
// Delete old one
pluginComponentFile.delete();
} else {
// Rename old one
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
WAHelper.copyFile(pluginComponentPath, pluginComponentPath + ".old" + dateFormat.format(date));
}
copyResourceFile(resource, pluginComponentPath);
}
} else {
copyResourceFile(resource, pluginComponentPath);
}
}
/**
* Method copies specified file from plugin resources
* @param resourceFile
* @param destFile
*/
public static void copyResourceFile(String resourceFile, String destFile) {
try {
InputStream is = ((PluginClassLoader)AzurePlugin.class.getClassLoader()).findResource(resourceFile).openStream();
File outputFile = new File(destFile);
FileOutputStream fos = new FileOutputStream(outputFile);
FileUtil.writeFile(is, fos);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
}
public static void fireDeploymentEvent(DeploymentEventArgs args) {
Object[] list = DEPLOYMENT_EVENT_LISTENERS.getListenerList();
for (int i = 0; i < list.length; i += 2) {
if (list[i] == DeploymentEventListener.class) {
((DeploymentEventListener) list[i + 1]).onDeploymentStep(args);
}
}
}
public static void addDeploymentEventListener(DeploymentEventListener listener) {
DEPLOYMENT_EVENT_LISTENERS.add(DeploymentEventListener.class, listener);
}
public static void removeDeploymentEventListener(DeploymentEventListener listener) {
DEPLOYMENT_EVENT_LISTENERS.remove(DeploymentEventListener.class, listener);
}
// todo: move field somewhere?
public static void removeUnNecessaryListener() {
for (int i = 0 ; i < depEveList.size(); i++) {
removeDeploymentEventListener(depEveList.get(i));
}
depEveList.clear();
}
public static void log(String message, Exception ex) {
LOG.error(message, ex);
LOG.info(message);
}
public static void log(String message) {
LOG.info(message);
}
}