configuration elements can be installed from repositories
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 2 Jun 2016 06:21:28 +0000 (09:21 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 2 Jun 2016 06:21:28 +0000 (09:21 +0300)
src/java/netxms-eclipse/Market/icons/install.gif [new file with mode: 0644]
src/java/netxms-eclipse/Market/plugin.xml
src/java/netxms-eclipse/Market/src/org/netxms/ui/eclipse/market/Activator.java
src/java/netxms-eclipse/Market/src/org/netxms/ui/eclipse/market/objects/RepositoryElement.java
src/java/netxms-eclipse/Market/src/org/netxms/ui/eclipse/market/objects/RepositoryRuntimeInfo.java
src/java/netxms-eclipse/Market/src/org/netxms/ui/eclipse/market/views/RepositoryManager.java
src/java/netxms-eclipse/Market/src/org/netxms/ui/eclipse/market/views/helpers/RepositoryLabelProvider.java

diff --git a/src/java/netxms-eclipse/Market/icons/install.gif b/src/java/netxms-eclipse/Market/icons/install.gif
new file mode 100644 (file)
index 0000000..d38085a
Binary files /dev/null and b/src/java/netxms-eclipse/Market/icons/install.gif differ
index b5a5e27..e3c9fb0 100644 (file)
             id="org.netxms.ui.eclipse.market.commands.openRepositoryManager"
             name="Repository Manager">
       </command>
+      <command
+            id="org.netxms.ui.eclipse.market.commands.mark"
+            name="Mark for installation">
+      </command>
+      <command
+            id="org.netxms.ui.eclipse.market.commands.unmark"
+            name="Unmark for installation">
+      </command>
+      <command
+            id="org.netxms.ui.eclipse.market.commands.install"
+            name="Install">
+      </command>
    </extension>
    <extension
          point="org.eclipse.ui.bindings">
             schemeId="org.netxms.ui.eclipse.defaultKeyBinding"
             sequence="M1+F2">
       </key>
+      <key
+            commandId="org.netxms.ui.eclipse.market.commands.mark"
+            contextId="org.netxms.ui.eclipse.market.context.RepositoryManager"
+            schemeId="org.netxms.ui.eclipse.defaultKeyBinding"
+            sequence="M1+M">
+      </key>
+      <key
+            commandId="org.netxms.ui.eclipse.market.commands.unmark"
+            contextId="org.netxms.ui.eclipse.market.context.RepositoryManager"
+            schemeId="org.netxms.ui.eclipse.defaultKeyBinding"
+            sequence="M1+U">
+      </key>
+      <key
+            commandId="org.netxms.ui.eclipse.market.commands.install"
+            contextId="org.netxms.ui.eclipse.market.context.RepositoryManager"
+            schemeId="org.netxms.ui.eclipse.defaultKeyBinding"
+            sequence="F2">
+      </key>
    </extension>
    <extension
          point="org.eclipse.ui.actionSets">
index dc10fdd..ff225c1 100644 (file)
@@ -17,6 +17,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */package org.netxms.ui.eclipse.market;
 
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.osgi.framework.BundleContext;
@@ -82,4 +83,35 @@ public class Activator extends AbstractUIPlugin
    {
       return imageDescriptorFromPlugin(PLUGIN_ID, path);
    }
+
+   /**
+    * Log via platform logging facilities
+    * 
+    * @param msg
+    */
+   public static void logInfo(String msg)
+   {
+      log(Status.INFO, msg, null);
+   }
+
+   /**
+    * Log via platform logging facilities
+    * 
+    * @param msg
+    */
+   public static void logError(String msg, Exception e)
+   {
+      log(Status.ERROR, msg, e);
+   }
+
+   /**
+    * Log via platform logging facilities
+    * 
+    * @param msg
+    * @param e
+    */
+   public static void log(int status, String msg, Exception e)
+   {
+      getDefault().getLog().log(new Status(status, PLUGIN_ID, Status.OK, msg, e));
+   }
 }
index 5f5be62..694c2e7 100644 (file)
  */
 package org.netxms.ui.eclipse.market.objects;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
 import java.util.UUID;
