e3f5e3591a393d6814bbee0b927f10dc914073e1
[public/netxms.git] / src / java / netxms-eclipse / Dashboard / src / org / netxms / ui / eclipse / dashboard / actions / ImportDashboard.java
1 /**
2 * NetXMS - open source network management system
3 * Copyright (C) 2003-2010 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.dashboard.actions;
20
21 import java.io.StringWriter;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import javax.xml.parsers.DocumentBuilder;
27 import javax.xml.parsers.DocumentBuilderFactory;
28 import javax.xml.transform.OutputKeys;
29 import javax.xml.transform.Transformer;
30 import javax.xml.transform.TransformerException;
31 import javax.xml.transform.TransformerFactory;
32 import javax.xml.transform.TransformerFactoryConfigurationError;
33 import javax.xml.transform.dom.DOMSource;
34 import javax.xml.transform.stream.StreamResult;
35 import org.eclipse.core.runtime.IProgressMonitor;
36 import org.eclipse.core.runtime.IStatus;
37 import org.eclipse.core.runtime.Platform;
38 import org.eclipse.core.runtime.Status;
39 import org.eclipse.jface.action.IAction;
40 import org.eclipse.jface.viewers.ISelection;
41 import org.eclipse.jface.viewers.IStructuredSelection;
42 import org.eclipse.jface.window.Window;
43 import org.eclipse.swt.widgets.Display;
44 import org.eclipse.ui.IObjectActionDelegate;
45 import org.eclipse.ui.IWorkbenchPart;
46 import org.eclipse.ui.IWorkbenchWindow;
47 import org.eclipse.ui.progress.UIJob;
48 import org.netxms.client.NXCObjectCreationData;
49 import org.netxms.client.NXCObjectModificationData;
50 import org.netxms.client.NXCSession;
51 import org.netxms.client.dashboards.DashboardElement;
52 import org.netxms.client.datacollection.DciValue;
53 import org.netxms.client.objects.Dashboard;
54 import org.netxms.client.objects.DashboardRoot;
55 import org.netxms.client.objects.AbstractObject;
56 import org.netxms.ui.eclipse.dashboard.Activator;
57 import org.netxms.ui.eclipse.dashboard.Messages;
58 import org.netxms.ui.eclipse.dashboard.dialogs.IdMatchingDialog;
59 import org.netxms.ui.eclipse.dashboard.dialogs.ImportDashboardDialog;
60 import org.netxms.ui.eclipse.dashboard.dialogs.helpers.DciIdMatchingData;
61 import org.netxms.ui.eclipse.dashboard.dialogs.helpers.ObjectIdMatchingData;
62 import org.netxms.ui.eclipse.dashboard.widgets.internal.DashboardElementConfig;
63 import org.netxms.ui.eclipse.jobs.ConsoleJob;
64 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
65 import org.w3c.dom.Document;
66 import org.w3c.dom.Element;
67 import org.w3c.dom.Node;
68 import org.w3c.dom.NodeList;
69
70 /**
71 * Create dashboard object
72 */
73 public class ImportDashboard implements IObjectActionDelegate
74 {
75 private IWorkbenchWindow window;
76 private IWorkbenchPart part;
77 private long parentId = -1;
78
79 /* (non-Javadoc)
80 * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart)
81 */
82 @Override
83 public void setActivePart(IAction action, IWorkbenchPart targetPart)
84 {
85 part = targetPart;
86 window = targetPart.getSite().getWorkbenchWindow();
87 }
88
89 /* (non-Javadoc)
90 * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
91 */
92 @Override
93 public void selectionChanged(IAction action, ISelection selection)
94 {
95 if ((selection instanceof IStructuredSelection) && (((IStructuredSelection)selection).size() == 1))
96 {
97 final Object object = ((IStructuredSelection)selection).getFirstElement();
98 if ((object instanceof Dashboard) || (object instanceof DashboardRoot))
99 {
100 parentId = ((AbstractObject)object).getObjectId();
101 }
102 else
103 {
104 parentId = -1;
105 }
106 }
107 else
108 {
109 parentId = -1;
110 }
111
112 action.setEnabled(parentId != -1);
113 }
114
115 /* (non-Javadoc)
116 * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
117 */
118 @Override
119 public void run(IAction action)
120 {
121 final ImportDashboardDialog dlg = new ImportDashboardDialog(window.getShell());
122 if (dlg.open() != Window.OK)
123 return;
124
125 final NXCSession session = (NXCSession)ConsoleSharedData.getSession();
126 final Display display = Display.getCurrent();
127
128 new ConsoleJob(Messages.ImportDashboard_JobTitle, part, Activator.PLUGIN_ID, null) {
129 @Override
130 protected void runInternal(IProgressMonitor monitor) throws Exception
131 {
132 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
133 DocumentBuilder db = dbf.newDocumentBuilder();
134 Document dom = db.parse(dlg.getImportFile());
135
136 Element root = dom.getDocumentElement();
137 if (!root.getNodeName().equals("dashboard")) //$NON-NLS-1$
138 throw new Exception(Messages.ImportDashboard_InvalidFile);
139
140 root.normalize();
141
142 List<DashboardElement> dashboardElements = new ArrayList<DashboardElement>();
143
144 NodeList elementsRoot = root.getElementsByTagName("elements"); //$NON-NLS-1$
145 for(int i = 0; i < elementsRoot.getLength(); i++)
146 {
147 if (elementsRoot.item(i).getNodeType() != Node.ELEMENT_NODE)
148 continue;
149
150 NodeList elements = ((Element)elementsRoot.item(i)).getElementsByTagName("dashboardElement"); //$NON-NLS-1$
151 for(int j = 0; j < elements.getLength(); j++)
152 {
153 Element e = (Element)elements.item(j);
154 DashboardElement de = new DashboardElement(getNodeValueAsInt(e, "type", 0), getNodeValueAsXml(e, "element")); //$NON-NLS-1$ //$NON-NLS-2$
155 de.setLayout(getNodeValueAsXml(e, "layout")); //$NON-NLS-1$
156 dashboardElements.add(de);
157 }
158 }
159
160 if (doIdMapping(display, session, dashboardElements, root))
161 {
162 NXCObjectCreationData cd = new NXCObjectCreationData(AbstractObject.OBJECT_DASHBOARD, dlg.getObjectName(), parentId);
163 final long objectId = session.createObject(cd);
164
165 NXCObjectModificationData md = new NXCObjectModificationData(objectId);
166 md.setColumnCount(getNodeValueAsInt(root, "columns", 1)); //$NON-NLS-1$
167 md.setObjectFlags(getNodeValueAsInt(root, "options", 0)); //$NON-NLS-1$
168 md.setDashboardElements(dashboardElements);
169 session.modifyObject(md);
170 }
171 }
172
173 @Override
174 protected String getErrorMessage()
175 {
176 return Messages.ImportDashboard_ErrorPrefix + dlg.getObjectName() + Messages.ImportDashboard_ErrorSuffix;
177 }
178 }.start();
179 }
180
181 /**
182 * Map node and DCI ID from source system to destination system
183 * @throws Exception
184 * @return true if import operation should continue
185 */
186 private boolean doIdMapping(final Display display, final NXCSession session, List<DashboardElement> dashboardElements, Element root) throws Exception
187 {
188 final Map<Long, ObjectIdMatchingData> objects = readSourceObjects(root);
189 final Map<Long, DciIdMatchingData> dcis = readSourceDci(root);
190
191 // add all node IDs from DCI list if they are missing
192 for(DciIdMatchingData d : dcis.values())
193 {
194 if (!objects.containsKey(d.srcNodeId))
195 objects.put(d.srcNodeId, new ObjectIdMatchingData(d.srcNodeId, "", AbstractObject.OBJECT_NODE)); //$NON-NLS-1$
196 }
197
198 // try to match objects
199 for(ObjectIdMatchingData d : objects.values())
200 {
201 if (d.srcId < 10)
202 {
203 // built-in object
204 d.dstId = d.srcId;
205 continue;
206 }
207
208 if (d.srcName.isEmpty())
209 continue;
210
211 AbstractObject object = session.findObjectByName(d.srcName);
212 if ((object != null) && (object.getObjectClass() == d.objectClass))
213 {
214 d.dstId = object.getObjectId();
215 d.dstName = object.getObjectName();
216 }
217 }
218
219 // try to match DCIs
220 for(DciIdMatchingData d : dcis.values())
221 {
222 // get node ID on target system
223 ObjectIdMatchingData od = objects.get(d.srcNodeId);
224
225 // bind DCI data to appropriate node data
226 od.dcis.add(d);
227
228 if (od.dstId == 0)
229 continue; // no match for node
230
231 d.dstNodeId = od.dstId;
232 DciValue[] dciValues = session.getLastValues(d.dstNodeId);
233 for(DciValue v : dciValues)
234 {
235 if (v.getDescription().equalsIgnoreCase(d.srcName))
236 {
237 d.dstDciId = v.getId();
238 d.dstName = v.getDescription();
239 break;
240 }
241 }
242 }
243
244 // show matching results to user
245 UIJob job = new UIJob(display, "") { //$NON-NLS-1$
246 @Override
247 public IStatus runInUIThread(IProgressMonitor monitor)
248 {
249 IdMatchingDialog dlg = new IdMatchingDialog(window.getShell(), objects, dcis);
250 return (dlg.open() == Window.OK) ? Status.OK_STATUS : Status.CANCEL_STATUS;
251 }
252 };
253 job.schedule();
254 job.join();
255 if (job.getResult().equals(Status.OK_STATUS))
256 {
257 // update dashboard elements with mapping data
258 for(DashboardElement e : dashboardElements)
259 updateDashboardElement(e, objects, dcis);
260 return true;
261 }
262 return false;
263 }
264
265 /**
266 * Update dashboard element from mapping data
267 *
268 * @param e
269 * @param objects
270 * @param dcis
271 * @throws Exception
272 */
273 private void updateDashboardElement(DashboardElement e, Map<Long, ObjectIdMatchingData> objects, Map<Long, DciIdMatchingData> dcis) throws Exception
274 {
275 DashboardElementConfig config = (DashboardElementConfig)Platform.getAdapterManager().getAdapter(e, DashboardElementConfig.class);
276 if (config == null)
277 return;
278
279 config.remapObjects(objects);
280 config.remapDataCollectionItems(dcis);
281 e.setData(config.createXml());
282 }
283
284 /**
285 * Read source objects from XML document
286 *
287 * @param root
288 * @return
289 */
290 private Map<Long, ObjectIdMatchingData> readSourceObjects(Element root)
291 {
292 Map<Long, ObjectIdMatchingData> objects = new HashMap<Long, ObjectIdMatchingData>();
293 NodeList objectsRoot = root.getElementsByTagName("objectMap"); //$NON-NLS-1$
294 for(int i = 0; i < objectsRoot.getLength(); i++)
295 {
296 if (objectsRoot.item(i).getNodeType() != Node.ELEMENT_NODE)
297 continue;
298
299 NodeList elements = ((Element)objectsRoot.item(i)).getElementsByTagName("object"); //$NON-NLS-1$
300 for(int j = 0; j < elements.getLength(); j++)
301 {
302 Element e = (Element)elements.item(j);
303 long id = getAttributeAsLong(e, "id", 0); //$NON-NLS-1$
304 objects.put(id, new ObjectIdMatchingData(id, e.getTextContent(), (int)getAttributeAsLong(e, "class", 0))); //$NON-NLS-1$
305 }
306 }
307 return objects;
308 }
309
310 /**
311 * Read source DCI from XML document
312 *
313 * @param root
314 * @return
315 */
316 private Map<Long, DciIdMatchingData> readSourceDci(Element root)
317 {
318 Map<Long, DciIdMatchingData> dcis = new HashMap<Long, DciIdMatchingData>();
319 NodeList objectsRoot = root.getElementsByTagName("dciMap"); //$NON-NLS-1$
320 for(int i = 0; i < objectsRoot.getLength(); i++)
321 {
322 if (objectsRoot.item(i).getNodeType() != Node.ELEMENT_NODE)
323 continue;
324
325 NodeList elements = ((Element)objectsRoot.item(i)).getElementsByTagName("dci"); //$NON-NLS-1$
326 for(int j = 0; j < elements.getLength(); j++)
327 {
328 Element e = (Element)elements.item(j);
329 long id = getAttributeAsLong(e, "id", 0); //$NON-NLS-1$
330 dcis.put(id, new DciIdMatchingData(getAttributeAsLong(e, "node", 0), id, e.getTextContent())); //$NON-NLS-1$
331 }
332 }
333 return dcis;
334 }
335
336 /**
337 * Get value of given node as integer.
338 *
339 * @param parent
340 * @param tag
341 * @param defaultValue
342 * @return
343 */
344 private static int getNodeValueAsInt(Element parent, String tag, int defaultValue)
345 {
346 NodeList l = parent.getElementsByTagName(tag);
347 if ((l.getLength() == 0) || (l.item(0).getNodeType() != Node.ELEMENT_NODE))
348 return defaultValue;
349
350 try
351 {
352 return Integer.parseInt(((Element)l.item(0)).getTextContent());
353 }
354 catch(NumberFormatException e)
355 {
356 return defaultValue;
357 }
358 }
359
360 /**
361 * Get value of given attribute as integer.
362 *
363 * @param parent
364 * @param tag
365 * @param defaultValue
366 * @return
367 */
368 private static long getAttributeAsLong(Element element, String attribute, long defaultValue)
369 {
370 try
371 {
372 return Long.parseLong(element.getAttribute(attribute));
373 }
374 catch(NumberFormatException e)
375 {
376 return defaultValue;
377 }
378 }
379
380 /**
381 * Get node value as XML document.
382 *
383 * @param parent
384 * @param tag
385 * @return
386 * @throws TransformerFactoryConfigurationError
387 * @throws TransformerException
388 */
389 private static String getNodeValueAsXml(Element parent, String tag) throws TransformerFactoryConfigurationError, TransformerException
390 {
391 NodeList l = parent.getElementsByTagName(tag);
392 if ((l.getLength() == 0) || (l.item(0).getNodeType() != Node.ELEMENT_NODE))
393 return "<" + tag + "></" + tag + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
394 return nodeToString(l.item(0));
395 }
396
397 /**
398 * Convert DOM tree node to string (XML document).
399 *
400 * @param node
401 * @return
402 * @throws TransformerFactoryConfigurationError
403 * @throws TransformerException
404 */
405 private static String nodeToString(Node node) throws TransformerFactoryConfigurationError, TransformerException
406 {
407 StringWriter sw = new StringWriter();
408 Transformer t = TransformerFactory.newInstance().newTransformer();
409 t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); //$NON-NLS-1$
410 t.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
411 t.transform(new DOMSource(node), new StreamResult(sw));
412 return sw.toString();
413 }
414 }