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