+import org.json.JSONArray;
+import org.json.JSONException;
 import org.json.JSONObject;
 
 /**
@@ -28,7 +35,9 @@ public abstract class RepositoryElement implements MarketObject
 {
    private UUID guid;
    private String name;
-   private MarketObject parent; 
+   private MarketObject parent;
+   private List<Instance> instances;
+   private boolean marked;
    
    /**
     * Create element from JSON object
@@ -41,6 +50,28 @@ public abstract class RepositoryElement implements MarketObject
       this.guid = guid;
       name = json.getString("name");
       parent = null;
+      marked = false;
+      
+      JSONArray a = json.getJSONArray("instances");
+      if (a != null)
+      {
+         instances = new ArrayList<Instance>(a.length());
+         for(int i = 0; i < a.length(); i++)
+         {
+            instances.add(new Instance(a.getJSONObject(i)));
+         }
+         Collections.sort(instances, new Comparator<Instance>() {
+            @Override
+            public int compare(Instance o1, Instance o2)
+            {
+               return o2.getVersion() - o1.getVersion();
+            }
+         });
+      }
+      else
+      {
+         instances = new ArrayList<Instance>(0);
+      }
    }   
    
    /* (non-Javadoc)
@@ -49,7 +80,7 @@ public abstract class RepositoryElement implements MarketObject
    @Override
    public String getName()
    {
-      return name;
+      return marked ? name + " *" : name;
    }
 
    /* (non-Javadoc)
@@ -97,4 +128,103 @@ public abstract class RepositoryElement implements MarketObject
    {
       this.parent = parent;
    }
+
+   /**
+    * @return the marked
+    */
+   public boolean isMarked()
+   {
+      return marked;
+   }
+
+   /**
+    * @param marked the marked to set
+    */
+   public void setMarked(boolean marked)
+   {
+      this.marked = marked;
+   }
+   
+   /**
+    * Get all instances of this element
+    * 
+    * @return
+    */
+   public List<Instance> getInstances()
+   {
+      return instances;
+   }
+   
+   /**
+    * Get most actual instance of this element
+    * 
+    * @return
+    */
+   public Instance getActualInstance()
+   {
+      return instances.isEmpty() ? null : instances.get(0);
+   }
+   
+   /**
+    * Get version of most actual instance
+    * 
+    * @return
+    */
+   public int getActualVersion()
+   {
+      return instances.isEmpty() ? 0 : instances.get(0).getVersion();
+   }
+   
+   /**
+    * Repository element's instance
+    */
+   public class Instance
+   {
+      private Date timestamp;
+      private int version;
+      private String comments;
+      
+      /**
+       * Create instance from JSON object
+       * 
+       * @param json
+       */
+      protected Instance(JSONObject json)
+      {
+         timestamp = new Date(json.getLong("timestamp") * 1000L);
+         version = json.getInt("version");
+         try
+         {
+            comments = json.getString("comment");
+         }
+         catch(JSONException e)
+         {
+            comments = "";
+         }
+      }
+
+      /**
+       * @return the timestamp
+       */
+      public Date getTimestamp()
+      {
+         return timestamp;
+      }
+
+      /**
+       * @return the version
+       */
+      public int getVersion()
+      {
+         return version;
+      }
+
+      /**
+       * @return the comments
+       */
+      public String getComments()
+      {
+         return comments;
+      }
+   }
 }
index 0292506..5110a0e 100644 (file)
  */
 package org.netxms.ui.eclipse.market.objects;
 
+import java.io.BufferedReader;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
 import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.ui.IViewPart;
 import org.json.JSONObject;
 import org.json.JSONTokener;
+import org.netxms.base.NXCommon;
 import org.netxms.client.market.Repository;
 import org.netxms.ui.eclipse.jobs.ConsoleJob;
 import org.netxms.ui.eclipse.market.Activator;
