bb764f1786623dfd6d7f4b9ae6f4068a8cb0222e
[public/netxms.git] / src / java / netxms-eclipse / ObjectTools / src / org / netxms / ui / eclipse / objecttools / api / ObjectToolExecutor.java
1 /**
2 * NetXMS - open source network management system
3 * Copyright (C) 2003-2015 Victor Kirhenshtein
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 package org.netxms.ui.eclipse.objecttools.api;
20
21 import java.io.IOException;
22 import java.net.URLEncoder;
23 import java.util.Arrays;
24 import java.util.Comparator;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Set;
28 import org.eclipse.core.runtime.IProgressMonitor;
29 import org.eclipse.core.runtime.Platform;
30 import org.eclipse.jface.window.Window;
31 import org.eclipse.ui.IWorkbenchPage;
32 import org.eclipse.ui.IWorkbenchWindow;
33 import org.eclipse.ui.PartInitException;
34 import org.eclipse.ui.PlatformUI;
35 import org.netxms.base.NXCommon;
36 import org.netxms.client.AgentFileData;
37 import org.netxms.client.NXCSession;
38 import org.netxms.client.objecttools.InputField;
39 import org.netxms.client.objecttools.InputFieldType;
40 import org.netxms.client.objecttools.ObjectTool;
41 import org.netxms.ui.eclipse.console.resources.StatusDisplayInfo;
42 import org.netxms.ui.eclipse.filemanager.views.AgentFileViewer;
43 import org.netxms.ui.eclipse.jobs.ConsoleJob;
44 import org.netxms.ui.eclipse.objecttools.Activator;
45 import org.netxms.ui.eclipse.objecttools.Messages;
46 import org.netxms.ui.eclipse.objecttools.dialogs.ObjectToolInputDialog;
47 import org.netxms.ui.eclipse.objecttools.views.AgentActionResults;
48 import org.netxms.ui.eclipse.objecttools.views.BrowserView;
49 import org.netxms.ui.eclipse.objecttools.views.LocalCommandResults;
50 import org.netxms.ui.eclipse.objecttools.views.ServerCommandResults;
51 import org.netxms.ui.eclipse.objecttools.views.TableToolResults;
52 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
53 import org.netxms.ui.eclipse.tools.MessageDialogHelper;
54
55 /**
56 * Executor for object tool
57 */
58 public final class ObjectToolExecutor
59 {
60 /**
61 * Private constructor to forbid instantiation
62 */
63 private ObjectToolExecutor()
64 {
65 }
66
67 /**
68 * Check if tool is allowed for execution on each node from set
69 *
70 * @param tool
71 * @param nodes
72 * @return
73 */
74 public static boolean isToolAllowed(ObjectTool tool, Set<NodeInfo> nodes)
75 {
76 if (tool.getType() != ObjectTool.TYPE_INTERNAL)
77 return true;
78
79 ObjectToolHandler handler = ObjectToolsCache.findHandler(tool.getData());
80 if (handler != null)
81 {
82 for(NodeInfo n : nodes)
83 if (!handler.canExecuteOnNode(n.object, tool))
84 return false;
85 return true;
86 }
87 else
88 {
89 return false;
90 }
91 }
92
93 /**
94 * Check if given tool is applicable for all nodes in set
95 *
96 * @param tool
97 * @param nodes
98 * @return
99 */
100 public static boolean isToolApplicable(ObjectTool tool, Set<NodeInfo> nodes)
101 {
102 for(NodeInfo n : nodes)
103 if (!tool.isApplicableForNode(n.object))
104 return false;
105 return true;
106 }
107
108 /**
109 * Execute object tool on node set
110 *
111 * @param tool Object tool
112 */
113 public static void execute(final Set<NodeInfo> nodes, final ObjectTool tool)
114 {
115 if ((tool.getFlags() & ObjectTool.ASK_CONFIRMATION) != 0)
116 {
117 String message = tool.getConfirmationText();
118 if (nodes.size() == 1)
119 {
120 NodeInfo node = nodes.iterator().next();
121 message = substituteMacros(message, node, new HashMap<String, String>(0));
122 }
123 else
124 {
125 message = substituteMacros(message, new NodeInfo(null, null), new HashMap<String, String>(0));
126 }
127 if (!MessageDialogHelper.openQuestion(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
128 Messages.get().ObjectToolsDynamicMenu_ConfirmExec, message))
129 return;
130 }
131
132 final Map<String, String> inputValues;
133 final InputField[] fields = tool.getInputFields();
134 if (fields.length > 0)
135 {
136 Arrays.sort(fields, new Comparator<InputField>() {
137 @Override
138 public int compare(InputField f1, InputField f2)
139 {
140 return f1.getSequence() - f2.getSequence();
141 }
142 });
143 inputValues = readInputFields(fields);
144 if (inputValues == null)
145 return; // cancelled
146 }
147 else
148 {
149 inputValues = new HashMap<String, String>(0);
150 }
151
152 // Check if password validation needed
153 boolean validationNeeded = false;
154 for(int i = 0; i < fields.length; i++)
155 if (fields[i].getOptions().validatePassword)
156 {
157 validationNeeded = true;
158 break;
159 }
160
161 if (validationNeeded)
162 {
163 final NXCSession session = ConsoleSharedData.getSession();
164 new ConsoleJob(Messages.get().ObjectToolExecutor_JobName, null, Activator.PLUGIN_ID, null) {
165 @Override
166 protected void runInternal(IProgressMonitor monitor) throws Exception
167 {
168 for(int i = 0; i < fields.length; i++)
169 {
170 if ((fields[i].getType() == InputFieldType.PASSWORD) && (fields[i].getOptions().validatePassword))
171 {
172 boolean valid = session.validateUserPassword(inputValues.get(fields[i].getName()));
173 if (!valid)
174 {
175 final String fieldName = fields[i].getDisplayName();
176 getDisplay().syncExec(new Runnable() {
177 @Override
178 public void run()
179 {
180 MessageDialogHelper.openError(null, Messages.get().ObjectToolExecutor_ErrorTitle,
181 String.format(Messages.get().ObjectToolExecutor_ErrorText, fieldName));
182 }
183 });
184 return;
185 }
186 }
187 }
188
189 runInUIThread(new Runnable() {
190 @Override
191 public void run()
192 {
193 for(NodeInfo n : nodes)
194 executeOnNode(n, tool, inputValues);
195 }
196 });
197 }
198
199 @Override
200 protected String getErrorMessage()
201 {
202 return Messages.get().ObjectToolExecutor_PasswordValidationFailed;
203 }
204 }.start();
205 }
206 else
207 {
208 for(NodeInfo n : nodes)
209 executeOnNode(n, tool, inputValues);
210 }
211 }
212
213 /**
214 * Read input fields
215 *
216 * @param fields
217 * @return
218 */
219 private static Map<String, String> readInputFields(InputField[] fields)
220 {
221 ObjectToolInputDialog dlg = new ObjectToolInputDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), fields);
222 if (dlg.open() != Window.OK)
223 return null;
224 return dlg.getValues();
225 }
226
227 /**
228 * Execute object tool on single node
229 *
230 * @param node
231 * @param tool
232 * @param inputValues
233 */
234 private static void executeOnNode(final NodeInfo node, final ObjectTool tool, Map<String, String> inputValues)
235 {
236 switch(tool.getType())
237 {
238 case ObjectTool.TYPE_ACTION:
239 executeAgentAction(node, tool, inputValues);
240 break;
241 case ObjectTool.TYPE_FILE_DOWNLOAD:
242 executeFileDownload(node, tool, inputValues);
243 break;
244 case ObjectTool.TYPE_INTERNAL:
245 executeInternalTool(node, tool);
246 break;
247 case ObjectTool.TYPE_LOCAL_COMMAND:
248 executeLocalCommand(node, tool, inputValues);
249 break;
250 case ObjectTool.TYPE_SERVER_COMMAND:
251 executeServerCommand(node, tool, inputValues);
252 break;
253 case ObjectTool.TYPE_TABLE_AGENT:
254 case ObjectTool.TYPE_TABLE_SNMP:
255 executeTableTool(node, tool);
256 break;
257 case ObjectTool.TYPE_URL:
258 openURL(node, tool, inputValues);
259 break;
260 }
261 }
262
263 /**
264 * Execute table tool
265 *
266 * @param node
267 * @param tool
268 */
269 private static void executeTableTool(final NodeInfo node, final ObjectTool tool)
270 {
271 final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
272 try
273 {
274 final IWorkbenchPage page = window.getActivePage();
275 final TableToolResults view = (TableToolResults)page.showView(TableToolResults.ID,
276 Long.toString(tool.getId()) + "&" + Long.toString(node.object.getObjectId()), IWorkbenchPage.VIEW_ACTIVATE); //$NON-NLS-1$
277 view.refreshTable();
278 }
279 catch(PartInitException e)
280 {
281 MessageDialogHelper.openError(window.getShell(), Messages.get().ObjectToolsDynamicMenu_Error, String.format(Messages.get().ObjectToolsDynamicMenu_ErrorOpeningView, e.getLocalizedMessage()));
282 }
283 }
284
285 /**
286 * @param node
287 * @param tool
288 * @param inputValues
289 */
290 private static void executeAgentAction(final NodeInfo node, final ObjectTool tool, Map<String, String> inputValues)
291 {
292 final NXCSession session = (NXCSession)ConsoleSharedData.getSession();
293 final String action = substituteMacros(tool.getData(), node, inputValues);
294
295 if ((tool.getFlags() & ObjectTool.GENERATES_OUTPUT) == 0)
296 {
297 new ConsoleJob(String.format(Messages.get().ObjectToolsDynamicMenu_ExecuteOnNode, node.object.getObjectName()), null, Activator.PLUGIN_ID, null) {
298 @Override
299 protected String getErrorMessage()
300 {
301 return String.format(Messages.get().ObjectToolsDynamicMenu_CannotExecuteOnNode, node.object.getObjectName());
302 }
303
304 @Override
305 protected void runInternal(IProgressMonitor monitor) throws Exception
306 {
307 session.executeAction(node.object.getObjectId(), action);
308 runInUIThread(new Runnable() {
309 @Override
310 public void run()
311 {
312 MessageDialogHelper.openInformation(null, Messages.get().ObjectToolsDynamicMenu_ToolExecution, String.format(Messages.get().ObjectToolsDynamicMenu_ExecSuccess, action, node.object.getObjectName()));
313 }
314 });
315 }
316 }.start();
317 }
318 else
319 {
320 final String secondaryId = Long.toString(node.object.getObjectId()) + "&" + Long.toString(tool.getId()); //$NON-NLS-1$
321 final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
322 try
323 {
324 AgentActionResults view = (AgentActionResults)window.getActivePage().showView(AgentActionResults.ID, secondaryId, IWorkbenchPage.VIEW_ACTIVATE);
325 view.executeAction(action);
326 }
327 catch(Exception e)
328 {
329 MessageDialogHelper.openError(window.getShell(), Messages.get().ObjectToolsDynamicMenu_Error, String.format(Messages.get().ObjectToolsDynamicMenu_ErrorOpeningView, e.getLocalizedMessage()));
330 }
331 }
332 }
333
334 /**
335 * Execute server command
336 *
337 * @param node
338 * @param tool
339 * @param inputValues
340 */
341 private static void executeServerCommand(final NodeInfo node, final ObjectTool tool, final Map<String, String> inputValues)
342 {
343 final NXCSession session = (NXCSession)ConsoleSharedData.getSession();
344 if ((tool.getFlags() & ObjectTool.GENERATES_OUTPUT) == 0)
345 {
346 new ConsoleJob(Messages.get().ObjectToolsDynamicMenu_ExecuteServerCmd, null, Activator.PLUGIN_ID, null) {
347 @Override
348 protected void runInternal(IProgressMonitor monitor) throws Exception
349 {
350 session.executeServerCommand(node.object.getObjectId(), tool.getData(), inputValues);
351 runInUIThread(new Runnable() {
352 @Override
353 public void run()
354 {
355 MessageDialogHelper.openInformation(null, Messages.get().ObjectToolsDynamicMenu_Information, Messages.get().ObjectToolsDynamicMenu_ServerCommandExecuted);
356 }
357 });
358 }
359
360 @Override
361 protected String getErrorMessage()
362 {
363 return Messages.get().ObjectToolsDynamicMenu_ServerCmdExecError;
364 }
365 }.start();
366 }
367 else
368 {
369 final String secondaryId = Long.toString(node.object.getObjectId()) + "&" + Long.toString(tool.getId()); //$NON-NLS-1$
370 final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
371 try
372 {
373 ServerCommandResults view = (ServerCommandResults)window.getActivePage().showView(ServerCommandResults.ID, secondaryId, IWorkbenchPage.VIEW_ACTIVATE);
374 view.executeCommand(tool.getData(), inputValues);
375 }
376 catch(Exception e)
377 {
378 MessageDialogHelper.openError(window.getShell(), Messages.get().ObjectToolsDynamicMenu_Error, String.format(Messages.get().ObjectToolsDynamicMenu_ErrorOpeningView, e.getLocalizedMessage()));
379 }
380 }
381 }
382
383 /**
384 * Execute local command
385 *
386 * @param node
387 * @param tool
388 * @param inputValues
389 */
390 private static void executeLocalCommand(final NodeInfo node, final ObjectTool tool, Map<String, String> inputValues)
391 {
392 String command = substituteMacros(tool.getData(), node, inputValues);
393
394 if ((tool.getFlags() & ObjectTool.GENERATES_OUTPUT) == 0)
395 {
396 final String os = Platform.getOS();
397
398 try
399 {
400 if (os.equals(Platform.OS_WIN32))
401 {
402 command = "CMD.EXE /C START \"NetXMS\" " + command; //$NON-NLS-1$
403 Runtime.getRuntime().exec(command);
404 }
405 else
406 {
407 Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", command }); //$NON-NLS-1$ //$NON-NLS-2$
408 }
409 }
410 catch(IOException e)
411 {
412 // TODO Auto-generated catch block
413 e.printStackTrace();
414 }
415 }
416 else
417 {
418 final String secondaryId = Long.toString(node.object.getObjectId()) + "&" + Long.toString(tool.getId()); //$NON-NLS-1$
419 final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
420 try
421 {
422 LocalCommandResults view = (LocalCommandResults)window.getActivePage().showView(LocalCommandResults.ID, secondaryId, IWorkbenchPage.VIEW_ACTIVATE);
423 view.runCommand(command);
424 }
425 catch(Exception e)
426 {
427 MessageDialogHelper.openError(window.getShell(), Messages.get().ObjectToolsDynamicMenu_Error, String.format(Messages.get().ObjectToolsDynamicMenu_ErrorOpeningView, e.getLocalizedMessage()));
428 }
429 }
430 }
431
432 /**
433 * @param node
434 * @param tool
435 * @param inputValues
436 */
437 private static void executeFileDownload(final NodeInfo node, final ObjectTool tool, Map<String, String> inputValues)
438 {
439 final NXCSession session = (NXCSession)ConsoleSharedData.getSession();
440 String[] parameters = tool.getData().split("\u007F"); //$NON-NLS-1$
441
442 final String fileName = substituteMacros(parameters[0], node, inputValues);
443 final int maxFileSize = Integer.parseInt(parameters[1]);
444 final boolean follow = parameters[2].equals("true") ? true : false; //$NON-NLS-1$
445
446 ConsoleJob job = new ConsoleJob(Messages.get().ObjectToolsDynamicMenu_DownloadFromAgent, null, Activator.PLUGIN_ID, null) {
447 @Override
448 protected String getErrorMessage()
449 {
450 return String.format(Messages.get().ObjectToolsDynamicMenu_DownloadError, fileName, node.object.getObjectName());
451 }
452
453 @Override
454 protected void runInternal(IProgressMonitor monitor) throws Exception
455 {
456 final AgentFileData file = session.downloadFileFromAgent(node.object.getObjectId(), fileName, maxFileSize, follow);
457 runInUIThread(new Runnable() {
458 @Override
459 public void run()
460 {
461 try
462 {
463 String secondaryId = Long.toString(node.object.getObjectId()) + "&" + URLEncoder.encode(fileName, "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
464 AgentFileViewer.createView(secondaryId, node.object.getObjectId(), file, follow);
465 }
466 catch(Exception e)
467 {
468 final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
469 MessageDialogHelper.openError(window.getShell(), Messages.get().ObjectToolsDynamicMenu_Error, String.format(Messages.get().ObjectToolsDynamicMenu_ErrorOpeningView, e.getLocalizedMessage()));
470 }
471 }
472 });
473 }
474 };
475 job.start();
476 }
477
478 /**
479 * @param node
480 * @param tool
481 */
482 private static void executeInternalTool(final NodeInfo node, final ObjectTool tool)
483 {
484 ObjectToolHandler handler = ObjectToolsCache.findHandler(tool.getData());
485 if (handler != null)
486 {
487 handler.execute(node.object, tool);
488 }
489 else
490 {
491 MessageDialogHelper.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.get().ObjectToolsDynamicMenu_Error, Messages.get().ObjectToolsDynamicMenu_HandlerNotDefined);
492 }
493 }
494
495 /**
496 * @param node
497 * @param tool
498 * @param inputValues
499 */
500 private static void openURL(final NodeInfo node, final ObjectTool tool, Map<String, String> inputValues)
501 {
502 final String url = substituteMacros(tool.getData(), node, inputValues);
503
504 final String sid = Long.toString(node.object.getObjectId()) + "&" + Long.toString(tool.getId()); //$NON-NLS-1$
505 final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
506 try
507 {
508 BrowserView view = (BrowserView)window.getActivePage().showView(BrowserView.ID, sid, IWorkbenchPage.VIEW_ACTIVATE);
509 view.openUrl(url);
510 }
511 catch(PartInitException e)
512 {
513 MessageDialogHelper.openError(window.getShell(), Messages.get().ObjectToolsDynamicMenu_Error, Messages.get().ObjectToolsDynamicMenu_CannotOpenWebBrowser + e.getLocalizedMessage());
514 }
515 }
516
517 /**
518 * Substitute macros in string
519 *
520 * @param s
521 * @param node
522 * @param inputValues
523 * @return
524 */
525 private static String substituteMacros(String s, NodeInfo node, Map<String, String> inputValues)
526 {
527 StringBuilder sb = new StringBuilder();
528
529 char[] src = s.toCharArray();
530 for(int i = 0; i < s.length(); i++)
531 {
532 if (src[i] == '%')
533 {
534 i++;
535 if (i == s.length())
536 break; // malformed string
537
538 switch(src[i])
539 {
540 case 'a':
541 sb.append((node.object != null) ? node.object.getPrimaryIP().getHostAddress() : Messages.get().ObjectToolsDynamicMenu_MultipleNodes);
542 break;
543 case 'A': // alarm message
544 if (node.alarm != null)
545 sb.append(node.alarm.getMessage());
546 break;
547 case 'c':
548 if (node.alarm != null)
549 sb.append(node.alarm.getSourceEventCode());
550 break;
551 case 'g':
552 sb.append((node.object != null) ? node.object.getGuid().toString() : Messages.get().ObjectToolsDynamicMenu_MultipleNodes);
553 break;
554 case 'i':
555 sb.append((node.object != null) ? String.format("0x%08X", node.object.getObjectId()) : Messages.get().ObjectToolsDynamicMenu_MultipleNodes); //$NON-NLS-1$
556 break;
557 case 'I':
558 sb.append((node.object != null) ? Long.toString(node.object.getObjectId()) : Messages.get().ObjectToolsDynamicMenu_MultipleNodes);
559 break;
560 case 'm': // alarm message
561 if (node.alarm != null)
562 sb.append(node.alarm.getMessage());
563 break;
564 case 'n':
565 sb.append((node.object != null) ? node.object.getObjectName() : Messages.get().ObjectToolsDynamicMenu_MultipleNodes);
566 break;
567 case 'N':
568 if (node.alarm != null)
569 sb.append(ConsoleSharedData.getSession().getEventName(node.alarm.getSourceEventCode()));
570 break;
571 case 's':
572 if (node.alarm != null)
573 sb.append(node.alarm.getCurrentSeverity());
574 break;
575 case 'S':
576 if (node.alarm != null)
577 sb.append(StatusDisplayInfo.getStatusText(node.alarm.getCurrentSeverity()));
578 break;
579 case 'U':
580 sb.append(ConsoleSharedData.getSession().getUserName());
581 break;
582 case 'v':
583 sb.append(NXCommon.VERSION);
584 break;
585 case 'y': // alarm state
586 if (node.alarm != null)
587 sb.append(node.alarm.getState());
588 break;
589 case 'Y': // alarm ID
590 if (node.alarm != null)
591 sb.append(node.alarm.getId());
592 break;
593 case '%':
594 sb.append('%');
595 break;
596 case '{': // object's custom attribute
597 StringBuilder attr = new StringBuilder();
598 for(i++; i < s.length(); i++)
599 {
600 if (src[i] == '}')
601 break;
602 attr.append(src[i]);
603 }
604 if ((node.object != null) && (attr.length() > 0))
605 {
606 String value = node.object.getCustomAttributes().get(attr.toString());
607 if (value != null)
608 sb.append(value);
609 }
610 break;
611 case '(': // input field
612 StringBuilder name = new StringBuilder();
613 for(i++; i < s.length(); i++)
614 {
615 if (src[i] == ')')
616 break;
617 name.append(src[i]);
618 }
619 if (name.length() > 0)
620 {
621 String value = inputValues.get(name.toString());
622 if (value != null)
623 sb.append(value);
624 }
625 break;
626 default:
627 break;
628 }
629 }
630 else
631 {
632 sb.append(src[i]);
633 }
634 }
635
636 return sb.toString();
637 }
638 }