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