@@ -38,8 +46,11 @@ public class RepositoryRuntimeInfo implements MarketObject
 {
    private Repository repository;
    private Category events;
-   private Category templates;
+   private Category rules;
+   private Category scripts;
    private Category snmpTraps;
+   private Category summaryTables;
+   private Category templates;
    private LoadingPlaceholder loadingPlaceholder;
    private boolean loaded;
    
@@ -52,8 +63,11 @@ public class RepositoryRuntimeInfo implements MarketObject
    {
       this.repository = repository;
       events = new Category("Events", this);
-      templates = new Category("Templates", this);
+      rules = new Category("Rules", this);
+      scripts = new Category("Scripts", this);
       snmpTraps = new Category("SNMP Traps", this);
+      summaryTables = new Category("Summary Tables", this);
+      templates = new Category("Templates", this);
       loadingPlaceholder = new LoadingPlaceholder(this);
       loaded = false;
    }
@@ -69,8 +83,11 @@ public class RepositoryRuntimeInfo implements MarketObject
    {
       loaded = false;
       events.clear();
-      templates.clear();
+      rules.clear();
+      scripts.clear();
       snmpTraps.clear();
+      summaryTables.clear();
+      templates.clear();
       
       ConsoleJob job = new ConsoleJob("Load repository objects", viewPart, Activator.PLUGIN_ID, null) {
          @Override
@@ -120,6 +137,7 @@ public class RepositoryRuntimeInfo implements MarketObject
       {
          JSONTokener t = new JSONTokener(in);
          JSONObject root = new JSONObject(t);
+         Activator.logInfo("JSON received for repository " + repository.getDescription() + " (" + repository.getUrl() + "): " + root.toString());
          loadEvents(root, objects);
          loadTemplates(root, objects);
       }
@@ -207,7 +225,7 @@ public class RepositoryRuntimeInfo implements MarketObject
    @Override
    public MarketObject[] getChildren()
    {
-      return loaded ? new MarketObject[] { events, templates, snmpTraps } : new MarketObject[] { loadingPlaceholder };
+      return loaded ? new MarketObject[] { events, rules, scripts, snmpTraps, summaryTables, templates } : new MarketObject[] { loadingPlaceholder };
    }
 
    /* (non-Javadoc)
@@ -228,4 +246,95 @@ public class RepositoryRuntimeInfo implements MarketObject
    {
       return repository.getId();
    }
+   
+   /**
+    * Set/remove mark on all repository elements
+    * 
+    * @param marked
+    */
+   public void setAllMarked(boolean marked)
+   {
+      if (!loaded)
+         return;
+      
+      for(MarketObject o : getChildren())
+      {
+         for(MarketObject e : o.getChildren())
+         {
+            if (e instanceof RepositoryElement)
+               ((RepositoryElement)e).setMarked(marked);
+         }
+      }
+   }
+   
+   /**
+    * Get all marked elements within repository
+    * 
+    * @return
+    */
+   public List<RepositoryElement> getMarkedElements()
+   {
+      List<RepositoryElement> list = new ArrayList<RepositoryElement>();
+      if (!loaded)
+         return list;
+
+      for(MarketObject o : getChildren())
+      {
+         for(MarketObject e : o.getChildren())
+         {
+            if ((e instanceof RepositoryElement) && ((RepositoryElement)e).isMarked())
+               list.add((RepositoryElement)e);
+         }
+      }
+      return list;
+   }
+   
+   /**
+    * Load import file from repository
+    * 
+    * @param request
+    * @return
+    * @throws Exception
+    */
+   public String loadImportFile(String request) throws Exception
+   {
+      StringBuilder content = new StringBuilder();
+      URL url = new URL(repository.getUrl() + "/rest-api/get-items?accessToken=" + repository.getAuthToken());
+      
+      OutputStream out = null;
+      BufferedReader in = null;
+      
+      URLConnection conn = url.openConnection();
+      if (!(conn instanceof HttpURLConnection))
+      {
+         throw new Exception("Unsupported URL type");
+      }
+      ((HttpURLConnection)conn).setRequestMethod("POST");
+      ((HttpURLConnection)conn).setRequestProperty("User-Agent", "NetXMS Console/" + NXCommon.VERSION);
+      ((HttpURLConnection)conn).setRequestProperty("Content-Type", "application/json; charset=utf-8");
+      ((HttpURLConnection)conn).setDoOutput(true);
+      ((HttpURLConnection)conn).setAllowUserInteraction(false);
+      ((HttpURLConnection)conn).setUseCaches(false);
+      
+      try
+      {
+         out = conn.getOutputStream();
+         out.write(request.getBytes("utf-8"));
+         
+         in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+         String line;
+         while((line = in.readLine()) != null)
+         {
+            content.append(line);
+         }
+      }
+      finally
+      {
+         if (out != null)
+            out.close();
+         if (in != null)
+            in.close();
+      }
+      return content.toString();
+   }
 }
index ac0922d..78f8770 100644 (file)
@@ -53,6 +53,7 @@ import org.netxms.ui.eclipse.console.resources.SharedIcons;
 import org.netxms.ui.eclipse.jobs.ConsoleJob;
 import org.netxms.ui.eclipse.market.Activator;
 import org.netxms.ui.eclipse.market.dialogs.RepositoryPropertiesDlg;
+import org.netxms.ui.eclipse.market.objects.RepositoryElement;
 import org.netxms.ui.eclipse.market.objects.RepositoryRuntimeInfo;
 import org.netxms.ui.eclipse.market.views.helpers.RepositoryContentProvider;
 import org.netxms.ui.eclipse.market.views.helpers.RepositoryFilter;
@@ -83,6 +84,9 @@ public class RepositoryManager extends ViewPart
    private Action actionShowFilter;
    private Action actionAddRepository;
    private Action actionDelete;
+   private Action actionMark;
+   private Action actionUnmark;
+   private Action actionInstall;
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
@@ -232,6 +236,36 @@ public class RepositoryManager extends ViewPart
             deleteRepository();
          }
       };
