3b334b14300f2d0c0779fbede4c46754095d9d57
[public/netxms.git] / src / java / netxms-client / src / main / java / org / netxms / client / NXCSession.java
1 /**
2 * NetXMS - open source network management system
3 * Copyright (C) 2003-2014 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.client;
20
21 import java.io.BufferedInputStream;
22 import java.io.ByteArrayInputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.net.InetAddress;
29 import java.net.Socket;
30 import java.net.UnknownHostException;
31 import java.security.GeneralSecurityException;
32 import java.security.Signature;
33 import java.security.SignatureException;
34 import java.security.cert.Certificate;
35 import java.security.cert.CertificateEncodingException;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.Date;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.Locale;
44 import java.util.Map;
45 import java.util.Map.Entry;
46 import java.util.Set;
47 import java.util.UUID;
48 import java.util.concurrent.LinkedBlockingQueue;
49 import java.util.concurrent.Semaphore;
50 import java.util.concurrent.TimeUnit;
51 import java.util.concurrent.atomic.AtomicLong;
52 import java.util.regex.Matcher;
53 import java.util.regex.Pattern;
54 import org.netxms.api.client.NetXMSClientException;
55 import org.netxms.api.client.ProgressListener;
56 import org.netxms.api.client.Session;
57 import org.netxms.api.client.SessionListener;
58 import org.netxms.api.client.SessionNotification;
59 import org.netxms.api.client.images.ImageLibraryManager;
60 import org.netxms.api.client.images.LibraryImage;
61 import org.netxms.api.client.mt.MappingTable;
62 import org.netxms.api.client.mt.MappingTableDescriptor;
63 import org.netxms.api.client.reporting.ReportDefinition;
64 import org.netxms.api.client.reporting.ReportRenderFormat;
65 import org.netxms.api.client.reporting.ReportResult;
66 import org.netxms.api.client.reporting.ReportingJob;
67 import org.netxms.api.client.reporting.ReportingServerManager;
68 import org.netxms.api.client.scripts.Script;
69 import org.netxms.api.client.scripts.ScriptLibraryManager;
70 import org.netxms.api.client.servermanager.ServerManager;
71 import org.netxms.api.client.servermanager.ServerVariable;
72 import org.netxms.api.client.users.AbstractUserObject;
73 import org.netxms.api.client.users.AuthCertificate;
74 import org.netxms.api.client.users.User;
75 import org.netxms.api.client.users.UserGroup;
76 import org.netxms.api.client.users.UserManager;
77 import org.netxms.base.CompatTools;
78 import org.netxms.base.EncryptionContext;
79 import org.netxms.base.GeoLocation;
80 import org.netxms.base.Logger;
81 import org.netxms.base.NXCPCodes;
82 import org.netxms.base.NXCPDataInputStream;
83 import org.netxms.base.NXCPException;
84 import org.netxms.base.NXCPMessage;
85 import org.netxms.base.NXCPMessageReceiver;
86 import org.netxms.base.NXCPMsgWaitQueue;
87 import org.netxms.base.NXCommon;
88 import org.netxms.client.constants.RCC;
89 import org.netxms.client.dashboards.DashboardElement;
90 import org.netxms.client.datacollection.ConditionDciInfo;
91 import org.netxms.client.datacollection.DataCollectionConfiguration;
92 import org.netxms.client.datacollection.DataCollectionItem;
93 import org.netxms.client.datacollection.DciData;
94 import org.netxms.client.datacollection.DciDataRow;
95 import org.netxms.client.datacollection.DciPushData;
96 import org.netxms.client.datacollection.DciSummaryTable;
97 import org.netxms.client.datacollection.DciSummaryTableDescriptor;
98 import org.netxms.client.datacollection.DciValue;
99 import org.netxms.client.datacollection.GraphSettings;
100 import org.netxms.client.datacollection.PerfTabDci;
101 import org.netxms.client.datacollection.SimpleDciValue;
102 import org.netxms.client.datacollection.Threshold;
103 import org.netxms.client.datacollection.ThresholdViolationSummary;
104 import org.netxms.client.datacollection.TransformationTestResult;
105 import org.netxms.client.datacollection.WinPerfObject;
106 import org.netxms.client.events.Alarm;
107 import org.netxms.client.events.AlarmComment;
108 import org.netxms.client.events.Event;
109 import org.netxms.client.events.EventInfo;
110 import org.netxms.client.events.EventProcessingPolicy;
111 import org.netxms.client.events.EventProcessingPolicyRule;
112 import org.netxms.client.events.EventTemplate;
113 import org.netxms.client.events.SyslogRecord;
114 import org.netxms.client.log.Log;
115 import org.netxms.client.maps.MapDCIInstance;
116 import org.netxms.client.maps.NetworkMapLink;
117 import org.netxms.client.maps.NetworkMapPage;
118 import org.netxms.client.maps.elements.NetworkMapElement;
119 import org.netxms.client.maps.elements.NetworkMapObject;
120 import org.netxms.client.objects.AbstractObject;
121 import org.netxms.client.objects.AccessPoint;
122 import org.netxms.client.objects.AgentPolicy;
123 import org.netxms.client.objects.AgentPolicyConfig;
124 import org.netxms.client.objects.BusinessService;
125 import org.netxms.client.objects.BusinessServiceRoot;
126 import org.netxms.client.objects.Cluster;
127 import org.netxms.client.objects.ClusterResource;
128 import org.netxms.client.objects.ClusterSyncNetwork;
129 import org.netxms.client.objects.Condition;
130 import org.netxms.client.objects.Container;
131 import org.netxms.client.objects.Dashboard;
132 import org.netxms.client.objects.DashboardRoot;
133 import org.netxms.client.objects.EntireNetwork;
134 import org.netxms.client.objects.GenericObject;
135 import org.netxms.client.objects.Interface;
136 import org.netxms.client.objects.MobileDevice;
137 import org.netxms.client.objects.NetworkMap;
138 import org.netxms.client.objects.NetworkMapGroup;
139 import org.netxms.client.objects.NetworkMapRoot;
140 import org.netxms.client.objects.NetworkService;
141 import org.netxms.client.objects.Node;
142 import org.netxms.client.objects.NodeLink;
143 import org.netxms.client.objects.PolicyGroup;
144 import org.netxms.client.objects.PolicyRoot;
145 import org.netxms.client.objects.Rack;
146 import org.netxms.client.objects.ServiceCheck;
147 import org.netxms.client.objects.ServiceRoot;
148 import org.netxms.client.objects.Subnet;
149 import org.netxms.client.objects.Template;
150 import org.netxms.client.objects.TemplateGroup;
151 import org.netxms.client.objects.TemplateRoot;
152 import org.netxms.client.objects.UnknownObject;
153 import org.netxms.client.objects.VPNConnector;
154 import org.netxms.client.objects.Zone;
155 import org.netxms.client.objecttools.ObjectTool;
156 import org.netxms.client.objecttools.ObjectToolDetails;
157 import org.netxms.client.packages.PackageDeploymentListener;
158 import org.netxms.client.packages.PackageInfo;
159 import org.netxms.client.situations.Situation;
160 import org.netxms.client.snmp.SnmpTrap;
161 import org.netxms.client.snmp.SnmpTrapLogRecord;
162 import org.netxms.client.snmp.SnmpUsmCredential;
163 import org.netxms.client.snmp.SnmpValue;
164 import org.netxms.client.snmp.SnmpWalkListener;
165 import org.netxms.client.topology.ConnectionPoint;
166 import org.netxms.client.topology.NetworkPath;
167 import org.netxms.client.topology.VlanInfo;
168 import org.netxms.client.topology.WirelessStation;
169
170 /**
171 * Communication session with NetXMS server.
172 */
173 public class NXCSession implements Session, ScriptLibraryManager, UserManager, ServerManager, ImageLibraryManager, ReportingServerManager
174 {
175 // Various public constants
176 public static final int DEFAULT_CONN_PORT = 4701;
177 public static final int CLIENT_PROTOCOL_VERSION = 43;
178
179 // Authentication types
180 public static final int AUTH_TYPE_PASSWORD = 0;
181 public static final int AUTH_TYPE_CERTIFICATE = 1;
182 public static final int AUTH_TYPE_SSO_TICKET = 2;
183
184 // Notification channels
185 public static final int CHANNEL_EVENTS = 0x0001;
186 public static final int CHANNEL_SYSLOG = 0x0002;
187 public static final int CHANNEL_ALARMS = 0x0004;
188 public static final int CHANNEL_OBJECTS = 0x0008;
189 public static final int CHANNEL_SNMP_TRAPS = 0x0010;
190 public static final int CHANNEL_AUDIT_LOG = 0x0020;
191 public static final int CHANNEL_SITUATIONS = 0x0040;
192
193 // Object sync options
194 public static final int OBJECT_SYNC_NOTIFY = 0x0001;
195 public static final int OBJECT_SYNC_WAIT = 0x0002;
196
197 // Configuration import options
198 public static final int CFG_IMPORT_REPLACE_EVENT_BY_CODE = 0x0001;
199 public static final int CFG_IMPORT_REPLACE_EVENT_BY_NAME = 0x0002;
200
201 // Address list IDs
202 public static final int ADDRESS_LIST_DISCOVERY_TARGETS = 1;
203 public static final int ADDRESS_LIST_DISCOVERY_FILTER = 2;
204
205 // Server components
206 public static final int SERVER_COMPONENT_DISCOVERY_MANAGER = 1;
207
208 // Client types
209 public static final int DESKTOP_CLIENT = 0;
210 public static final int WEB_CLIENT = 1;
211 public static final int MOBILE_CLIENT = 2;
212 public static final int TABLET_CLIENT = 3;
213 public static final int APPLICATION_CLIENT = 4;
214
215 // Private constants
216 private static final int CLIENT_CHALLENGE_SIZE = 256;
217 private static final int MAX_DCI_DATA_ROWS = 200000;
218 private static final int MAX_DCI_STRING_VALUE_LENGTH = 256;
219 private static final int RECEIVED_FILE_TTL = 300000; // 300 seconds
220 private static final int FILE_BUFFER_SIZE = 128 * 1024; // 128k
221
222 // Internal synchronization objects
223 private final Semaphore syncObjects = new Semaphore(1);
224 private final Semaphore syncUserDB = new Semaphore(1);
225
226 // Connection-related attributes
227 private String connAddress;
228 private int connPort;
229 private String connLoginName;
230 private String connPassword;
231 private boolean connUseEncryption;
232 private String connClientInfo = "nxjclient/" + NXCommon.VERSION;
233 private int clientType = DESKTOP_CLIENT;
234 private String clientAddress = null;
235 private int authType = AUTH_TYPE_PASSWORD;
236 private boolean ignoreProtocolVersion = false;
237 private Certificate connCertificate = null;
238 private Signature connSignature = null;
239
240 // Information about logged in user
241 private int sessionId;
242 private int userId;
243 private long userSystemRights;
244 private boolean passwordExpired;
245
246 // Internal communication data
247 private Socket connSocket = null;
248 private NXCPMsgWaitQueue msgWaitQueue = null;
249 private ReceiverThread recvThread = null;
250 private HousekeeperThread housekeeperThread = null;
251 private AtomicLong requestId = new AtomicLong(1);
252 private boolean isConnected = false;
253 private boolean serverConsoleConnected = false;
254 private EncryptionContext encryptionContext = null;
255
256 // Communication parameters
257 private int defaultRecvBufferSize = 4194304; // Default is 4MB
258 private int maxRecvBufferSize = 33554432; // Max is 32MB
259 private int commandTimeout = 30000; // Default is 30 sec
260
261 // Notification listeners and queue
262 private LinkedBlockingQueue<SessionNotification> notificationQueue = new LinkedBlockingQueue<SessionNotification>(8192);
263 private Set<SessionListener> listeners = new HashSet<SessionListener>(0);
264 private Set<ServerConsoleListener> consoleListeners = new HashSet<ServerConsoleListener>(0);
265
266 // Received files
267 private Map<Long, NXCReceivedFile> receivedFiles = new HashMap<Long, NXCReceivedFile>();
268
269 // Received file updates(for file monitoring)
270 private Map<String, String> recievedUpdates = new HashMap<String, String>();
271
272 // Server information
273 private String serverVersion = "(unknown)";
274 private byte[] serverId = new byte[8];
275 private String serverTimeZone;
276 private byte[] serverChallenge = new byte[CLIENT_CHALLENGE_SIZE];
277 private boolean zoningEnabled = false;
278 private boolean helpdeskLinkActive = false;
279 private String tileServerURL;
280 private String dateFormat;
281 private String timeFormat;
282 private String shortTimeFormat;
283 private int defaultDciRetentionTime;
284 private int defaultDciPollingInterval;
285 private boolean strictAlarmStatusFlow;
286 private boolean timedAlarmAckEnabled;
287 private int minViewRefreshInterval;
288 private long serverTime = System.currentTimeMillis();
289 private long serverTimeRecvTime = System.currentTimeMillis();
290
291 // Objects
292 private Map<Long, AbstractObject> objectList = new HashMap<Long, AbstractObject>();
293 private boolean objectsSynchronized = false;
294
295 // Users
296 private Map<Long, AbstractUserObject> userDB = new HashMap<Long, AbstractUserObject>();
297
298 // Event templates
299 private Map<Long, EventTemplate> eventTemplates = new HashMap<Long, EventTemplate>();
300 private boolean eventTemplatesNeedSync = false;
301
302 /**
303 * @param connAddress
304 * @param connPort
305 * @param connLoginName
306 */
307 public NXCSession(String connAddress, int connPort, String connLoginName)
308 {
309 this(connAddress, DEFAULT_CONN_PORT, connLoginName, "", false);
310 }
311
312 /**
313 * @param connAddress
314 * @param connLoginName
315 * @param connPassword
316 */
317 public NXCSession(String connAddress, String connLoginName, String connPassword)
318 {
319 this(connAddress, DEFAULT_CONN_PORT, connLoginName, connPassword, false);
320 }
321
322 /**
323 * @param connAddress
324 * @param connPort
325 * @param connLoginName
326 * @param connPassword
327 */
328 public NXCSession(String connAddress, int connPort, String connLoginName, String connPassword)
329 {
330 this(connAddress, connPort, connLoginName, connPassword, false);
331 }
332
333 /**
334 * @param connAddress
335 * @param connPort
336 * @param connLoginName
337 * @param connPassword
338 * @param connUseEncryption
339 */
340 public NXCSession(String connAddress, int connPort, String connLoginName, String connPassword, boolean connUseEncryption)
341 {
342 this.connAddress = connAddress;
343 this.connPort = connPort;
344 this.connLoginName = connLoginName;
345 this.connPassword = connPassword;
346 this.connUseEncryption = connUseEncryption;
347 }
348
349 /*
350 * (non-Javadoc)
351 *
352 * @see java.lang.Object#finalize()
353 */
354 @Override
355 protected void finalize() throws Throwable
356 {
357 try
358 {
359 disconnect();
360 }
361 finally
362 {
363 super.finalize();
364 }
365 }
366
367 /**
368 * Convert IP address to 32 bit integer
369 *
370 * @param addr
371 * @return
372 */
373 private static long int32FromInetAddress(InetAddress addr)
374 {
375 byte[] bytes = addr.getAddress();
376 return (((long)bytes[0] & 0xFF) << 24) | (((long)bytes[1] & 0xFF) << 16) | (((long)bytes[2] & 0xFF) << 8) | ((long)bytes[3] & 0xFF);
377 }
378
379 /**
380 * Create custom object from NXCP message. May be overridden by derived classes to create custom
381 * NetXMS objects. This method called before standard object creation, so it can be used for
382 * overriding standard object classes. If this method returns null, standard object
383 * creation mechanism will be used. Default implementation will always return null.
384 *
385 * @param objectClass NetXMS object class ID
386 * @param msg Source NXCP message
387 * @return NetXMS object or null if object cannot be created
388 */
389 protected AbstractObject createCustomObjectFromMessage(int objectClass, NXCPMessage msg)
390 {
391 return null;
392 }
393
394 /**
395 * Create object from message
396 *
397 * @param msg Source NXCP message
398 * @return NetXMS object
399 */
400 private AbstractObject createObjectFromMessage(NXCPMessage msg)
401 {
402 final int objectClass = msg.getVariableAsInteger(NXCPCodes.VID_OBJECT_CLASS);
403
404 AbstractObject object = createCustomObjectFromMessage(objectClass, msg);
405 if (object != null)
406 return object;
407
408 switch(objectClass)
409 {
410 case AbstractObject.OBJECT_ACCESSPOINT:
411 object = new AccessPoint(msg, this);
412 break;
413 case AbstractObject.OBJECT_AGENTPOLICY:
414 object = new AgentPolicy(msg, this);
415 break;
416 case AbstractObject.OBJECT_AGENTPOLICY_CONFIG:
417 object = new AgentPolicyConfig(msg, this);
418 break;
419 case AbstractObject.OBJECT_BUSINESSSERVICE:
420 object = new BusinessService(msg, this);
421 break;
422 case AbstractObject.OBJECT_BUSINESSSERVICEROOT:
423 object = new BusinessServiceRoot(msg, this);
424 break;
425 case AbstractObject.OBJECT_CLUSTER:
426 object = new Cluster(msg, this);
427 break;
428 case AbstractObject.OBJECT_CONDITION:
429 object = new Condition(msg, this);
430 break;
431 case AbstractObject.OBJECT_CONTAINER:
432 object = new Container(msg, this);
433 break;
434 case AbstractObject.OBJECT_DASHBOARD:
435 object = new Dashboard(msg, this);
436 break;
437 case AbstractObject.OBJECT_DASHBOARDROOT:
438 object = new DashboardRoot(msg, this);
439 break;
440 case AbstractObject.OBJECT_INTERFACE:
441 object = new Interface(msg, this);
442 break;
443 case AbstractObject.OBJECT_MOBILEDEVICE:
444 object = new MobileDevice(msg, this);
445 break;
446 case AbstractObject.OBJECT_NETWORK:
447 object = new EntireNetwork(msg, this);
448 break;
449 case AbstractObject.OBJECT_NETWORKMAP:
450 object = new NetworkMap(msg, this);
451 break;
452 case AbstractObject.OBJECT_NETWORKMAPGROUP:
453 object = new NetworkMapGroup(msg, this);
454 break;
455 case AbstractObject.OBJECT_NETWORKMAPROOT:
456 object = new NetworkMapRoot(msg, this);
457 break;
458 case AbstractObject.OBJECT_NETWORKSERVICE:
459 object = new NetworkService(msg, this);
460 break;
461 case AbstractObject.OBJECT_NODE:
462 object = new Node(msg, this);
463 break;
464 case AbstractObject.OBJECT_NODELINK:
465 object = new NodeLink(msg, this);
466 break;
467 case AbstractObject.OBJECT_POLICYGROUP:
468 object = new PolicyGroup(msg, this);
469 break;
470 case AbstractObject.OBJECT_POLICYROOT:
471 object = new PolicyRoot(msg, this);
472 break;
473 case AbstractObject.OBJECT_RACK:
474 object = new Rack(msg, this);
475 break;
476 case AbstractObject.OBJECT_SERVICEROOT:
477 object = new ServiceRoot(msg, this);
478 break;
479 case AbstractObject.OBJECT_SLMCHECK:
480 object = new ServiceCheck(msg, this);
481 break;
482 case AbstractObject.OBJECT_SUBNET:
483 object = new Subnet(msg, this);
484 break;
485 case AbstractObject.OBJECT_TEMPLATE:
486 object = new Template(msg, this);
487 break;
488 case AbstractObject.OBJECT_TEMPLATEGROUP:
489 object = new TemplateGroup(msg, this);
490 break;
491 case AbstractObject.OBJECT_TEMPLATEROOT:
492 object = new TemplateRoot(msg, this);
493 break;
494 case AbstractObject.OBJECT_VPNCONNECTOR:
495 object = new VPNConnector(msg, this);
496 break;
497 case AbstractObject.OBJECT_ZONE:
498 object = new Zone(msg, this);
499 break;
500 default:
501 object = new GenericObject(msg, this);
502 break;
503 }
504
505 return object;
506 }
507
508 /**
509 * Setup encryption
510 *
511 * @param msg CMD_REQUEST_SESSION_KEY message
512 * @throws IOException
513 * @throws NXCException
514 */
515 private void setupEncryption(NXCPMessage msg) throws IOException, NXCException
516 {
517 final NXCPMessage response = new NXCPMessage(NXCPCodes.CMD_SESSION_KEY, msg.getMessageId());
518 response.setEncryptionDisabled(true);
519
520 try
521 {
522 encryptionContext = EncryptionContext.createInstance(msg);
523 response.setVariable(NXCPCodes.VID_SESSION_KEY, encryptionContext.getEncryptedSessionKey(msg));
524 response.setVariable(NXCPCodes.VID_SESSION_IV, encryptionContext.getEncryptedIv(msg));
525 response.setVariableInt16(NXCPCodes.VID_CIPHER, encryptionContext.getCipher());
526 response.setVariableInt16(NXCPCodes.VID_KEY_LENGTH, encryptionContext.getKeyLength());
527 response.setVariableInt16(NXCPCodes.VID_IV_LENGTH, encryptionContext.getIvLength());
528 response.setVariableInt32(NXCPCodes.VID_RCC, RCC.SUCCESS);
529 }
530 catch(Exception e)
531 {
532 response.setVariableInt32(NXCPCodes.VID_RCC, RCC.NO_CIPHERS);
533 }
534
535 sendMessage(response);
536 }
537
538 /**
539 * Receiver thread for NXCSession
540 */
541 private class ReceiverThread extends Thread
542 {
543 ReceiverThread()
544 {
545 setDaemon(true);
546 start();
547 }
548
549 @Override
550 public void run()
551 {
552 final NXCPMessageReceiver receiver = new NXCPMessageReceiver(defaultRecvBufferSize, maxRecvBufferSize);
553 InputStream in;
554
555 try
556 {
557 in = connSocket.getInputStream();
558 }
559 catch(IOException e)
560 {
561 return; // Stop receiver thread if input stream cannot be obtained
562 }
563
564 while(connSocket.isConnected())
565 {
566 try
567 {
568 final NXCPMessage msg = receiver.receiveMessage(in, encryptionContext);
569 switch(msg.getMessageCode())
570 {
571 case NXCPCodes.CMD_REQUEST_SESSION_KEY:
572 setupEncryption(msg);
573 break;
574 case NXCPCodes.CMD_KEEPALIVE:
575 serverTime = msg.getVariableAsInt64(NXCPCodes.VID_TIMESTAMP) * 1000;
576 serverTimeRecvTime = System.currentTimeMillis();
577 break;
578 case NXCPCodes.CMD_OBJECT:
579 case NXCPCodes.CMD_OBJECT_UPDATE:
580 if (!msg.getVariableAsBoolean(NXCPCodes.VID_IS_DELETED))
581 {
582 final AbstractObject obj = createObjectFromMessage(msg);
583 synchronized(objectList)
584 {
585 objectList.put(obj.getObjectId(), obj);
586 }
587 if (msg.getMessageCode() == NXCPCodes.CMD_OBJECT_UPDATE)
588 {
589 sendNotification(new NXCNotification(NXCNotification.OBJECT_CHANGED, obj.getObjectId(), obj));
590 }
591 }
592 else
593 {
594 long objectId = msg.getVariableAsInteger(NXCPCodes.VID_OBJECT_ID);
595 synchronized(objectList)
596 {
597 objectList.remove(objectId);
598 }
599 sendNotification(new NXCNotification(NXCNotification.OBJECT_DELETED, objectId));
600 }
601 break;
602 case NXCPCodes.CMD_OBJECT_LIST_END:
603 completeSync(syncObjects);
604 break;
605 case NXCPCodes.CMD_USER_DATA:
606 final User user = new User(msg);
607 synchronized(userDB)
608 {
609 if (user.isDeleted())
610 {
611 userDB.remove(user.getId());
612 }
613 else
614 {
615 userDB.put(user.getId(), user);
616 }
617 }
618 break;
619 case NXCPCodes.CMD_GROUP_DATA:
620 final UserGroup group = new UserGroup(msg);
621 synchronized(userDB)
622 {
623 if (group.isDeleted())
624 {
625 userDB.remove(group.getId());
626 }
627 else
628 {
629 userDB.put(group.getId(), group);
630 }
631 }
632 break;
633 case NXCPCodes.CMD_USER_DB_EOF:
634 completeSync(syncUserDB);
635 break;
636 case NXCPCodes.CMD_USER_DB_UPDATE:
637 processUserDBUpdate(msg);
638 break;
639 case NXCPCodes.CMD_ALARM_UPDATE:
640 sendNotification(new NXCNotification(
641 msg.getVariableAsInteger(NXCPCodes.VID_NOTIFICATION_CODE) + NXCNotification.NOTIFY_BASE,
642 new Alarm(msg)));
643 break;
644 case NXCPCodes.CMD_JOB_CHANGE_NOTIFICATION:
645 sendNotification(new NXCNotification(NXCNotification.JOB_CHANGE, new ServerJob(msg)));
646 break;
647 case NXCPCodes.CMD_FILE_DATA:
648 processFileData(msg);
649 break;
650 case NXCPCodes.CMD_FILE_MONITORING:
651 processFileTail(msg);
652 break;
653 case NXCPCodes.CMD_ABORT_FILE_TRANSFER:
654 processFileTransferError(msg);
655 break;
656 case NXCPCodes.CMD_NOTIFY:
657 processNotificationMessage(msg, true);
658 break;
659 case NXCPCodes.CMD_RS_NOTIFY:
660 processNotificationMessage(msg, false);
661 break;
662 case NXCPCodes.CMD_EVENTLOG_RECORDS:
663 processNewEvents(msg);
664 break;
665 case NXCPCodes.CMD_TRAP_LOG_RECORDS:
666 processNewTraps(msg);
667 break;
668 case NXCPCodes.CMD_SYSLOG_RECORDS:
669 processSyslogRecords(msg);
670 break;
671 case NXCPCodes.CMD_ACTION_DB_UPDATE:
672 processActionConfigChange(msg);
673 break;
674 case NXCPCodes.CMD_EVENT_DB_UPDATE:
675 processEventConfigChange(msg);
676 break;
677 case NXCPCodes.CMD_TRAP_CFG_UPDATE:
678 processTrapConfigChange(msg);
679 break;
680 case NXCPCodes.CMD_SITUATION_CHANGE:
681 processSituationChange(msg);
682 break;
683 case NXCPCodes.CMD_ADM_MESSAGE:
684 processConsoleOutput(msg);
685 break;
686 case NXCPCodes.CMD_IMAGE_LIBRARY_UPDATE:
687 processImageLibraryUpdate(msg);
688 break;
689 default:
690 if (msg.getMessageCode() >= 0x1000)
691 {
692 // Custom message
693 sendNotification(new NXCNotification(NXCNotification.CUSTOM_MESSAGE, msg));
694 }
695 msgWaitQueue.putMessage(msg);
696 break;
697 }
698 }
699 catch(IOException e)
700 {
701 break; // Stop on read errors
702 }
703 catch(NXCPException e)
704 {
705 if (e.getErrorCode() == NXCPException.SESSION_CLOSED) break;
706 }
707 catch(NXCException e)
708 {
709 if (e.getErrorCode() == RCC.ENCRYPTION_ERROR) break;
710 }
711 }
712 }
713
714 /**
715 * Process server console output
716 *
717 * @param msg notification message
718 */
719 private void processConsoleOutput(NXCPMessage msg)
720 {
721 final String text = msg.getVariableAsString(NXCPCodes.VID_MESSAGE);
722 synchronized(consoleListeners)
723 {
724 for(ServerConsoleListener l : consoleListeners)
725 {
726 l.onConsoleOutput(text);
727 }
728 }
729 }
730
731 /**
732 * Process event notification messages.
733 *
734 * @param msg NXCP message
735 */
736 private void processNewEvents(final NXCPMessage msg)
737 {
738 int count = msg.getVariableAsInteger(NXCPCodes.VID_NUM_RECORDS);
739 int order = msg.getVariableAsInteger(NXCPCodes.VID_RECORDS_ORDER);
740 long varId = NXCPCodes.VID_EVENTLOG_MSG_BASE;
741 for(int i = 0; i < count; i++)
742 {
743 Event event = new Event(msg, varId);
744 sendNotification(new NXCNotification(NXCNotification.NEW_EVENTLOG_RECORD, order, event));
745 }
746 }
747
748 /**
749 * Process SNMP trap notification messages.
750 *
751 * @param msg NXCP message
752 */
753 private void processNewTraps(final NXCPMessage msg)
754 {
755 int count = msg.getVariableAsInteger(NXCPCodes.VID_NUM_RECORDS);
756 int order = msg.getVariableAsInteger(NXCPCodes.VID_RECORDS_ORDER);
757 long varId = NXCPCodes.VID_TRAP_LOG_MSG_BASE;
758 for(int i = 0; i < count; i++)
759 {
760 SnmpTrapLogRecord trap = new SnmpTrapLogRecord(msg, varId);
761 sendNotification(new NXCNotification(NXCNotification.NEW_SNMP_TRAP, order, trap));
762 }
763 }
764
765 /**
766 * Process syslog messages.
767 *
768 * @param msg NXCP message
769 */
770 private void processSyslogRecords(final NXCPMessage msg)
771 {
772 int count = msg.getVariableAsInteger(NXCPCodes.VID_NUM_RECORDS);
773 int order = msg.getVariableAsInteger(NXCPCodes.VID_RECORDS_ORDER);
774 long varId = NXCPCodes.VID_SYSLOG_MSG_BASE;
775 for(int i = 0; i < count; i++)
776 {
777 SyslogRecord record = new SyslogRecord(msg, varId);
778 sendNotification(new NXCNotification(NXCNotification.NEW_SYSLOG_RECORD, order, record));
779 }
780 }
781
782 /**
783 * Process CMD_NOTIFY message
784 *
785 * @param msg NXCP message
786 */
787 private void processNotificationMessage(final NXCPMessage msg, boolean shiftCode)
788 {
789 int code = msg.getVariableAsInteger(NXCPCodes.VID_NOTIFICATION_CODE);
790 if (shiftCode)
791 code += NXCNotification.NOTIFY_BASE;
792 long data = msg.getVariableAsInt64(NXCPCodes.VID_NOTIFICATION_DATA);
793 if(code == NXCNotification.ALARM_STATUS_FLOW_CHANGED)
794 {
795 strictAlarmStatusFlow = ((int)data != 0);
796 }
797 sendNotification(new NXCNotification(code, data));
798 }
799
800 /**
801 * Process CMD_FILE_MONITORING message
802 *
803 * @param msg NXCP message
804 */
805 private void processFileTail(final NXCPMessage msg)
806 {
807 String fileName = msg.getVariableAsString(NXCPCodes.VID_FILE_NAME);
808 String fileContent = msg.getVariableAsString(NXCPCodes.VID_FILE_DATA);
809
810 synchronized(recievedUpdates)
811 {
812 recievedUpdates.put(fileName, fileContent);
813 recievedUpdates.notifyAll();
814 }
815 }
816
817 /**
818 * Process file data
819 *
820 * @param msg
821 */
822 private void processFileData(final NXCPMessage msg)
823 {
824 long id = msg.getMessageId();
825 NXCReceivedFile file;
826 synchronized(receivedFiles)
827 {
828 file = receivedFiles.get(id);
829 if (file == null)
830 {
831 file = new NXCReceivedFile(id);
832 receivedFiles.put(id, file);
833 }
834 }
835 file.writeData(msg.getBinaryData());
836 if (msg.isEndOfFile())
837 {
838 file.close();
839 synchronized(receivedFiles)
840 {
841 receivedFiles.notifyAll();
842 }
843 }
844 }
845
846 /**
847 * Process file transfer error
848 *
849 * @param msg
850 */
851 private void processFileTransferError(final NXCPMessage msg)
852 {
853 long id = msg.getMessageId();
854 NXCReceivedFile file;
855 synchronized(receivedFiles)
856 {
857 file = receivedFiles.get(id);
858 if (file == null)
859 {
860 file = new NXCReceivedFile(id);
861 receivedFiles.put(id, file);
862 }
863 file.close();
864 receivedFiles.notifyAll();
865 }
866 }
867
868 /**
869 * Process updates in user database
870 *
871 * @param msg Notification message
872 */
873 private void processUserDBUpdate(final NXCPMessage msg)
874 {
875 final int code = msg.getVariableAsInteger(NXCPCodes.VID_UPDATE_TYPE);
876 final long id = msg.getVariableAsInt64(NXCPCodes.VID_USER_ID);
877
878 AbstractUserObject object = null;
879 switch(code)
880 {
881 case NXCNotification.USER_DB_OBJECT_CREATED:
882 case NXCNotification.USER_DB_OBJECT_MODIFIED:
883 object = ((id & 0x80000000) != 0) ? new UserGroup(msg) : new User(msg);
884 synchronized(userDB)
885 {
886 userDB.put(id, object);
887 }
888 break;
889 case NXCNotification.USER_DB_OBJECT_DELETED:
890 synchronized(userDB)
891 {
892 object = userDB.get(id);
893 if (object != null)
894 {
895 userDB.remove(id);
896 }
897 }
898 break;
899 }
900
901 // Send notification if changed object was found in local database copy
902 // or added to it and notification code was known
903 if (object != null) sendNotification(new NXCNotification(NXCNotification.USER_DB_CHANGED, code, object));
904 }
905
906 /**
907 * Process server notification on SNMP trap configuration change
908 *
909 * @param msg notification message
910 */
911 private void processTrapConfigChange(final NXCPMessage msg)
912 {
913 int code = msg.getVariableAsInteger(NXCPCodes.VID_NOTIFICATION_CODE) + NXCNotification.NOTIFY_BASE;
914 long id = msg.getVariableAsInt64(NXCPCodes.VID_TRAP_ID);
915 SnmpTrap trap = (code != NXCNotification.TRAP_CONFIGURATION_DELETED) ? new SnmpTrap(msg) : null;
916 sendNotification(new NXCNotification(code, id, trap));
917 }
918
919 /**
920 * Process server notification on situation object change
921 *
922 * @param msg notification message
923 */
924 private void processSituationChange(final NXCPMessage msg)
925 {
926 int code = msg.getVariableAsInteger(NXCPCodes.VID_NOTIFICATION_CODE) + NXCNotification.SITUATION_BASE;
927 Situation s = new Situation(msg);
928 sendNotification(new NXCNotification(code, s.getId(), s));
929 }
930
931 /**
932 * Process server notification on action configuration change
933 *
934 * @param msg notification message
935 */
936 private void processActionConfigChange(final NXCPMessage msg)
937 {
938 int code = msg.getVariableAsInteger(NXCPCodes.VID_NOTIFICATION_CODE) + NXCNotification.NOTIFY_BASE;
939 long id = msg.getVariableAsInt64(NXCPCodes.VID_ACTION_ID);
940 ServerAction action = (code != NXCNotification.ACTION_DELETED) ? new ServerAction(msg) : null;
941 sendNotification(new NXCNotification(code, id, action));
942 }
943
944 /**
945 * Process server notification on event configuration change
946 *
947 * @param msg notification message
948 */
949 private void processEventConfigChange(final NXCPMessage msg)
950 {
951 int code = msg.getVariableAsInteger(NXCPCodes.VID_NOTIFICATION_CODE) + NXCNotification.NOTIFY_BASE;
952 long eventCode = msg.getVariableAsInt64(NXCPCodes.VID_EVENT_CODE);
953 EventTemplate et = (code != NXCNotification.EVENT_TEMPLATE_DELETED) ? new EventTemplate(msg) : null;
954 if (eventTemplatesNeedSync)
955 {
956 synchronized(eventTemplates)
957 {
958 if (code == NXCNotification.EVENT_TEMPLATE_DELETED)
959 {
960 eventTemplates.remove(eventCode);
961 }
962 else
963 {
964 eventTemplates.put(eventCode, et);
965 }
966 }
967 }
968 sendNotification(new NXCNotification(code, eventCode, et));
969 }
970
971 /**
972 * Process server notification on image library change
973 *
974 * @param msg notification message
975 */
976 public void processImageLibraryUpdate(NXCPMessage msg)
977 {
978 final UUID imageGuid = msg.getVariableAsUUID(NXCPCodes.VID_GUID);
979 final int flags = msg.getVariableAsInteger(NXCPCodes.VID_FLAGS);
980 sendNotification(new NXCNotification(NXCNotification.IMAGE_LIBRARY_CHANGED,
981 flags == 0 ? NXCNotification.IMAGE_UPDATED : NXCNotification.IMAGE_DELETED, imageGuid));
982 }
983 }
984
985 /**
986 * Housekeeper thread - cleans received files, etc.
987 *
988 * @author Victor
989 */
990 private class HousekeeperThread extends Thread
991 {
992 private boolean stopFlag = false;
993
994 HousekeeperThread()
995 {
996 setDaemon(true);
997 start();
998 }
999
1000 /*
1001 * (non-Javadoc)
1002 *
1003 * @see java.lang.Thread#run()
1004 */
1005 @Override
1006 public void run()
1007 {
1008 while(!stopFlag)
1009 {
1010 try
1011 {
1012 sleep(1000);
1013 }
1014 catch(InterruptedException e)
1015 {
1016 }
1017
1018 // Check for old entries in received files
1019 synchronized(receivedFiles)
1020 {
1021 long currTime = System.currentTimeMillis();
1022 Iterator<NXCReceivedFile> it = receivedFiles.values().iterator();
1023 while(it.hasNext())
1024 {
1025 NXCReceivedFile file = it.next();
1026 if (file.getTimestamp() + RECEIVED_FILE_TTL < currTime)
1027 {
1028 file.getFile().delete();
1029 it.remove();
1030 }
1031 }
1032 }
1033 }
1034 }
1035
1036 /**
1037 * @param stopFlag the stopFlag to set
1038 */
1039 public void setStopFlag(boolean stopFlag)
1040 {
1041 this.stopFlag = stopFlag;
1042 }
1043 }
1044
1045 /**
1046 * @return the authType
1047 */
1048 public int getAuthType()
1049 {
1050 return authType;
1051 }
1052
1053 /**
1054 * @param authType the authType to set
1055 */
1056 public void setAuthType(int authType)
1057 {
1058 this.authType = authType;
1059 }
1060
1061 /**
1062 * Wait for synchronization completion
1063 */
1064 private void waitForSync(final Semaphore syncObject, final int timeout) throws NXCException
1065 {
1066 if (timeout == 0)
1067 {
1068 syncObject.acquireUninterruptibly();
1069 }
1070 else
1071 {
1072 long actualTimeout = timeout;
1073 boolean success = false;
1074
1075 while(actualTimeout > 0)
1076 {
1077 long startTime = System.currentTimeMillis();
1078 try
1079 {
1080 if (syncObjects.tryAcquire(actualTimeout, TimeUnit.MILLISECONDS))
1081 {
1082 success = true;
1083 syncObjects.release();
1084 break;
1085 }
1086 }
1087 catch(InterruptedException e)
1088 {
1089 }
1090 actualTimeout -= System.currentTimeMillis() - startTime;
1091 }
1092 if (!success) throw new NXCException(RCC.TIMEOUT);
1093 }
1094 }
1095
1096 /**
1097 * Report synchronization completion
1098 *
1099 * @param syncObject Synchronization object
1100 */
1101 private void completeSync(final Semaphore syncObject)
1102 {
1103 syncObject.release();
1104 }
1105
1106 /*
1107 * (non-Javadoc)
1108 *
1109 * @see org.netxms.api.client.Session#addListener(org.netxms.api.client.
1110 * SessionListener)
1111 */
1112 @Override
1113 public void addListener(SessionListener listener)
1114 {
1115 boolean changed;
1116 synchronized(listeners)
1117 {
1118 changed = listeners.add(listener);
1119 }
1120 if (changed)
1121 notificationQueue.offer(new NXCNotification(NXCNotification.UPDATE_LISTENER_LIST));
1122 }
1123
1124 /*
1125 * (non-Javadoc)
1126 *
1127 * @see org.netxms.api.client.Session#removeListener(org.netxms.api.client.
1128 * SessionListener)
1129 */
1130 @Override
1131 public void removeListener(SessionListener listener)
1132 {
1133 boolean changed;
1134 synchronized(listeners)
1135 {
1136 changed = listeners.remove(listener);
1137 }
1138 if (changed)
1139 notificationQueue.offer(new NXCNotification(NXCNotification.UPDATE_LISTENER_LIST));
1140 }
1141
1142 /**
1143 * Add server console listener
1144 *
1145 * @param listener
1146 */
1147 public void addConsoleListener(ServerConsoleListener listener)
1148 {
1149 synchronized(consoleListeners)
1150 {
1151 consoleListeners.add(listener);
1152 }
1153 }
1154
1155 /**
1156 * Remove server console listener
1157 *
1158 * @param listener
1159 */
1160 public void removeConsoleListener(ServerConsoleListener listener)
1161 {
1162 synchronized(consoleListeners)
1163 {
1164 consoleListeners.remove(listener);
1165 }
1166 }
1167
1168 /**
1169 * Notification processor
1170 */
1171 private class NotificationProcessor extends Thread
1172 {
1173 private SessionListener[] cachedListenerList = new SessionListener[0];
1174
1175 NotificationProcessor()
1176 {
1177 setDaemon(true);
1178 start();
1179 }
1180
1181 /* (non-Javadoc)
1182 * @see java.lang.Thread#run()
1183 */
1184 @Override
1185 public void run()
1186 {
1187 while(true)
1188 {
1189 SessionNotification n;
1190 try
1191 {
1192 n = notificationQueue.take();
1193 }
1194 catch(InterruptedException e)
1195 {
1196 continue;
1197 }
1198
1199 if (n.getCode() == NXCNotification.STOP_PROCESSING_THREAD)
1200 break;
1201
1202 if (n.getCode() == NXCNotification.UPDATE_LISTENER_LIST)
1203 {
1204 synchronized(listeners)
1205 {
1206 cachedListenerList = listeners.toArray(new SessionListener[listeners.size()]);
1207 }
1208 continue;
1209 }
1210
1211 // loop must be on listeners set copy to prevent
1212 // possible deadlock when one of the listeners calls
1213 // syncExec on UI thread while UI thread trying to add
1214 // new listener and stays locked inside addListener
1215 for(SessionListener l : cachedListenerList)
1216 {
1217 try
1218 {
1219 l.notificationHandler(n);
1220 }
1221 catch(Exception e)
1222 {
1223 Logger.error("NXCSession.NotificationProcessor", "Unhandled exception in notification handler", e);
1224 }
1225 }
1226 }
1227 }
1228 }
1229
1230 /**
1231 * Call notification handlers on all registered listeners
1232 *
1233 * @param n Notification object
1234 */
1235 protected void sendNotification(NXCNotification n)
1236 {
1237 if (!notificationQueue.offer(n))
1238 {
1239 Logger.debug("NXCSession.sendNotification", "Notification processing queue is full");
1240 }
1241 }
1242
1243 /**
1244 * Send message to server
1245 *
1246 * @param msg Message to sent
1247 * @throws IOException in case of socket communication failure
1248 * @throws NXCException in case of encryption error
1249 */
1250 public synchronized void sendMessage(final NXCPMessage msg) throws IOException, NXCException
1251 {
1252 if (connSocket == null)
1253 {
1254 throw new IllegalStateException("Not connected to the server. Did you forgot to call connect() first?");
1255 }
1256 final OutputStream outputStream = connSocket.getOutputStream();
1257 byte[] message;
1258 if ((encryptionContext != null) && !msg.isEncryptionDisabled())
1259 {
1260 try
1261 {
1262 message = encryptionContext.encryptMessage(msg);
1263 }
1264 catch(GeneralSecurityException e)
1265 {
1266 throw new NXCException(RCC.ENCRYPTION_ERROR);
1267 }
1268 }
1269 else
1270 {
1271 message = msg.createNXCPMessage();
1272 }
1273 outputStream.write(message);
1274 }
1275
1276 /**
1277 * Send file over CSCP
1278 *
1279 * @param requestId
1280 * @param file source file to be sent
1281 * @throws IOException
1282 * @throws NXCException
1283 */
1284 protected void sendFile(final long requestId, final File file, ProgressListener listener)
1285 throws IOException, NXCException
1286 {
1287 if (listener != null) listener.setTotalWorkAmount(file.length());
1288 final InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
1289 sendFileStream(requestId, inputStream, listener);
1290 inputStream.close();
1291 }
1292
1293 /**
1294 * Send block of data as binary message
1295 *
1296 * @param requestId
1297 * @param data
1298 * @throws IOException
1299 * @throws NXCException
1300 */
1301 protected void sendFile(final long requestId, final byte[] data, ProgressListener listener)
1302 throws IOException, NXCException
1303 {
1304 if (listener != null) listener.setTotalWorkAmount(data.length);
1305 final InputStream inputStream = new ByteArrayInputStream(data);
1306 sendFileStream(requestId, inputStream, listener);
1307 inputStream.close();
1308 }
1309
1310 /**
1311 * Send binary message, data loaded from provided input stream and splitted
1312 * into chunks of {@value FILE_BUFFER_SIZE} bytes
1313 *
1314 * @param requestId
1315 * @param inputStream
1316 * @throws IOException
1317 * @throws NXCException
1318 */
1319 private void sendFileStream(final long requestId, final InputStream inputStream, ProgressListener listener)
1320 throws IOException, NXCException
1321 {
1322 NXCPMessage msg = new NXCPMessage(NXCPCodes.CMD_FILE_DATA, requestId);
1323 msg.setBinaryMessage(true);
1324
1325 boolean success = false;
1326 final byte[] buffer = new byte[FILE_BUFFER_SIZE];
1327 long bytesSent = 0;
1328 while(true)
1329 {
1330 final int bytesRead = inputStream.read(buffer);
1331 if (bytesRead < FILE_BUFFER_SIZE)
1332 {
1333 msg.setEndOfFile(true);
1334 }
1335
1336 msg.setBinaryData(CompatTools.arrayCopy(buffer, bytesRead));
1337 sendMessage(msg);
1338
1339 bytesSent += bytesRead;
1340 if (listener != null) listener.markProgress(bytesSent);
1341
1342 if (bytesRead < FILE_BUFFER_SIZE)
1343 {
1344 success = true;
1345 break;
1346 }
1347 }
1348
1349 if (!success)
1350 {
1351 NXCPMessage abortMessage = new NXCPMessage(NXCPCodes.CMD_ABORT_FILE_TRANSFER, requestId);
1352 abortMessage.setBinaryMessage(true);
1353 sendMessage(abortMessage);
1354 waitForRCC(abortMessage.getMessageId());
1355 }
1356 }
1357
1358 /*
1359 * (non-Javadoc)
1360 *
1361 * @see org.netxms.api.client.Session#waitForMessage(int, long, int)
1362 */
1363 @Override
1364 public NXCPMessage waitForMessage(final int code, final long id, final int timeout) throws NXCException
1365 {
1366 final NXCPMessage msg = msgWaitQueue.waitForMessage(code, id, timeout);
1367 if (msg == null)
1368 throw new NXCException(RCC.TIMEOUT);
1369 return msg;
1370 }
1371
1372 /*
1373 * (non-Javadoc)
1374 *
1375 * @see org.netxms.api.client.Session#waitForMessage(int, long)
1376 */
1377 @Override
1378 public NXCPMessage waitForMessage(final int code, final long id) throws NXCException
1379 {
1380 final NXCPMessage msg = msgWaitQueue.waitForMessage(code, id);
1381 if (msg == null)
1382 throw new NXCException(RCC.TIMEOUT);
1383 return msg;
1384 }
1385
1386 /*
1387 * (non-Javadoc)
1388 *
1389 * @see org.netxms.api.client.Session#waitForRCC(long)
1390 */
1391 @Override
1392 public NXCPMessage waitForRCC(final long id) throws NXCException
1393 {
1394 return waitForRCC(id, msgWaitQueue.getDefaultTimeout());
1395 }
1396
1397 /*
1398 * (non-Javadoc)
1399 *
1400 * @see org.netxms.api.client.Session#waitForRCC(long, int)
1401 */
1402 public NXCPMessage waitForRCC(final long id, final int timeout) throws NXCException
1403 {
1404 final NXCPMessage msg = waitForMessage(NXCPCodes.CMD_REQUEST_COMPLETED, id, timeout);
1405 final int rcc = msg.getVariableAsInteger(NXCPCodes.VID_RCC);
1406 if (rcc != RCC.SUCCESS)
1407 {
1408 if ((rcc == RCC.COMPONENT_LOCKED) && (msg.findVariable(NXCPCodes.VID_LOCKED_BY) != null))
1409 {
1410 throw new NXCException(rcc, "locked by " + msg.getVariableAsString(NXCPCodes.VID_LOCKED_BY));
1411 }
1412 else if (msg.findVariable(NXCPCodes.VID_ERROR_TEXT) != null)
1413 {
1414 throw new NXCException(rcc, msg.getVariableAsString(NXCPCodes.VID_ERROR_TEXT));
1415 }
1416 else
1417 {
1418 throw new NXCException(rcc);
1419 }
1420 }
1421 return msg;
1422 }
1423
1424 /*
1425 * (non-Javadoc)
1426 *
1427 * @see org.netxms.api.client.Session#newMessage(int)
1428 */
1429 @Override
1430 public final NXCPMessage newMessage(int code)
1431 {
1432 return new NXCPMessage(code, requestId.getAndIncrement());
1433 }
1434
1435 /**
1436 * Wait for specific file to arrive
1437 *
1438 * @param id Message ID
1439 * @param timeout Wait timeout in milliseconds
1440 * @return Received file or null in case of failure
1441 */
1442 public File waitForFile(final long id, final int timeout)
1443 {
1444 int timeRemaining = timeout;
1445 File file = null;
1446
1447 while(timeRemaining > 0)
1448 {
1449 synchronized(receivedFiles)
1450 {
1451 NXCReceivedFile rf = receivedFiles.get(id);
1452 if (rf != null)
1453 {
1454 if (rf.getStatus() != NXCReceivedFile.OPEN)
1455 {
1456 if (rf.getStatus() == NXCReceivedFile.RECEIVED) file = rf.getFile();
1457 break;
1458 }
1459 }
1460
1461 long startTime = System.currentTimeMillis();
1462 try
1463 {
1464 receivedFiles.wait(timeRemaining);
1465 }
1466 catch(InterruptedException e)
1467 {
1468 }
1469 timeRemaining -= System.currentTimeMillis() - startTime;
1470 }
1471 }
1472 return file;
1473 }
1474
1475 /**
1476 * Wait for specific file tail to arrive
1477 *
1478 * @param fileName Waiting file name
1479 * @param timeout Wait timeout in milliseconds
1480 * @return Received tail string or null in case of failure
1481 */
1482 public String waitForFileTail(String fileName, final int timeout)
1483 {
1484 int timeRemaining = timeout;
1485 String tail = null;
1486
1487 while(timeRemaining > 0)
1488 {
1489 synchronized(recievedUpdates)
1490 {
1491 tail = recievedUpdates.get(fileName);
1492 if (tail != null)
1493 {
1494 recievedUpdates.remove(fileName);
1495 break;
1496 }
1497
1498 long startTime = System.currentTimeMillis();
1499 try
1500 {
1501 recievedUpdates.wait(timeRemaining);
1502 }
1503 catch(InterruptedException e)
1504 {
1505 }
1506 timeRemaining -= System.currentTimeMillis() - startTime;
1507 }
1508 }
1509 return tail;
1510 }
1511
1512 /**
1513 * Execute simple commands (without arguments and only returning RCC)
1514 *
1515 * @param command Command code
1516 * @throws IOException
1517 * @throws NXCException
1518 */
1519 protected void executeSimpleCommand(int command) throws IOException, NXCException
1520 {
1521 final NXCPMessage msg = newMessage(command);
1522 sendMessage(msg);
1523 waitForRCC(msg.getMessageId());
1524 }
1525
1526 /**
1527 * Receive table from server.
1528 *
1529 * @param requestId request ID
1530 * @param msgCode Message code
1531 * @return Received table
1532 * @throws NXCException if operation was timed out
1533 */
1534 public Table receiveTable(long requestId, int msgCode) throws NXCException
1535 {
1536 NXCPMessage msg = waitForMessage(msgCode, requestId);
1537 Table table = new Table(msg);
1538 while(!msg.isEndOfSequence())
1539 {
1540 msg = waitForMessage(msgCode, requestId);
1541 table.addDataFromMessage(msg);
1542 }
1543 return table;
1544 }
1545
1546 /*
1547 * (non-Javadoc)
1548 *
1549 * @see org.netxms.api.client.Session#connect()
1550 */
1551 @Override
1552 public void connect() throws IOException, UnknownHostException, NetXMSClientException
1553 {
1554 encryptionContext = null;
1555 Logger.info("NXCSession.connect", "Connecting to " + connAddress + ":" + connPort);
1556 try
1557 {
1558 connSocket = new Socket(connAddress, connPort);
1559 msgWaitQueue = new NXCPMsgWaitQueue(commandTimeout);
1560 recvThread = new ReceiverThread();
1561 housekeeperThread = new HousekeeperThread();
1562 new NotificationProcessor();
1563
1564 // get server information
1565 Logger.debug("NXCSession.connect", "connection established, retrieving server info");
1566 NXCPMessage request = newMessage(NXCPCodes.CMD_GET_SERVER_INFO);
1567 sendMessage(request);
1568 NXCPMessage response = waitForMessage(NXCPCodes.CMD_REQUEST_COMPLETED, request.getMessageId());
1569
1570 if ((response.getVariableAsInteger(NXCPCodes.VID_PROTOCOL_VERSION) != CLIENT_PROTOCOL_VERSION) && !ignoreProtocolVersion)
1571 {
1572 Logger.warning("NXCSession.connect", "connection failed, server protocol version is " +
1573 response.getVariableAsInteger(NXCPCodes.VID_PROTOCOL_VERSION));
1574 throw new NXCException(RCC.BAD_PROTOCOL);
1575 }
1576
1577 serverVersion = response.getVariableAsString(NXCPCodes.VID_SERVER_VERSION);
1578 serverId = response.getVariableAsBinary(NXCPCodes.VID_SERVER_ID);
1579 serverTimeZone = response.getVariableAsString(NXCPCodes.VID_TIMEZONE);
1580 serverTime = response.getVariableAsInt64(NXCPCodes.VID_TIMESTAMP) * 1000;
1581 serverTimeRecvTime = System.currentTimeMillis();
1582 serverChallenge = response.getVariableAsBinary(NXCPCodes.VID_CHALLENGE);
1583
1584 tileServerURL = response.getVariableAsString(NXCPCodes.VID_TILE_SERVER_URL);
1585 if (tileServerURL != null)
1586 {
1587 if (!tileServerURL.endsWith("/")) tileServerURL = tileServerURL.concat("/");
1588 }
1589 else
1590 {
1591 tileServerURL = "http://tile.openstreetmap.org/";
1592 }
1593
1594 dateFormat = response.getVariableAsString(NXCPCodes.VID_DATE_FORMAT);
1595 if ((dateFormat == null) || (dateFormat.length() == 0))
1596 dateFormat = "dd.MM.yyyy";
1597
1598 timeFormat = response.getVariableAsString(NXCPCodes.VID_TIME_FORMAT);
1599 if ((timeFormat == null) || (timeFormat.length() == 0))
1600 timeFormat = "HH:mm:ss";
1601
1602 shortTimeFormat = response.getVariableAsString(NXCPCodes.VID_SHORT_TIME_FORMAT);
1603 if ((shortTimeFormat == null) || (shortTimeFormat.length() == 0))
1604 shortTimeFormat = "HH:mm";
1605
1606 // Setup encryption if required
1607 if (connUseEncryption)
1608 {
1609 request = newMessage(NXCPCodes.CMD_REQUEST_ENCRYPTION);
1610 request.setVariableInt16(NXCPCodes.VID_USE_X509_KEY_FORMAT, 1);
1611 sendMessage(request);
1612 waitForRCC(request.getMessageId());
1613 }
1614
1615 // Login to server
1616 Logger.debug("NXCSession.connect", "Connected to server version " + serverVersion + ", trying to login");
1617 request = newMessage(NXCPCodes.CMD_LOGIN);
1618 request.setVariableInt16(NXCPCodes.VID_AUTH_TYPE, authType);
1619 request.setVariable(NXCPCodes.VID_LOGIN_NAME, connLoginName);
1620
1621 if ((authType == AUTH_TYPE_PASSWORD) || (authType == AUTH_TYPE_SSO_TICKET))
1622 {
1623 request.setVariable(NXCPCodes.VID_PASSWORD, connPassword);
1624 }
1625 else if (authType == AUTH_TYPE_CERTIFICATE)
1626 {
1627 if ((serverChallenge == null) || (connSignature == null) || (connCertificate == null))
1628 {
1629 throw new NXCException(RCC.ENCRYPTION_ERROR);
1630 }
1631 byte[] signedChallenge = signChallenge(serverChallenge);
1632 request.setVariable(NXCPCodes.VID_SIGNATURE, signedChallenge);
1633 try
1634 {
1635 request.setVariable(NXCPCodes.VID_CERTIFICATE, connCertificate.getEncoded());
1636 }
1637 catch(CertificateEncodingException e)
1638 {
1639 throw new NXCException(RCC.ENCRYPTION_ERROR);
1640 }
1641 }
1642
1643 request.setVariable(NXCPCodes.VID_LIBNXCL_VERSION, NXCommon.VERSION);
1644 request.setVariable(NXCPCodes.VID_CLIENT_INFO, connClientInfo);
1645 request
1646 .setVariable(NXCPCodes.VID_OS_INFO, System.getProperty("os.name") + " " + System.getProperty("os.version"));
1647 request.setVariableInt16(NXCPCodes.VID_CLIENT_TYPE, clientType);
1648 if (clientAddress != null) request.setVariable(NXCPCodes.VID_CLIENT_ADDRESS, clientAddress);
1649 sendMessage(request);
1650 response = waitForMessage(NXCPCodes.CMD_LOGIN_RESP, request.getMessageId());
1651 int rcc = response.getVariableAsInteger(NXCPCodes.VID_RCC);
1652 Logger.debug("NXCSession.connect", "CMD_LOGIN_RESP received, RCC=" + rcc);
1653 if (rcc != RCC.SUCCESS)
1654 {
1655 Logger.warning("NXCSession.connect", "Login failed, RCC=" + rcc);
1656 throw new NXCException(rcc);
1657 }
1658 userId = response.getVariableAsInteger(NXCPCodes.VID_USER_ID);
1659 sessionId = response.getVariableAsInteger(NXCPCodes.VID_SESSION_ID);
1660 userSystemRights = response.getVariableAsInt64(NXCPCodes.VID_USER_SYS_RIGHTS);
1661 passwordExpired = response.getVariableAsBoolean(NXCPCodes.VID_CHANGE_PASSWD_FLAG);
1662 zoningEnabled = response.getVariableAsBoolean(NXCPCodes.VID_ZONING_ENABLED);
1663 helpdeskLinkActive = response.getVariableAsBoolean(NXCPCodes.VID_HELPDESK_LINK_ACTIVE);
1664
1665 defaultDciPollingInterval = response.getVariableAsInteger(NXCPCodes.VID_POLLING_INTERVAL);
1666 if (defaultDciPollingInterval == 0)
1667 defaultDciPollingInterval = 60;
1668
1669 defaultDciRetentionTime = response.getVariableAsInteger(NXCPCodes.VID_RETENTION_TIME);
1670 if (defaultDciRetentionTime == 0)
1671 defaultDciRetentionTime = 30;
1672
1673 minViewRefreshInterval = response.getVariableAsInteger(NXCPCodes.VID_VIEW_REFRESH_INTERVAL);
1674 if (minViewRefreshInterval <= 0)
1675 minViewRefreshInterval = 200;
1676
1677 strictAlarmStatusFlow = response.getVariableAsBoolean(NXCPCodes.VID_ALARM_STATUS_FLOW_STATE);
1678 timedAlarmAckEnabled = response.getVariableAsBoolean(NXCPCodes.VID_TIMED_ALARM_ACK_ENABLED);
1679
1680 Logger.info("NXCSession.connect", "succesfully connected and logged in, userId=" + userId);
1681 isConnected = true;
1682 }
1683 finally
1684 {
1685 if (!isConnected) disconnect();
1686 }
1687 }
1688
1689 /*
1690 * (non-Javadoc)
1691 *
1692 * @see org.netxms.client.Session#disconnect()
1693 */
1694 @Override
1695 public void disconnect()
1696 {
1697 if (connSocket != null)
1698 {
1699 try
1700 {
1701 connSocket.shutdownInput();
1702 connSocket.shutdownOutput();
1703 }
1704 catch(IOException e)
1705 {
1706 }
1707
1708 try
1709 {
1710 connSocket.close();
1711 }
1712 catch(IOException e)
1713 {
1714 }
1715 }
1716
1717 // cause notification processing thread to stop
1718 notificationQueue.clear();
1719 notificationQueue.offer(new NXCNotification(NXCNotification.STOP_PROCESSING_THREAD));
1720
1721 if (recvThread != null)
1722 {
1723 while(recvThread.isAlive())
1724 {
1725 try
1726 {
1727 recvThread.join();
1728 }
1729 catch(InterruptedException e)
1730 {
1731 }
1732 }
1733 recvThread = null;
1734 }
1735
1736 if (housekeeperThread != null)
1737 {
1738 housekeeperThread.setStopFlag(true);
1739 while(housekeeperThread.isAlive())
1740 {
1741 try
1742 {
1743 housekeeperThread.join();
1744 }
1745 catch(InterruptedException e)
1746 {
1747 }
1748 }
1749 housekeeperThread = null;
1750 }
1751
1752 connSocket = null;
1753
1754 if (msgWaitQueue != null)
1755 {
1756 msgWaitQueue.shutdown();
1757 msgWaitQueue = null;
1758 }
1759
1760 isConnected = false;
1761 }
1762
1763 /**
1764 * @return
1765 */
1766 public boolean isIgnoreProtocolVersion()
1767 {
1768 return ignoreProtocolVersion;
1769 }
1770
1771 /**
1772 * If set to true, protocol version is not checked at connect.
1773 *
1774 * @param ignoreProtocolVersion
1775 */
1776 public void setIgnoreProtocolVersion(boolean ignoreProtocolVersion)
1777 {
1778 this.ignoreProtocolVersion = ignoreProtocolVersion;
1779 }
1780
1781 /* (non-Javadoc)
1782 * @see org.netxms.api.client.Session#getDefaultRecvBufferSize()
1783 */
1784 @Override
1785 public int getDefaultRecvBufferSize()
1786 {
1787 return defaultRecvBufferSize;
1788 }
1789
1790 /* (non-Javadoc)
1791 * @see org.netxms.api.client.Session#getMaxRecvBufferSize()
1792 */
1793 @Override
1794 public int getMaxRecvBufferSize()
1795 {
1796 return maxRecvBufferSize;
1797 }
1798
1799 /* (non-Javadoc)
1800 * @see org.netxms.api.client.Session#setRecvBufferSize(int, int)
1801 */
1802 @Override
1803 public void setRecvBufferSize(int defaultBufferSize, int maxBufferSize)
1804 {
1805 this.defaultRecvBufferSize = defaultBufferSize;
1806 this.maxRecvBufferSize = maxBufferSize;
1807 }
1808
1809 /* (non-Javadoc)
1810 * @see org.netxms.api.client.Session#getServerAddress()
1811 */
1812 @Override
1813 public String getServerAddress()
1814 {
1815 return connAddress;
1816 }
1817
1818 /*
1819 * (non-Javadoc)
1820 *
1821 * @see org.netxms.api.client.Session#getUserName()
1822 */
1823 @Override
1824 public String getUserName()
1825 {
1826 return connLoginName;
1827 }
1828
1829 /*
1830 * (non-Javadoc)
1831 *
1832 * @see org.netxms.api.client.Session#getServerVersion()
1833 */
1834 @Override
1835 public String getServerVersion()
1836 {
1837 return serverVersion;
1838 }
1839
1840 /*
1841 * (non-Javadoc)
1842 *
1843 * @see org.netxms.api.client.Session#getServerId()
1844 */
1845 @Override
1846 public byte[] getServerId()
1847 {
1848 return serverId;
1849 }
1850
1851 /*
1852 * (non-Javadoc)
1853 *
1854 * @see org.netxms.api.client.Session#getServerTimeZone()
1855 */
1856 @Override
1857 public String getServerTimeZone()
1858 {
1859 return serverTimeZone;
1860 }
1861
1862 /**
1863 * @return the serverTime
1864 */
1865 public long getServerTime()
1866 {
1867 long offset = System.currentTimeMillis() - serverTimeRecvTime;
1868 return serverTime + offset;
1869 }
1870
1871 /**
1872 * @return the serverChallenge
1873 */
1874 public byte[] getServerChallenge()
1875 {
1876 return serverChallenge;
1877 }
1878
1879 /**
1880 * @return the tileServerURL
1881 */
1882 public String getTileServerURL()
1883 {
1884 return tileServerURL;
1885 }
1886
1887 /**
1888 * @return the zoningEnabled
1889 */
1890 public boolean isZoningEnabled()
1891 {
1892 return zoningEnabled;
1893 }
1894
1895 /**
1896 * Get status of helpdesk integration module on server.
1897 *
1898 * @return true if helpdesk integration module loaded on server
1899 */
1900 public boolean isHelpdeskLinkActive()
1901 {
1902 return helpdeskLinkActive;
1903 }
1904
1905 /*
1906 * (non-Javadoc)
1907 *
1908 * @see org.netxms.api.client.Session#getConnClientInfo()
1909 */
1910 @Override
1911 public String getConnClientInfo()
1912 {
1913 return connClientInfo;
1914 }
1915
1916 /*
1917 * (non-Javadoc)
1918 *
1919 * @see org.netxms.api.client.Session#setConnClientInfo(java.lang.String)
1920 */
1921 @Override
1922 public void setConnClientInfo(final String connClientInfo)
1923 {
1924 this.connClientInfo = connClientInfo;
1925 }
1926
1927 /*
1928 * (non-Javadoc)
1929 *
1930 * @see org.netxms.api.client.Session#setCommandTimeout(int)
1931 */
1932 @Override
1933 public void setCommandTimeout(final int commandTimeout)
1934 {
1935 this.commandTimeout = commandTimeout;
1936 }
1937
1938 /*
1939 * (non-Javadoc)
1940 *
1941 * @see org.netxms.api.client.Session#getUserId()
1942 */
1943 @Override
1944 public int getUserId()
1945 {
1946 return userId;
1947 }
1948
1949 /*
1950 * (non-Javadoc)
1951 *
1952 * @see org.netxms.api.client.Session#getUserSystemRights()
1953 */
1954 @Override
1955 public long getUserSystemRights()
1956 {
1957 return userSystemRights;
1958 }
1959
1960 /*
1961 * (non-Javadoc)
1962 *
1963 * @see org.netxms.api.client.Session#isPasswordExpired()
1964 */
1965 @Override
1966 public boolean isPasswordExpired()
1967 {
1968 return passwordExpired;
1969 }
1970
1971 /**
1972 * Synchronizes NetXMS objects between server and client. After successful
1973 * sync, subscribe client to object change notifications.
1974 *
1975 * @throws IOException if socket I/O error occurs
1976 * @throws NXCException if NetXMS server returns an error or operation was timed out
1977 */
1978 public synchronized void syncObjects() throws IOException, NXCException
1979 {
1980 syncObjects.acquireUninterruptibly();
1981 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_OBJECTS);
1982 msg.setVariableInt16(NXCPCodes.VID_SYNC_COMMENTS, 1);
1983 sendMessage(msg);
1984 waitForRCC(msg.getMessageId());
1985 waitForSync(syncObjects, commandTimeout * 10);
1986 objectsSynchronized = true;
1987 sendNotification(new NXCNotification(NXCNotification.OBJECT_SYNC_COMPLETED));
1988 subscribe(CHANNEL_OBJECTS);
1989 }
1990
1991 /**
1992 * Synchronizes selected object set with the server.
1993 *
1994 * @param objects identifiers of objects need to be synchronized
1995 * @param syncComments if true, comments for objects will be synchronized as well
1996 * @throws IOException if socket I/O error occurs
1997 * @throws NXCException if NetXMS server returns an error or operation was timed out
1998 */
1999 public void syncObjectSet(long[] objects, boolean syncComments) throws IOException, NXCException
2000 {
2001 syncObjectSet(objects, syncComments, 0);
2002 }
2003
2004 /**
2005 * Synchronizes selected object set with the server. The following options are accepted:
2006 * OBJECT_SYNC_NOTIFY - send object update notification for each received object
2007 * OBJECT_SYNC_WAIT - wait until all requested objects received
2008 *
2009 * @param objects identifiers of objects need to be synchronized
2010 * @param syncComments if true, comments for objects will be synchronized as well
2011 * @param options sync options (see above)
2012 * @throws IOException if socket I/O error occurs
2013 * @throws NXCException if NetXMS server returns an error or operation was timed out
2014 */
2015 public void syncObjectSet(long[] objects, boolean syncComments, int options) throws IOException, NXCException
2016 {
2017 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_SELECTED_OBJECTS);
2018 msg.setVariableInt16(NXCPCodes.VID_SYNC_COMMENTS, syncComments ? 1 : 0);
2019 msg.setVariableInt16(NXCPCodes.VID_FLAGS, options);
2020 msg.setVariableInt32(NXCPCodes.VID_NUM_OBJECTS, objects.length);
2021 msg.setVariable(NXCPCodes.VID_OBJECT_LIST, objects);
2022 sendMessage(msg);
2023 waitForRCC(msg.getMessageId());
2024
2025 if ((options & OBJECT_SYNC_WAIT) != 0) waitForRCC(msg.getMessageId());
2026 }
2027
2028 /**
2029 * Synchronize only those objects from given set which are not synchronized yet.
2030 *
2031 * @param objects identifiers of objects need to be synchronized
2032 * @param syncComments if true, comments for objects will be synchronized as well
2033 * @throws IOException if socket I/O error occurs
2034 * @throws NXCException if NetXMS server returns an error or operation was timed out
2035 */
2036 public void syncMissingObjects(long[] objects, boolean syncComments) throws IOException, NXCException
2037 {
2038 syncMissingObjects(objects, syncComments, 0);
2039 }
2040
2041 /**
2042 * Synchronize only those objects from given set which are not synchronized yet.
2043 * Accepts all options which are valid for syncObjectSet.
2044 *
2045 * @param objects identifiers of objects need to be synchronized
2046 * @param syncComments if true, comments for objects will be synchronized as well
2047 * @param options sync options (see comments for syncObjectSet)
2048 * @throws IOException if socket I/O error occurs
2049 * @throws NXCException if NetXMS server returns an error or operation was timed out
2050 */
2051 public void syncMissingObjects(long[] objects, boolean syncComments, int options) throws IOException, NXCException
2052 {
2053 final long[] syncList = CompatTools.arrayCopy(objects, objects.length);
2054 int count = syncList.length;
2055 synchronized(objectList)
2056 {
2057 for(int i = 0; i < syncList.length; i++)
2058 {
2059 if (objectList.containsKey(syncList[i]))
2060 {
2061 syncList[i] = 0;
2062 count--;
2063 }
2064 }
2065 }
2066
2067 if (count > 0) syncObjectSet(syncList, syncComments, options);
2068 }
2069
2070 /**
2071 * Find NetXMS object by it's identifier.
2072 *
2073 * @param id Object identifier
2074 * @return Object with given ID or null if object cannot be found
2075 */
2076 public AbstractObject findObjectById(final long id)
2077 {
2078 AbstractObject obj;
2079
2080 synchronized(objectList)
2081 {
2082 obj = objectList.get(id);
2083 }
2084 return obj;
2085 }
2086
2087 /**
2088 * Find NetXMS object by it's identifier with additional class checking.
2089 *
2090 * @param id object identifier
2091 * @param requiredClass required object class
2092 * @return Object with given ID or null if object cannot be found or is not an instance of required class
2093 */
2094 public AbstractObject findObjectById(final long id, final Class<? extends AbstractObject> requiredClass)
2095 {
2096 AbstractObject object = findObjectById(id);
2097 return requiredClass.isInstance(object) ? object : null;
2098 }
2099
2100 /**
2101 * Find multiple NetXMS objects by identifiers
2102 *
2103 * @param idList array of object identifiers
2104 * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers
2105 * @return list of found objects
2106 */
2107 public List<AbstractObject> findMultipleObjects(final long[] idList, boolean returnUnknown)
2108 {
2109 return findMultipleObjects(idList, null, returnUnknown);
2110 }
2111
2112 /**
2113 * Find multiple NetXMS objects by identifiers
2114 *
2115 * @param idList array of object identifiers
2116 * @param classFilter class filter for objects, or null to disable filtering
2117 * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers
2118 * @return list of found objects
2119 */
2120 public List<AbstractObject> findMultipleObjects(
2121 final long[] idList, Class<? extends AbstractObject> classFilter, boolean returnUnknown)
2122 {
2123 List<AbstractObject> result = new ArrayList<AbstractObject>(idList.length);
2124
2125 synchronized(objectList)
2126 {
2127 for(int i = 0; i < idList.length; i++)
2128 {
2129 final AbstractObject object = objectList.get(idList[i]);
2130 if ((object != null) && ((classFilter == null) || classFilter.isInstance(object)))
2131 {
2132 result.add(object);
2133 }
2134 else if (returnUnknown)
2135 {
2136 result.add(new UnknownObject(idList[i], this));
2137 }
2138 }
2139 }
2140
2141 return result;
2142 }
2143
2144 /**
2145 * Find multiple NetXMS objects by identifiers
2146 *
2147 * @param idList array of object identifiers
2148 * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers
2149 * @return array of found objects
2150 */
2151 public List<AbstractObject> findMultipleObjects(final Long[] idList, boolean returnUnknown)
2152 {
2153 return findMultipleObjects(idList, null, returnUnknown);
2154 }
2155
2156 /**
2157 * Find multiple NetXMS objects by identifiers
2158 *
2159 * @param idList array of object identifiers
2160 * @param classFilter class filter for objects, or null to disable filtering
2161 * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers
2162 * @return array of found objects
2163 */
2164 public List<AbstractObject> findMultipleObjects(
2165 final Long[] idList, Class<? extends AbstractObject> classFilter, boolean returnUnknown)
2166 {
2167 List<AbstractObject> result = new ArrayList<AbstractObject>(idList.length);
2168
2169 synchronized(objectList)
2170 {
2171 for(int i = 0; i < idList.length; i++)
2172 {
2173 final AbstractObject object = objectList.get(idList[i]);
2174 if ((object != null) && ((classFilter == null) || classFilter.isInstance(object)))
2175 {
2176 result.add(object);
2177 }
2178 else if (returnUnknown)
2179 {
2180 result.add(new UnknownObject(idList[i], this));
2181 }
2182 }
2183 }
2184
2185 return result;
2186 }
2187
2188 /**
2189 * Find object by name. If multiple objects with same name exist,
2190 * it is not determined what object will be returned. Name comparison
2191 * is case-insensitive.
2192 *
2193 * @param name object name to find
2194 * @return object with matching name or null
2195 */
2196 public AbstractObject findObjectByName(final String name)
2197 {
2198 AbstractObject result = null;
2199 synchronized(objectList)
2200 {
2201 for(AbstractObject object : objectList.values())
2202 {
2203 if (object.getObjectName().equalsIgnoreCase(name))
2204 {
2205 result = object;
2206 break;
2207 }
2208 }
2209 }
2210 return result;
2211 }
2212
2213 /**
2214 * Find object by name using regular expression. If multiple objects with same name exist,
2215 * it is not determined what object will be returned. Name comparison is case-insensitive.
2216 *
2217 * @param pattern regular expression for matching object name
2218 * @return object with matching name or null
2219 */
2220 public AbstractObject findObjectByNamePattern(final String pattern)
2221 {
2222 AbstractObject result = null;
2223 Matcher matcher = Pattern.compile(pattern).matcher("");
2224 synchronized(objectList)
2225 {
2226 for(AbstractObject object : objectList.values())
2227 {
2228 matcher.reset(object.getObjectName());
2229 if (matcher.matches())
2230 {
2231 result = object;
2232 break;
2233 }
2234 }
2235 }
2236 return result;
2237 }
2238
2239 /**
2240 * Get list of top-level objects matching given class filter. Class filter
2241 * may be null to ignore object class.
2242 *
2243 * @return List of all top matching level objects (either without parents or with
2244 * inaccessible parents)
2245 */
2246 public AbstractObject[] getTopLevelObjects(Set<Integer> classFilter)
2247 {
2248 HashSet<AbstractObject> list = new HashSet<AbstractObject>();
2249 synchronized(objectList)
2250 {
2251 for(AbstractObject object : objectList.values())
2252 {
2253 if ((classFilter != null) && !classFilter.contains(object.getObjectClass())) continue;
2254
2255 if (!object.hasParents())
2256 {
2257 list.add(object);
2258 }
2259 else
2260 {
2261 boolean hasParents = false;
2262 Iterator<Long> it = object.getParents();
2263 while(it.hasNext())
2264 {
2265 Long parent = it.next();
2266 if (classFilter != null)
2267 {
2268 AbstractObject p = objectList.get(parent);
2269 if ((p != null) && classFilter.contains(p.getObjectClass()))
2270 {
2271 hasParents = true;
2272 break;
2273 }
2274 }
2275 else
2276 {
2277 if (objectList.containsKey(parent))
2278 {
2279 hasParents = true;
2280 break;
2281 }
2282 }
2283 }
2284 if (!hasParents) list.add(object);
2285 }
2286 }
2287 }
2288 return list.toArray(new AbstractObject[list.size()]);
2289 }
2290
2291 /**
2292 * Get list of top-level objects.
2293 *
2294 * @return List of all top level objects (either without parents or with
2295 * inaccessible parents)
2296 */
2297 public AbstractObject[] getTopLevelObjects()
2298 {
2299 return getTopLevelObjects(null);
2300 }
2301
2302 /**
2303 * Get list of all objects
2304 *
2305 * @return List of all objects
2306 */
2307 public AbstractObject[] getAllObjects()
2308 {
2309 AbstractObject[] list;
2310
2311 synchronized(objectList)
2312 {
2313 list = objectList.values().toArray(new AbstractObject[objectList.size()]);
2314 }
2315 return list;
2316 }
2317
2318 /**
2319 * Get object name by ID.
2320 *
2321 * @param objectId object ID
2322 * @return object name if object is known, or string in form [<object_id>] for unknown objects
2323 */
2324 public String getObjectName(long objectId)
2325 {
2326 AbstractObject object = findObjectById(objectId);
2327 return (object != null) ? object.getObjectName() : ("[" + Long.toString(objectId) + "]");
2328 }
2329
2330 /**
2331 * Get list of active alarms. For accessing terminated alarms log view API should be used.
2332 *
2333 * @return Hash map containing alarms
2334 * @throws IOException if socket I/O error occurs
2335 * @throws NXCException if NetXMS server returns an error or operation was timed out
2336 */
2337 public HashMap<Long, Alarm> getAlarms() throws IOException, NXCException
2338 {
2339 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALL_ALARMS);
2340 final long rqId = msg.getMessageId();
2341 sendMessage(msg);
2342
2343 final HashMap<Long, Alarm> alarmList = new HashMap<Long, Alarm>(0);
2344 while(true)
2345 {
2346 msg = waitForMessage(NXCPCodes.CMD_ALARM_DATA, rqId);
2347 long alarmId = msg.getVariableAsInteger(NXCPCodes.VID_ALARM_ID);
2348 if (alarmId == 0)
2349 break; // ALARM_ID == 0 indicates end of list
2350 alarmList.put(alarmId, new Alarm(msg));
2351 }
2352
2353 return alarmList;
2354 }
2355
2356 /**
2357 * Get information about single active alarm. Terminated alarms cannot be accessed with this call.
2358 *
2359 * @param alarmId alarm ID
2360 * @return alarm object
2361 * @throws IOException if socket I/O error occurs
2362 * @throws NXCException if NetXMS server returns an error or operation was timed out
2363 */
2364 public Alarm getAlarm(long alarmId) throws IOException, NXCException
2365 {
2366 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM);
2367 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2368 sendMessage(msg);
2369 final NXCPMessage response = waitForRCC(msg.getMessageId());
2370 return new Alarm(response);
2371 }
2372
2373 /**
2374 * Get information about events related to single active alarm. Information for terminated alarms cannot be accessed with this call.
2375 * User must have "view alarms" permission on alarm's source node and "view event log" system-wide access.
2376 *
2377 * @param alarmId alarm ID
2378 * @return list of related events
2379 * @throws IOException if socket I/O error occurs
2380 * @throws NXCException if NetXMS server returns an error or operation was timed out
2381 */
2382 public List<EventInfo> getAlarmEvents(long alarmId) throws IOException, NXCException
2383 {
2384 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM_EVENTS);
2385 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2386 sendMessage(msg);
2387 final NXCPMessage response = waitForRCC(msg.getMessageId());
2388
2389 int count = response.getVariableAsInteger(NXCPCodes.VID_NUM_ELEMENTS);
2390 List<EventInfo> list = new ArrayList<EventInfo>(count);
2391 long varId = NXCPCodes.VID_ELEMENT_LIST_BASE;
2392 for(int i = 0; i < count; i++)
2393 {
2394 EventInfo parent = null;
2395 long rootId = response.getVariableAsInt64(varId + 1);
2396 if (rootId != 0)
2397 {
2398 for(EventInfo e : list)
2399 {
2400 if (e.getId() == rootId)
2401 {
2402 parent = e;
2403 break;
2404 }
2405 }
2406 }
2407 list.add(new EventInfo(response, varId, parent));
2408 varId += 10;
2409 }
2410 return list;
2411 }
2412
2413 /**
2414 * Acknowledge alarm.
2415 *
2416 * @param alarmId Identifier of alarm to be acknowledged.
2417 * @param sticky if set to true, acknowledged state will be made "sticky" (duplicate alarms with same key will not revert it back to outstanding)
2418 * @param time timeout for sticky acknowledge in seconds (0 for infinite)
2419 * @throws IOException if socket I/O error occurs
2420 * @throws NXCException if NetXMS server returns an error or operation was timed out
2421 */
2422 public void acknowledgeAlarm(final long alarmId, boolean sticky, int time) throws IOException, NXCException
2423 {
2424 NXCPMessage msg = newMessage(NXCPCodes.CMD_ACK_ALARM);
2425 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2426 msg.setVariableInt16(NXCPCodes.VID_STICKY_FLAG, sticky ? 1 : 0);
2427 msg.setVariableInt32(NXCPCodes.VID_TIMESTAMP, time);
2428 sendMessage(msg);
2429 waitForRCC(msg.getMessageId());
2430 }
2431
2432 /**
2433 * Acknowledge alarm.
2434 *
2435 * @param alarmId Identifier of alarm to be acknowledged.
2436 * @throws IOException if socket I/O error occurs
2437 * @throws NXCException if NetXMS server returns an error or operation was timed out
2438 */
2439 public void acknowledgeAlarm(final long alarmId) throws IOException, NXCException
2440 {
2441 acknowledgeAlarm(alarmId, false, 0);
2442 }
2443
2444 /**
2445 * Acknowledge alarm by helpdesk reference.
2446 *
2447 * @param helpdeskReference Helpdesk issue reference (e.g. JIRA issue key)
2448 * @throws IOException if socket I/O error occurs
2449 * @throws NXCException if NetXMS server returns an error or operation was timed out
2450 */
2451 public void acknowledgeAlarm(String helpdeskReference) throws IOException, NXCException
2452 {
2453 NXCPMessage msg = newMessage(NXCPCodes.CMD_ACK_ALARM);
2454 msg.setVariable(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2455 sendMessage(msg);
2456 waitForRCC(msg.getMessageId());
2457 }
2458
2459 /**
2460 * Resolve alarm.
2461 *
2462 * @param alarmId Identifier of alarm to be resolved.
2463 * @throws IOException if socket I/O error occurs
2464 * @throws NXCException if NetXMS server returns an error or operation was timed out
2465 */
2466 public void resolveAlarm(final long alarmId) throws IOException, NXCException
2467 {
2468 NXCPMessage msg = newMessage(NXCPCodes.CMD_RESOLVE_ALARM);
2469 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2470 sendMessage(msg);
2471 waitForRCC(msg.getMessageId());
2472 }
2473
2474 /**
2475 * Resolve alarm by helpdesk reference.
2476 *
2477 * @param helpdeskReference Identifier of alarm to be resolved.
2478 * @throws IOException if socket I/O error occurs
2479 * @throws NXCException if NetXMS server returns an error or operation was timed out
2480 */
2481 public void resolveAlarm(final String helpdeskReference) throws IOException, NXCException
2482 {
2483 NXCPMessage msg = newMessage(NXCPCodes.CMD_RESOLVE_ALARM);
2484 msg.setVariable(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2485 sendMessage(msg);
2486 waitForRCC(msg.getMessageId());
2487 }
2488
2489 /**
2490 * Terminate alarm.
2491 *
2492 * @param alarmId Identifier of alarm to be terminated.
2493 * @throws IOException if socket I/O error occurs
2494 * @throws NXCException if NetXMS server returns an error or operation was timed out
2495 */
2496 public void terminateAlarm(final long alarmId) throws IOException, NXCException
2497 {
2498 NXCPMessage msg = newMessage(NXCPCodes.CMD_TERMINATE_ALARM);
2499 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2500 sendMessage(msg);
2501 waitForRCC(msg.getMessageId());
2502 }
2503
2504 /**
2505 * Terminate alarm by helpdesk reference.
2506 *
2507 * @param helpdeskReference Identifier of alarm to be resolved.
2508 * @throws IOException if socket I/O error occurs
2509 * @throws NXCException if NetXMS server returns an error or operation was timed out
2510 */
2511 public void terminateAlarm(final String helpdeskReference) throws IOException, NXCException
2512 {
2513 NXCPMessage msg = newMessage(NXCPCodes.CMD_TERMINATE_ALARM);
2514 msg.setVariable(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2515 sendMessage(msg);
2516 waitForRCC(msg.getMessageId());
2517 }
2518
2519 /**
2520 * Delete alarm.
2521 *
2522 * @param alarmId Identifier of alarm to be deleted.
2523 * @throws IOException if socket I/O error occurs
2524 * @throws NXCException if NetXMS server returns an error or operation was timed out
2525 */
2526 public void deleteAlarm(final long alarmId) throws IOException, NXCException
2527 {
2528 NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_ALARM);
2529 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2530 sendMessage(msg);
2531 waitForRCC(msg.getMessageId());
2532 }
2533
2534 /**
2535 * Open issue in helpdesk system from given alarm
2536 *
2537 * @param alarmId alarm identifier
2538 * @return helpdesk issue identifier
2539 * @throws IOException if socket I/O error occurs
2540 * @throws NXCException if NetXMS server returns an error or operation was timed out
2541 */
2542 public String openHelpdeskIssue(long alarmId) throws IOException, NXCException
2543 {
2544 NXCPMessage msg = newMessage(NXCPCodes.CMD_OPEN_HELPDESK_ISSUE);
2545 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId);
2546 sendMessage(msg);
2547 return waitForRCC(msg.getMessageId()).getVariableAsString(NXCPCodes.VID_HELPDESK_REF);
2548 }
2549
2550 /**
2551 * Get URL for helpdesk issue associated with given alarm
2552 *
2553 * @param alarmId
2554 * @return
2555 * @throws IOException if socket I/O error occurs
2556 * @throws NXCException if NetXMS server returns an error or operation was timed out
2557 */
2558 public String getHelpdeskIssueUrl(long alarmId) throws IOException, NXCException
2559 {
2560 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_HELPDESK_URL);
2561 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId);
2562 sendMessage(msg);
2563 return waitForRCC(msg.getMessageId()).getVariableAsString(NXCPCodes.VID_URL);
2564 }
2565
2566 /**
2567 * Unlink helpdesk issue from alarm. User must have OBJECT_ACCESS_UPDATE_ALARMS access right
2568 * on alarm's source object and SYSTEM_ACCESS_UNLINK_ISSUES system wide access right.
2569 *
2570 * @param helpdeskReference
2571 * @throws IOException if socket I/O error occurs
2572 * @throws NXCException if NetXMS server returns an error or operation was timed out
2573 */
2574 public void unlinkHelpdeskIssue(String helpdeskReference) throws IOException, NXCException
2575 {
2576 NXCPMessage msg = newMessage(NXCPCodes.CMD_UNLINK_HELPDESK_ISSUE);
2577 msg.setVariable(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2578 sendMessage(msg);
2579 waitForRCC(msg.getMessageId());
2580 }
2581
2582 /**
2583 * Unlink helpdesk issue from alarm. User must have OBJECT_ACCESS_UPDATE_ALARMS access right
2584 * on alarm's source object and SYSTEM_ACCESS_UNLINK_ISSUES system wide access right.
2585 *
2586 * @param helpdeskReference
2587 * @throws IOException if socket I/O error occurs
2588 * @throws NXCException if NetXMS server returns an error or operation was timed out
2589 */
2590 public void unlinkHelpdeskIssue(long alarmId) throws IOException, NXCException
2591 {
2592 NXCPMessage msg = newMessage(NXCPCodes.CMD_UNLINK_HELPDESK_ISSUE);
2593 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId);
2594 sendMessage(msg);
2595 waitForRCC(msg.getMessageId());
2596 }
2597
2598 /**
2599 * Get list of comments for given alarm.
2600 *
2601 * @param alarmId alarm ID
2602 * @return list of alarm comments
2603 * @throws IOException if socket I/O error occurs
2604 * @throws NXCException if NetXMS server returns an error or operation was timed out
2605 */
2606 public List<AlarmComment> getAlarmComments(long alarmId) throws IOException, NXCException
2607 {
2608 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM_COMMENTS);
2609 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2610 sendMessage(msg);
2611
2612 final NXCPMessage response = waitForRCC(msg.getMessageId());
2613 int count = response.getVariableAsInteger(NXCPCodes.VID_NUM_ELEMENTS);
2614 final List<AlarmComment> comments = new ArrayList<AlarmComment>(count);
2615 long varId = NXCPCodes.VID_ELEMENT_LIST_BASE;
2616 for(int i = 0; i < count; i++)
2617 {
2618 comments.add(new AlarmComment(response, varId));
2619 varId += 10;
2620 }
2621 return comments;
2622 }
2623
2624 /**
2625 * Delete alarm comment.
2626 *
2627 * @param alarmId alarm ID
2628 * @param commentId comment ID
2629 * @throws IOException if socket I/O error occurs
2630 * @throws NXCException if NetXMS server returns an error or operation was timed out
2631 */
2632 public void deleteAlarmComment(long alarmId, long commentId) throws IOException, NXCException
2633 {
2634 NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_ALARM_COMMENT);
2635 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2636 msg.setVariableInt32(NXCPCodes.VID_COMMENT_ID, (int) commentId);
2637 sendMessage(msg);
2638 waitForRCC(msg.getMessageId());
2639 }
2640
2641 /**
2642 * Create alarm comment.
2643 *
2644 * @param alarmId
2645 * @param text
2646 * @throws IOException
2647 * @throws NXCException
2648 */
2649 public void createAlarmComment(long alarmId, String text) throws IOException, NXCException {
2650 updateAlarmComment(alarmId, 0, text);
2651 }
2652
2653 /**
2654 * Create alarm comment by helpdesk reference.
2655 *
2656 * @param helpdeskReference
2657 * @param text
2658 * @throws IOException
2659 * @throws NXCException
2660 */
2661 public void createAlarmComment(final String helpdeskReference, String text) throws IOException, NXCException {
2662 NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_ALARM_COMMENT);
2663 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, 0);
2664 msg.setVariable(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2665 msg.setVariable(NXCPCodes.VID_COMMENTS, text);
2666 sendMessage(msg);
2667 waitForRCC(msg.getMessageId());
2668 }
2669
2670 /**
2671 * Update alarm comment.
2672 * If alarmId == 0 — new comment will be created.
2673 *
2674 * @param alarmId alarm ID
2675 * @param commentId comment ID or 0 for creating new comment
2676 * @param text message text
2677 * @throws IOException if socket I/O error occurs
2678 * @throws NXCException if NetXMS server returns an error or operation was timed out
2679 */
2680 public void updateAlarmComment(long alarmId, long commentId, String text) throws IOException, NXCException
2681 {
2682 NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_ALARM_COMMENT);
2683 msg.setVariableInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2684 msg.setVariableInt32(NXCPCodes.VID_COMMENT_ID, (int) commentId);
2685 msg.setVariable(NXCPCodes.VID_COMMENTS, text);
2686 sendMessage(msg);
2687 waitForRCC(msg.getMessageId());
2688 }
2689
2690 /**
2691 * Changes state of alarm status flow. Strict or not - terminate state can be set only after
2692 * resolve state or after any state.
2693 *
2694 * @param state state of alarm status flow - strict or not (1 or 0)
2695 * @throws IOException if socket I/O error occurs
2696 * @throws NXCException if NetXMS server returns an error or operation was timed out
2697 */
2698 public void setAlarmFlowState(int state) throws IOException, NXCException
2699 {
2700 NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_ALARM_STATUS_FLOW);
2701 msg.setVariableInt32(NXCPCodes.VID_ALARM_STATUS_FLOW_STATE, state);
2702 sendMessage(msg);
2703 waitForRCC(msg.getMessageId());
2704 }
2705
2706 /*
2707 * (non-Javadoc)
2708 *
2709 * @see
2710 * org.netxms.api.client.servermanager.ServerManager#getServerVariables()
2711 */
2712 @Override
2713 public Map<String, ServerVariable> getServerVariables() throws IOException, NXCException
2714 {
2715 NXCPMessage request = newMessage(NXCPCodes.CMD_GET_CONFIG_VARLIST);
2716 sendMessage(request);
2717
2718 final NXCPMessage response = waitForRCC(request.getMessageId());
2719
2720 long id;
2721 int i, count = response.getVariableAsInteger(NXCPCodes.VID_NUM_VARIABLES);
2722 final HashMap<String, ServerVariable> varList = new HashMap<String, ServerVariable>(count);
2723 for(i = 0, id = NXCPCodes.VID_VARLIST_BASE; i < count; i++, id += 3)
2724 {
2725 String name = response.getVariableAsString(id);
2726 varList.put(name,
2727 new ServerVariable(name, response.getVariableAsString(id + 1), response.getVariableAsBoolean(id + 2)));
2728 }
2729
2730 return varList;
2731 }
2732
2733 /*
2734 * (non-Javadoc)
2735 *
2736 * @see
2737 * org.netxms.api.client.servermanager.ServerManager#setServerVariable(java
2738 * .lang.String, java.lang.String)
2739 */
2740 @Override
2741 public void setServerVariable(final String name, final String value) throws IOException, NXCException
2742 {
2743 NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_CONFIG_VARIABLE);
2744 msg.setVariable(NXCPCodes.VID_NAME, name);
2745 msg.setVariable(NXCPCodes.VID_VALUE, value);
2746 sendMessage(msg);
2747 waitForRCC(msg.getMessageId());
2748 }
2749
2750 /*
2751 * (non-Javadoc)
2752 *
2753 * @see
2754 * org.netxms.api.client.servermanager.ServerManager#deleteServerVariable
2755 * (java.lang.String)
2756 */
2757 @Override
2758 public void deleteServerVariable(final String name) throws IOException, NXCException
2759 {
2760 NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_CONFIG_VARIABLE);
2761 msg.setVariable(NXCPCodes.VID_NAME, name);
2762 sendMessage(msg);
2763 waitForRCC(msg.getMessageId());
2764 }
2765
2766 /**
2767 * Get server config CLOB
2768 *
2769 * @param name
2770 * @return
2771 * @throws IOException
2772 * @throws NXCException
2773 */
2774 public String getServerConfigClob(final String name) throws IOException, NXCException
2775 {
2776 final NXCPMessage msg = newMessage(NXCPCodes.CMD_CONFIG_GET_CLOB);
2777 msg.setVariable(NXCPCodes.VID_NAME, name);
2778 sendMessage(msg);
2779 final NXCPMessage response = waitForRCC(msg.getMessageId());
2780 return response.getVariableAsString(NXCPCodes.VID_VALUE);
2781 }
2782
2783 /**
2784 * Set server config CLOB
2785 *
2786 * @param name
2787 * @param value
2788 * @throws IOException
2789 * @throws NXCException
2790 */
2791 public void setServerConfigClob(final String name, final String value) throws IOException, NXCException
2792 {
2793 NXCPMessage msg = newMessage(NXCPCodes.CMD_CONFIG_SET_CLOB);
2794 msg.setVariable(NXCPCodes.VID_NAME, name);
2795 msg.setVariable(NXCPCodes.VID_VALUE, value);
2796 sendMessage(msg);
2797 waitForRCC(msg.getMessageId());
2798 }
2799
2800 /**
2801 * Subscribe to notification channel(s)
2802 *
2803 * @param channels Notification channels to subscribe to. Multiple channels can be
2804 * specified by combining them with OR operation.
2805 * @throws IOException if socket I/O error occurs
2806 * @throws NXCException if NetXMS server returns an error or operation was timed out
2807 */
2808 public void subscribe(int channels) throws IOException, NXCException
2809 {
2810 NXCPMessage msg = newMessage(NXCPCodes.CMD_CHANGE_SUBSCRIPTION);
2811 msg.setVariableInt32(NXCPCodes.VID_FLAGS, channels);
2812 msg.setVariableInt16(NXCPCodes.VID_OPERATION, 1);
2813 sendMessage(msg);
2814 waitForRCC(msg.getMessageId());
2815 }
2816
2817 /**
2818 * Unsubscribe from notification channel(s)
2819 *
2820 * @param channels Notification channels to unsubscribe from. Multiple channels can
2821 * be specified by combining them with OR operation.
2822 * @throws IOException if socket I/O error occurs
2823 * @throws NXCException if NetXMS server returns an error or operation was timed out
2824 */
2825 public void unsubscribe(int channels) throws IOException, NXCException
2826 {
2827 NXCPMessage msg = newMessage(NXCPCodes.CMD_CHANGE_SUBSCRIPTION);
2828 msg.setVariableInt32(NXCPCodes.VID_FLAGS, channels);
2829 msg.setVariableInt16(NXCPCodes.VID_OPERATION, 0);
2830 sendMessage(msg);
2831 waitForRCC(msg.getMessageId());
2832 }
2833
2834 /*
2835 * (non-Javadoc)
2836 *
2837 * @see org.netxms.api.client.users.UserManager#syncUserDatabase()
2838 */
2839 @Override
2840 public void syncUserDatabase() throws IOException, NXCException
2841 {
2842 syncUserDB.acquireUninterruptibly();
2843 NXCPMessage msg = newMessage(NXCPCodes.CMD_LOAD_USER_DB);
2844 sendMessage(msg);
2845 waitForRCC(msg.getMessageId());
2846 waitForSync(syncUserDB, commandTimeout * 10);
2847 }
2848
2849 /*
2850 * (non-Javadoc)
2851 *
2852 * @see org.netxms.api.client.users.UserManager#findUserDBObjectById(long)
2853 */
2854 @Override
2855 public AbstractUserObject findUserDBObjectById(final long id)
2856 {
2857 AbstractUserObject object;
2858
2859 synchronized(userDB)
2860 {
2861 object = userDB.get(id);
2862 }
2863 return object;
2864 }
2865
2866 /*
2867 * (non-Javadoc)
2868 *
2869 * @see org.netxms.api.client.users.UserManager#getUserDatabaseObjects()
2870 */
2871 @Override
2872 public AbstractUserObject[] getUserDatabaseObjects()
2873 {
2874 AbstractUserObject[] list;
2875
2876 synchronized(userDB)
2877 {
2878 Collection<AbstractUserObject> values = userDB.values();
2879 list = values.toArray(new AbstractUserObject[values.size()]);
2880 }
2881 return list;
2882 }
2883
2884 /**
2885 * Create user or group on server
2886 *
2887 * @param name Login name for new user
2888 * @return ID assigned to newly created user
2889 * @throws IOException if socket I/O error occurs
2890 * @throws NXCException if NetXMS server returns an error or operation was timed out
2891 */
2892 private long createUserDBObject(final String name, final boolean isGroup) throws IOException, NXCException
2893 {
2894 final NXCPMessage msg = newMessage(NXCPCodes.CMD_CREATE_USER);
2895 msg.setVariable(NXCPCodes.VID_USER_NAME, name);
2896 msg.setVariableInt16(NXCPCodes.VID_IS_GROUP, isGroup ? 1 : 0);
2897 sendMessage(msg);
2898
2899 final NXCPMessage response = waitForRCC(msg.getMessageId());
2900 return response.getVariableAsInt64(NXCPCodes.VID_USER_ID);
2901 }
2902
2903 /*
2904 * (non-Javadoc)
2905 *
2906 * @see org.netxms.api.client.users.UserManager#createUser(java.lang.String)
2907 */
2908 @Override
2909 public long createUser(final String name) throws IOException, NXCException
2910 {
2911 return createUserDBObject(name, false);
2912 }
2913
2914 /*
2915 * (non-Javadoc)
2916 *
2917 * @see
2918 * org.netxms.api.client.users.UserManager#createUserGroup(java.lang.String)
2919 */
2920 @Override
2921 public long createUserGroup(final String name) throws IOException, NXCException
2922 {
2923 return createUserDBObject(name, true);
2924 }
2925
2926 /*
2927 * (non-Javadoc)
2928 *
2929 * @see org.netxms.api.client.users.UserManager#deleteUserDBObject(long)
2930 */
2931 @Override
2932 public void deleteUserDBObject(final long id) throws IOException, NXCException
2933 {
2934 NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_USER);
2935 msg.setVariableInt32(NXCPCodes.VID_USER_ID, (int) id);
2936 sendMessage(msg);
2937 waitForRCC(msg.getMessageId());
2938 }
2939
2940 /*
2941 * (non-Javadoc)
2942 *
2943 * @see org.netxms.api.client.users.UserManager#setUserPassword(long,
2944 * java.lang.String, java.lang.String)
2945 */
2946 @Override
2947 public void setUserPassword(final long id, final String newPassword, final String oldPassword)
2948 throws IOException, NXCException
2949 {
2950 NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_PASSWORD);
2951 msg.setVariableInt32(NXCPCodes.VID_USER_ID, (int) id);
2952 msg.setVariable(NXCPCodes.VID_PASSWORD, newPassword);
2953 if (oldPassword != null) msg.setVariable(NXCPCodes.VID_OLD_PASSWORD, oldPassword);
2954 sendMessage(msg);
2955 waitForRCC(msg.getMessageId());
2956 }
2957
2958 /*
2959 * (non-Javadoc)
2960 *
2961 * @see
2962 * org.netxms.api.client.users.UserManager#modifyUserDBObject(org.netxms.
2963 * api.client.users.AbstractUserObject, int)
2964 */
2965 @Override
2966 public void modifyUserDBObject(final AbstractUserObject object, final int fields) throws IOException, NXCException
2967 {
2968 NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_USER);
2969 msg.setVariableInt32(NXCPCodes.VID_FIELDS, fields);
2970 object.fillMessage(msg);
2971 sendMessage(msg);
2972 waitForRCC(msg.getMessageId());
2973 }
2974
2975 /*
2976 * (non-Javadoc)
2977 *
2978 * @see
2979 * org.netxms.api.client.users.UserManager#modifyUserDBObject(org.netxms.
2980 * api.client.users.AbstractUserObject)
2981 */
2982 @Override
2983 public void modifyUserDBObject(final AbstractUserObject object) throws IOException, NXCException
2984 {
2985 modifyUserDBObject(object, 0x7FFFFFFF);
2986 }
2987
2988 /*
2989 * (non-Javadoc)
2990 *
2991 * @see org.netxms.api.client.users.UserManager#lockUserDatabase()
2992 */
2993 @Override
2994 public void lockUserDatabase() throws IOException, NXCException
2995 {
2996 NXCPMessage msg = newMessage(NXCPCodes.CMD_LOCK_USER_DB);
2997 sendMessage(msg);
2998 waitForRCC(msg.getMessageId());
2999 }
3000
3001 /*
3002 * (non-Javadoc)
3003 *
3004 * @see org.netxms.api.client.users.UserManager#unlockUserDatabase()
3005 */
3006 @Override
3007 public void unlockUserDatabase() throws IOException, NXCException
3008 {
3009 NXCPMessage msg = newMessage(NXCPCodes.CMD_UNLOCK_USER_DB);
3010 sendMessage(msg);
3011 waitForRCC(msg.getMessageId());
3012 }
3013
3014 /*
3015 * (non-Javadoc)
3016 *
3017 * @see
3018 * org.netxms.api.client.Session#setAttributeForCurrentUser(java.lang.String,
3019 * java.lang.String)
3020 */
3021 @Override
3022 public void setAttributeForCurrentUser(final String name, final String value) throws IOException, NXCException
3023 {
3024 NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_CURRENT_USER_ATTR);
3025 msg.setVariable(NXCPCodes.VID_NAME, name);
3026 msg.setVariable(NXCPCodes.VID_VALUE, value);
3027 sendMessage(msg);
3028 waitForRCC(msg.getMessageId());
3029 }
3030
3031 /*
3032 * (non-Javadoc)
3033 *
3034 * @see
3035 * org.netxms.api.client.Session#getAttributeForCurrentUser(java.lang.String)
3036 */
3037 @Override
3038 public String getAttributeForCurrentUser(final String name) throws IOException, NXCException
3039 {
3040 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_CURRENT_USER_ATTR);
3041 msg.setVariable(NXCPCodes.VID_NAME, name);
3042 sendMessage(msg);
3043 final NXCPMessage response = waitForRCC(msg.getMessageId());
3044 return response.getVariableAsString(NXCPCodes.VID_VALUE);
3045 }
3046
3047 /**
3048 * Get last DCI values for given node
3049 *
3050 * @param nodeId ID of the node to get DCI values for
3051 * @param objectTooltipOnly if set to true, only DCIs with DCF_SHOW_ON_OBJECT_TOOLTIP flag set are returned
3052 * @return List of DCI values
3053 * @throws IOException if socket I/O error occurs
3054 * @throws NXCException if NetXMS server returns an error or operation was timed out
3055 */
3056 public DciValue[] getLastValues(final long nodeId, boolean objectTooltipOnly) throws IOException, NXCException
3057 {
3058 final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_LAST_VALUES);
3059 msg.setVariableInt32(NXCPCodes.VID_OBJECT_ID, (int) nodeId);
3060 msg.setVariableInt16(NXCPCodes.VID_OBJECT_TOOLTIP_ONLY, objectTooltipOnly ? 1 : 0);
3061 sendMessage(msg);
3062
3063 final NXCPMessage response = waitForRCC(msg.getMessageId());
3064
3065 int count = response.getVariableAsInteger(NXCPCodes.VID_NUM_ITEMS);
3066 DciValue[] list = new DciValue[count];
3067 long base = NXCPCodes.VID_DCI_VALUES_BASE;
3068 for(int i = 0; i < count; i++, base += 50)
3069 {
3070 list[i] = DciValue.createFromMessage(nodeId, response, base);
3071 }
3072
3073 return list;
3074 }
3075
3076 /**
3077 * Get last DCI values for given node
3078 *
3079 * @param nodeId ID of the node to get DCI values for
3080 * @return List of DCI values
3081 * @throws IOException if socket I/O error occurs
3082 * @throws NXCException if NetXMS server returns an error or operation was timed out
3083 */
3084 public DciValue[] getLastValues(final long nodeId) throws IOException, NXCException
3085 {
3086 return getLastValues(nodeId, false);
3087 }
3088
3089 /**
3090 * Get last DCI values for given DCI id list(list can contain simple DCIss and table DCIs)
3091 *
3092 * @param dciIDList List with all required data to get last DCI id
3093 * @return List of DCI values
3094 * @throws IOException if socket I/O error occurs
3095 * @throws NXCException if NetXMS server returns an error or operation was timed out
3096 */
3097 public DciValue[] getLastValues(Set<MapDCIInstance> dciIDList) throws IOException, NXCException
3098 {
3099 final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_DCI_VALUES);
3100 msg.setVariableInt32(NXCPCodes.VID_NUM_ITEMS, dciIDList.size());
3101 long base = NXCPCodes.VID_DCI_ID_LIST_BASE;
3102 for(MapDCIInstance item : dciIDList)
3103 {
3104 item.fillMessage(msg, base);
3105 base +=10;
3106 }
3107
3108 sendMessage(msg);
3109
3110 final NXCPMessage response = waitForRCC(msg.getMessageId());
3111
3112 int count = response.getVariableAsInteger(NXCPCodes.VID_NUM_ITEMS);
3113 DciValue[] list = new DciValue[count];
3114 base = NXCPCodes.VID_DCI_ID_LIST_BASE;
3115 for(int i = 0; i < count; i++, base += 10)
3116 {
3117 list[i] = (DciValue)new SimpleDciValue(response.getVariableAsInt64(base), response.getVariableAsString(base+1), response.getVariableAsInteger(base+2), response.getVariableAsInteger(base+3));
3118 }
3119
3120 return list;
3121 }
3122
3123 /**
3124 * Get last values for given table DCI on given node
3125 *
3126 * @param nodeId ID of the node to get DCI values for
3127 * @param dciId DCI ID
3128 * @return Table object with last values for table DCI
3129 * @throws IOException if socket I/O error occurs
3130 * @throws NXCException if NetXMS server returns an error or operation was timed out
3131 */
3132 public Table getTableLastValues(final long nodeId, final long dciId) throws IOException, NXCException
3133 {
3134 final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_TABLE_LAST_VALUES);
3135 msg.setVariableInt32(NXCPCodes.VID_OBJECT_ID, (int) nodeId);
3136 msg.setVariableInt32(NXCPCodes.VID_DCI_ID, (int) dciId);
3137 sendMessage(msg);
3138
3139 final NXCPMessage response = waitForRCC(msg.getMessageId());
3140 return new Table(response);
3141 }
3142
3143 /**
3144 * Get list of DCIs configured to be shown on performance tab in console for
3145 * given node.
3146 *
3147 * @param nodeId Node object ID
3148 * @return List of performance tab DCIs
3149 * @throws IOException if socket I/O error occurs
3150 * @throws NXCException if NetXMS server returns an error or operation was timed out
3151 */
3152 public PerfTabDci[] getPerfTabItems(final long nodeId) throws IOException, NXCException
3153 {
3154 final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_PERFTAB_DCI_LIST);
3155 msg.setVariableInt32(NXCPCodes.VID_OBJECT_ID, (int) nodeId);
3156 sendMessage(msg);
3157
3158 final NXCPMessage response = waitForRCC(msg.getMessageId());
3159
3160 int count = response.getVariableAsInteger(NXCPCodes.VID_NUM_ITEMS);
3161 PerfTabDci[] list = new PerfTabDci[count];
3162 long base = NXCPCodes.VID_SYSDCI_LIST_BASE;
3163 for(int i = 0; i < count; i++, base += 10)
3164 {
3165 list[i] = new PerfTabDci(response, base);
3166 }
3167
3168 return list;
3169 }
3170
3171 /**
3172 * Get threshold violation summary for all nodes under given parent object. Parent object could
3173 * be container, subnet, zone, entire network, or infrastructure service root.
3174 *
3175 * @param objectId parent object ID
3176 * @return list of threshold violation summary objects for all nodes below given root
3177 * @throws IOException if socket I/O error occurs
3178 * @throws NXCException if NetXMS server returns an error or operation was timed out
3179 */
3180 public List<ThresholdViolationSummary> getThresholdSummary(final long objectId) throws IOException, NXCException
3181 {
3182 final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_THRESHOLD_SUMMARY);
3183 msg.setVariableInt32(NXCPCodes.VID_OBJECT_ID, (int) objectId);
3184 sendMessage(msg);
3185
3186 final NXCPMessage response = waitForRCC(msg.getMessageId());
3187
3188 List<ThresholdViolationSummary> list = new ArrayList<ThresholdViolationSummary>();
3189 long varId = NXCPCodes.VID_THRESHOLD_BASE;
3190 while(response.getVariableAsInt64(varId) != 0)
3191 {
3192 final ThresholdViolationSummary t = new ThresholdViolationSummary(response, varId);
3193 list.add(t);
3194 varId += 50 * t.getDciList().size() + 2;
3195 }
3196
3197 return list;
3198 }
3199
3200 /**
3201 * Parse data from raw message CMD_DCI_DATA
3202 *
3203 * @param input Raw data
3204 * @param data Data object to add rows to
3205 * @return number of received data rows
3206 */
3207 private int parseDataRows(final byte[] input, DciData data)
3208 {
3209 final NXCPDataInputStream inputStream = new NXCPDataInputStream(input);
3210 int rows = 0;
3211
3212 try
3213 {
3214 inputStream.skipBytes(4); // DCI ID
3215 rows = inputStream.readInt();
3216 final int dataType = inputStream.readInt();
3217 data.setDataType(dataType);
3218 inputStream.skipBytes(4); // padding
3219
3220 for(int i = 0; i < rows; i++)
3221 {
3222 long timestamp = inputStream.readUnsignedInt() * 1000; // convert to
3223 // milliseconds
3224
3225 switch(dataType)
3226 {
3227 case DataCollectionItem.DT_INT:
3228 data.addDataRow(new DciDataRow(new Date(timestamp), new Long(inputStream.readInt())));
3229 break;
3230 case DataCollectionItem.DT_UINT:
3231 data.addDataRow(new DciDataRow(new Date(timestamp), new Long(inputStream.readUnsignedInt())));
3232 break;
3233 case DataCollectionItem.DT_INT64:
3234 case DataCollectionItem.DT_UINT64:
3235 inputStream.skipBytes(4); // padding
3236 data.addDataRow(new DciDataRow(new Date(timestamp), new Long(inputStream.readLong())));
3237 break;
3238 case DataCollectionItem.DT_FLOAT:
3239