+      
+      actionMark = new Action("&Mark for installation") {
+         @Override
+         public void run()
+         {
+            markForInstallation(true);
+         }
+      };
+      actionMark.setActionDefinitionId("org.netxms.ui.eclipse.market.commands.mark"); //$NON-NLS-1$
+      handlerService.activateHandler(actionMark.getActionDefinitionId(), new ActionHandler(actionMark));
+      
+      actionUnmark = new Action("&Unmark for installation") {
+         @Override
+         public void run()
+         {
+            markForInstallation(false);
+         }
+      };
+      actionUnmark.setActionDefinitionId("org.netxms.ui.eclipse.market.commands.unmark"); //$NON-NLS-1$
+      handlerService.activateHandler(actionUnmark.getActionDefinitionId(), new ActionHandler(actionUnmark));
+      
+      actionInstall = new Action("&Install", Activator.getImageDescriptor("icons/install.gif")) {
+         @Override
+         public void run()
+         {
+            install();
+         }
+      };
+      actionInstall.setActionDefinitionId("org.netxms.ui.eclipse.market.commands.install"); //$NON-NLS-1$
+      handlerService.activateHandler(actionInstall.getActionDefinitionId(), new ActionHandler(actionInstall));
    }
    
    /**
@@ -251,6 +285,8 @@ public class RepositoryManager extends ViewPart
     */
    private void fillLocalPullDown(IMenuManager manager)
    {
+      manager.add(actionInstall);
+      manager.add(new Separator());
       manager.add(actionAddRepository);
       manager.add(new Separator());
       manager.add(actionShowFilter);
@@ -265,6 +301,8 @@ public class RepositoryManager extends ViewPart
     */
    private void fillLocalToolBar(IToolBarManager manager)
    {
+      manager.add(actionInstall);
+      manager.add(new Separator());
       manager.add(actionAddRepository);
       manager.add(new Separator());
       manager.add(actionRefresh);
@@ -308,6 +346,23 @@ public class RepositoryManager extends ViewPart
       {
          mgr.add(actionDelete);
       }
+      else if (selectionContainsRepositoryElements(selection))
+      {
+         mgr.add(actionMark);
+         mgr.add(actionUnmark);
+      }
+   }
+   
+   /**
+    * @param selection
+    * @return
+    */
+   private static boolean selectionContainsRepositoryElements(IStructuredSelection selection)
+   {
+      for(Object o : selection.toList())
+         if (o instanceof RepositoryElement)
+            return true;
+      return false;
    }
    
    /**
@@ -446,4 +501,120 @@ public class RepositoryManager extends ViewPart
          }
       }.start();
    }
+   
+   /**
+    * Mark selected elements for installation
+    */
+   private void markForInstallation(boolean marked)
+   {
+      IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
+      for(Object o : selection.toList())
+      {
+         if (o instanceof RepositoryElement)
+            ((RepositoryElement)o).setMarked(marked);
+      }
+      viewer.refresh();
+   }
+   
+   /**
+    * Install selected elements
+    */
+   @SuppressWarnings("unchecked")
+   private void install()
+   {     
+      final List<InstallData> installData = new ArrayList<InstallData>();
+      ArrayList<RepositoryRuntimeInfo> repositories = (ArrayList<RepositoryRuntimeInfo>)viewer.getInput();
+      for(RepositoryRuntimeInfo r : repositories)
+      {
+         List<RepositoryElement> markedElements = r.getMarkedElements();
+         if (markedElements.isEmpty())
+            continue;
+
+         StringBuilder sb = new StringBuilder();
+         for(RepositoryElement e : markedElements)
+         {
+            if (sb.length() == 0)
+               sb.append("{ \"get-items\":[ ");
+            else
+               sb.append(", ");
+            sb.append("{ \"guid\":\"");
+            sb.append(e.getGuid().toString());
+            sb.append("\", \"version\":");
+            sb.append(e.getActualVersion());
+            sb.append(" }");
+         }
+         sb.append(" ] }");
+         installData.add(new InstallData(r, sb.toString()));
+      }
+      
+      if (installData.isEmpty())
+         return;
+      
+      actionInstall.setEnabled(false);
+      new ConsoleJob("Install items from repository", this, Activator.PLUGIN_ID, null) {
+         @Override
+         protected void runInternal(IProgressMonitor monitor) throws Exception
+         {
+            for(final InstallData d : installData)
+            {
+               importFromRepository(d.repository, d.request);
+               runInUIThread(new Runnable() {
+                  @Override
+                  public void run()
+                  {
+                     d.repository.setAllMarked(false);
+                     viewer.refresh();
+                  }
+               });
+            }
+         }
+         
+         @Override
+         protected void jobFinalize()
+         {
+            runInUIThread(new Runnable() {
+               @Override
+               public void run()
+               {
+                  actionInstall.setEnabled(true);
+               }
+            });
+         }
+
+         @Override
+         protected String getErrorMessage()
+         {
+            return "Import failed";
+         }
+      }.start();
+   }
+   
+   /**
+    * Import configuration elements from repository
+    * 
+    * @param repository
+    * @param request
+    * @throws Exception
+    */
+   private void importFromRepository(RepositoryRuntimeInfo repository, String request) throws Exception
+   {
+      String importFile = repository.loadImportFile(request);
+      Activator.logInfo("Import XML received from repository " + repository.getName() + ": " + importFile);
+      session.importConfiguration(importFile, 0);
+   }
+   
+   /**
+    * Install data
+    */
+   private class InstallData
+   {
+      public RepositoryRuntimeInfo repository;
+      public String request;
+
+      public InstallData(RepositoryRuntimeInfo repository, String request)
+      {
+         this.repository = repository;
+         this.request = request;
+      }
+   }
 }
index 4ea8ade..c6c9458 100644 (file)
 package org.netxms.ui.eclipse.market.views.helpers;
 
 import java.util.UUID;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.IFontProvider;
 import org.eclipse.jface.viewers.ITableLabelProvider;
 import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
 import org.netxms.ui.eclipse.market.Activator;
 import org.netxms.ui.eclipse.market.objects.EventReference;
 import org.netxms.ui.eclipse.market.objects.MarketObject;
+import org.netxms.ui.eclipse.market.objects.RepositoryElement;
 import org.netxms.ui.eclipse.market.objects.RepositoryRuntimeInfo;
 import org.netxms.ui.eclipse.market.objects.TemplateReference;
 
 /**
  * Label provider for repository manager
  */
-public class RepositoryLabelProvider extends LabelProvider implements ITableLabelProvider
+public class RepositoryLabelProvider extends LabelProvider implements ITableLabelProvider, IFontProvider, IColorProvider
 {
    private Image imageEvent = Activator.getImageDescriptor("icons/event.gif").createImage();
    private Image imageRepository = Activator.getImageDescriptor("icons/repository.gif").createImage();
    private Image imageTemplate = Activator.getImageDescriptor("icons/template.png").createImage();
+   private Font markFont;
+   private Color markColor;
+   
+   /**
+    * Constructor
+    */
+   public RepositoryLabelProvider()
+   {
+      FontData fd = JFaceResources.getDefaultFont().getFontData()[0];
+      fd.style = SWT.BOLD;
+      markFont = new Font(Display.getCurrent(), fd);
+      markColor = new Color(Display.getCurrent(), 0, 148, 255);
+   }
    
    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
@@ -69,6 +91,10 @@ public class RepositoryLabelProvider extends LabelProvider implements ITableLabe
       {
          case 0:
             return object.getName();
+         case 1:
+            if (object instanceof RepositoryElement)
+               return Integer.toString(((RepositoryElement)object).getActualVersion());
+            return "";
          case 2:
             UUID guid = object.getGuid();
             return (guid != null) ? guid.toString() : ""; 
@@ -82,7 +108,42 @@ public class RepositoryLabelProvider extends LabelProvider implements ITableLabe
    @Override
    public void dispose()
    {
+      imageEvent.dispose();
       imageRepository.dispose();
+      imageTemplate.dispose();
+      markFont.dispose();
+      markColor.dispose();
       super.dispose();
    }
+
+   /* (non-Javadoc)
+    * @see org.eclipse.jface.viewers.IFontProvider#getFont(java.lang.Object)
+    */
+   @Override
+   public Font getFont(Object element)
+   {
+      if ((element instanceof RepositoryElement) && ((RepositoryElement)element).isMarked())
+         return markFont;
+      return null;
+   }
+
+   /* (non-Javadoc)
+    * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object)
+    */
+   @Override
+   public Color getForeground(Object element)
+   {
+      if ((element instanceof RepositoryElement) && ((RepositoryElement)element).isMarked())
+         return markColor;
+      return null;
+   }
+
+   /* (non-Javadoc)
+    * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object)
+    */
+   @Override
+   public Color getBackground(Object element)
+   {
+      return null;
+   }
 }