f93641210ddd486dffe6ef4195befbe7dca4e1cc
[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 listeners.clear();
1990 consoleListeners.clear();
1991 messageSubscriptions.clear();
1992 receivedFiles.clear();
1993 recievedUpdates.clear();
1994 }
1995
1996 /**
1997 * Get connection state
1998 * @return connection state
1999 */
2000 public boolean isConnected()
2001 {
2002 return isConnected;
2003 }
2004
2005 /**
2006 * Get encryption state for current session.
2007 *
2008 * @return true if session is encrypted
2009 */
2010 public boolean isEncrypted()
2011 {
2012 return connUseEncryption;
2013 }
2014
2015 /**
2016 * @return
2017 */
2018 public boolean isIgnoreProtocolVersion()
2019 {
2020 return ignoreProtocolVersion;
2021 }
2022
2023 /**
2024 * If set to true, protocol version is not checked at connect.
2025 *
2026 * @param ignoreProtocolVersion
2027 */
2028 public void setIgnoreProtocolVersion(boolean ignoreProtocolVersion)
2029 {
2030 this.ignoreProtocolVersion = ignoreProtocolVersion;
2031 }
2032
2033 /**
2034 * Validate protocol versions
2035 *
2036 * @param versions
2037 * @return
2038 */
2039 public boolean validateProtocolVersions(int[] versions)
2040 {
2041 if (protocolVersion == null)
2042 return false;
2043 for(int index : versions)
2044 if (!protocolVersion.isCorrectVersion(index))
2045 return false;
2046 return true;
2047 }
2048
2049 /**
2050 * Get default receiver buffer size.
2051 *
2052 * @return Default receiver buffer size in bytes.
2053 */
2054 public int getDefaultRecvBufferSize()
2055 {
2056 return defaultRecvBufferSize;
2057 }
2058
2059 /**
2060 * Get max receiver buffer size.
2061 *
2062 * @return Max receiver buffer size in bytes.
2063 */
2064 public int getMaxRecvBufferSize()
2065 {
2066 return maxRecvBufferSize;
2067 }
2068
2069 /**
2070 * Set receiver buffer size. This method should be called before connect(). It will not have any effect after
2071 * connect().
2072 *
2073 * @param defaultBufferSize default size of receiver buffer in bytes.
2074 * @param maxBufferSize max size of receiver buffer in bytes.
2075 */
2076 public void setRecvBufferSize(int defaultBufferSize, int maxBufferSize)
2077 {
2078 this.defaultRecvBufferSize = defaultBufferSize;
2079 this.maxRecvBufferSize = maxBufferSize;
2080 }
2081
2082 /**
2083 * Get server address
2084 *
2085 * @return Server address
2086 */
2087 public String getServerAddress()
2088 {
2089 return connAddress;
2090 }
2091
2092 /**
2093 * Get NetXMS server version.
2094 *
2095 * @return Server version
2096 */
2097 public String getServerVersion()
2098 {
2099 return serverVersion;
2100 }
2101
2102 /**
2103 * Get NetXMS server UID.
2104 *
2105 * @return Server UID
2106 */
2107 public long getServerId()
2108 {
2109 return serverId;
2110 }
2111
2112 /**
2113 * Get server time zone.
2114 *
2115 * @return server's time zone string
2116 */
2117 public String getServerTimeZone()
2118 {
2119 return serverTimeZone;
2120 }
2121
2122 /**
2123 * Get server time
2124 *
2125 * @return the serverTime
2126 */
2127 public long getServerTime()
2128 {
2129 long offset = System.currentTimeMillis() - serverTimeRecvTime;
2130 return serverTime + offset;
2131 }
2132
2133 /**
2134 * @return the serverChallenge
2135 */
2136 public byte[] getServerChallenge()
2137 {
2138 return serverChallenge;
2139 }
2140
2141 /**
2142 * @return the tileServerURL
2143 */
2144 public String getTileServerURL()
2145 {
2146 return tileServerURL;
2147 }
2148
2149 /**
2150 * @return the zoningEnabled
2151 */
2152 public boolean isZoningEnabled()
2153 {
2154 return zoningEnabled;
2155 }
2156
2157 /**
2158 * Get status of helpdesk integration module on server.
2159 *
2160 * @return true if helpdesk integration module loaded on server
2161 */
2162 public boolean isHelpdeskLinkActive()
2163 {
2164 return helpdeskLinkActive;
2165 }
2166
2167 /**
2168 * Get client information string
2169 *
2170 * @return
2171 */
2172 public String getClientInfo()
2173 {
2174 return connClientInfo;
2175 }
2176
2177 /**
2178 * Set client information string
2179 *
2180 * @param connClientInfo
2181 */
2182 public void setClientInfo(final String connClientInfo)
2183 {
2184 this.connClientInfo = connClientInfo;
2185 }
2186
2187 /**
2188 * Set command execution timeout.
2189 *
2190 * @param commandTimeout
2191 * New command timeout
2192 */
2193 public void setCommandTimeout(final int commandTimeout)
2194 {
2195 this.commandTimeout = commandTimeout;
2196 }
2197
2198 /**
2199 * Set connect call timeout (must be set before connect call)
2200 *
2201 * @param connectTimeout connect timeout in milliseconds
2202 */
2203 public void setConnectTimeout(int connectTimeout)
2204 {
2205 this.connectTimeout = connectTimeout;
2206 }
2207
2208 /**
2209 * Get identifier of logged in user.
2210 *
2211 * @return Identifier of logged in user
2212 */
2213 public int getUserId()
2214 {
2215 return userId;
2216 }
2217
2218 /**
2219 * @return the userName
2220 */
2221 public String getUserName()
2222 {
2223 return userName;
2224 }
2225
2226 /**
2227 * @return the authenticationMethod
2228 */
2229 public AuthenticationType getAuthenticationMethod()
2230 {
2231 return authenticationMethod;
2232 }
2233
2234 /**
2235 * Get system-wide rights of currently logged in user.
2236 *
2237 * @return System-wide rights of currently logged in user
2238 */
2239 public long getUserSystemRights()
2240 {
2241 return userSystemRights;
2242 }
2243
2244 /**
2245 * Check if password is expired for currently logged in user.
2246 *
2247 * @return true if password is expired
2248 */
2249 public boolean isPasswordExpired()
2250 {
2251 return passwordExpired;
2252 }
2253
2254 /**
2255 * Get maximum number of records allowed to be displayed in alarm list
2256 */
2257 public int getAlarmListDisplayLimit()
2258 {
2259 return alarmListDisplayLimit;
2260 }
2261
2262 /**
2263 * Synchronizes NetXMS objects between server and client. After successful
2264 * sync, subscribe client to object change notifications.
2265 *
2266 * @throws IOException if socket I/O error occurs
2267 * @throws NXCException if NetXMS server returns an error or operation was timed out
2268 */
2269 public synchronized void syncObjects() throws IOException, NXCException
2270 {
2271 syncObjects.acquireUninterruptibly();
2272 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_OBJECTS);
2273 msg.setFieldInt16(NXCPCodes.VID_SYNC_COMMENTS, 1);
2274 sendMessage(msg);
2275 waitForRCC(msg.getMessageId());
2276 waitForSync(syncObjects, commandTimeout * 10);
2277 objectsSynchronized = true;
2278 sendNotification(new SessionNotification(SessionNotification.OBJECT_SYNC_COMPLETED));
2279 subscribe(CHANNEL_OBJECTS);
2280 }
2281
2282 /**
2283 * Synchronizes selected object set with the server.
2284 *
2285 * @param objects identifiers of objects need to be synchronized
2286 * @param syncComments if true, comments for objects will be synchronized as well
2287 * @throws IOException if socket I/O error occurs
2288 * @throws NXCException if NetXMS server returns an error or operation was timed out
2289 */
2290 public void syncObjectSet(long[] objects, boolean syncComments) throws IOException, NXCException
2291 {
2292 syncObjectSet(objects, syncComments, 0);
2293 }
2294
2295 /**
2296 * Synchronizes selected object set with the server. The following options are accepted:
2297 * OBJECT_SYNC_NOTIFY - send object update notification for each received object
2298 * OBJECT_SYNC_WAIT - wait until all requested objects received
2299 *
2300 * @param objects identifiers of objects need to be synchronized
2301 * @param syncComments if true, comments for objects will be synchronized as well
2302 * @param options sync options (see above)
2303 * @throws IOException if socket I/O error occurs
2304 * @throws NXCException if NetXMS server returns an error or operation was timed out
2305 */
2306 public void syncObjectSet(long[] objects, boolean syncComments, int options) throws IOException, NXCException
2307 {
2308 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_SELECTED_OBJECTS);
2309 msg.setFieldInt16(NXCPCodes.VID_SYNC_COMMENTS, syncComments ? 1 : 0);
2310 msg.setFieldInt16(NXCPCodes.VID_FLAGS, options);
2311 msg.setFieldInt32(NXCPCodes.VID_NUM_OBJECTS, objects.length);
2312 msg.setField(NXCPCodes.VID_OBJECT_LIST, objects);
2313 sendMessage(msg);
2314 waitForRCC(msg.getMessageId());
2315
2316 if ((options & OBJECT_SYNC_WAIT) != 0) waitForRCC(msg.getMessageId());
2317 }
2318
2319 /**
2320 * Synchronize only those objects from given set which are not synchronized yet.
2321 *
2322 * @param objects identifiers of objects need to be synchronized
2323 * @param syncComments if true, comments for objects will be synchronized as well
2324 * @throws IOException if socket I/O error occurs
2325 * @throws NXCException if NetXMS server returns an error or operation was timed out
2326 */
2327 public void syncMissingObjects(long[] objects, boolean syncComments) throws IOException, NXCException
2328 {
2329 syncMissingObjects(objects, syncComments, 0);
2330 }
2331
2332 /**
2333 * Synchronize only those objects from given set which are not synchronized yet.
2334 * Accepts all options which are valid for syncObjectSet.
2335 *
2336 * @param objects identifiers of objects need to be synchronized
2337 * @param syncComments if true, comments for objects will be synchronized as well
2338 * @param options sync options (see comments for syncObjectSet)
2339 * @throws IOException if socket I/O error occurs
2340 * @throws NXCException if NetXMS server returns an error or operation was timed out
2341 */
2342 public void syncMissingObjects(long[] objects, boolean syncComments, int options) throws IOException, NXCException
2343 {
2344 final long[] syncList = Arrays.copyOf(objects, objects.length);
2345 int count = syncList.length;
2346 synchronized(objectList)
2347 {
2348 for(int i = 0; i < syncList.length; i++)
2349 {
2350 if (objectList.containsKey(syncList[i]))
2351 {
2352 syncList[i] = 0;
2353 count--;
2354 }
2355 }
2356 }
2357
2358 if (count > 0)
2359 {
2360 syncObjectSet(syncList, syncComments, options);
2361 }
2362 }
2363
2364 /**
2365 * Find NetXMS object by it's identifier.
2366 *
2367 * @param id Object identifier
2368 * @return Object with given ID or null if object cannot be found
2369 */
2370 public AbstractObject findObjectById(final long id)
2371 {
2372 AbstractObject obj;
2373
2374 synchronized(objectList)
2375 {
2376 obj = objectList.get(id);
2377 }
2378 return obj;
2379 }
2380
2381 /**
2382 * Find NetXMS object by it's identifier with additional class checking.
2383 *
2384 * @param id object identifier
2385 * @param requiredClass required object class
2386 * @return Object with given ID or null if object cannot be found or is not an instance of required class
2387 */
2388 @SuppressWarnings("unchecked")
2389 public <T extends AbstractObject> T findObjectById(final long id, final Class<T> requiredClass)
2390 {
2391 AbstractObject object = findObjectById(id);
2392 return requiredClass.isInstance(object) ? (T)object : null;
2393 }
2394
2395 /**
2396 * Find multiple NetXMS objects by identifiers
2397 *
2398 * @param idList array of object identifiers
2399 * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers
2400 * @return list of found objects
2401 */
2402 public List<AbstractObject> findMultipleObjects(final long[] idList, boolean returnUnknown)
2403 {
2404 return findMultipleObjects(idList, null, returnUnknown);
2405 }
2406
2407 /**
2408 * Find multiple NetXMS objects by identifiers
2409 *
2410 * @param idList array of object identifiers
2411 * @param classFilter class filter for objects, or null to disable filtering
2412 * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers
2413 * @return list of found objects
2414 */
2415 public List<AbstractObject> findMultipleObjects(final long[] idList, Class<? extends AbstractObject> classFilter, boolean returnUnknown)
2416 {
2417 List<AbstractObject> result = new ArrayList<AbstractObject>(idList.length);
2418
2419 synchronized(objectList)
2420 {
2421 for(int i = 0; i < idList.length; i++)
2422 {
2423 final AbstractObject object = objectList.get(idList[i]);
2424 if ((object != null) && ((classFilter == null) || classFilter.isInstance(object)))
2425 {
2426 result.add(object);
2427 }
2428 else if (returnUnknown)
2429 {
2430 result.add(new UnknownObject(idList[i], this));
2431 }
2432 }
2433 }
2434
2435 return result;
2436 }
2437
2438 /**
2439 * Find multiple NetXMS objects by identifiers
2440 *
2441 * @param idList array of object identifiers
2442 * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers
2443 * @return array of found objects
2444 */
2445 public List<AbstractObject> findMultipleObjects(final Long[] idList, boolean returnUnknown)
2446 {
2447 return findMultipleObjects(idList, null, returnUnknown);
2448 }
2449
2450 /**
2451 * Find multiple NetXMS objects by identifiers
2452 *
2453 * @param idList array of object identifiers
2454 * @param classFilter class filter for objects, or null to disable filtering
2455 * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers
2456 * @return array of found objects
2457 */
2458 public List<AbstractObject> findMultipleObjects(final Long[] idList, Class<? extends AbstractObject> classFilter, boolean returnUnknown)
2459 {
2460 List<AbstractObject> result = new ArrayList<AbstractObject>(idList.length);
2461
2462 synchronized(objectList)
2463 {
2464 for(int i = 0; i < idList.length; i++)
2465 {
2466 final AbstractObject object = objectList.get(idList[i]);
2467 if ((object != null) && ((classFilter == null) || classFilter.isInstance(object)))
2468 {
2469 result.add(object);
2470 }
2471 else if (returnUnknown)
2472 {
2473 result.add(new UnknownObject(idList[i], this));
2474 }
2475 }
2476 }
2477
2478 return result;
2479 }
2480
2481 /**
2482 * Find zone object by zone ID.
2483 *
2484 * @param zoneId zone ID to find
2485 * @return zone object or null
2486 */
2487 public Zone findZone(long zoneId)
2488 {
2489 Zone result = null;
2490 synchronized(objectList)
2491 {
2492 AbstractObject entireNetwork = objectList.get(1L);
2493 Collection<AbstractObject> objects = (entireNetwork != null) ?
2494 entireNetwork.getAllChilds(AbstractObject.OBJECT_ZONE) : objectList.values();
2495 for(AbstractObject object : objects)
2496 {
2497 if ((object instanceof Zone) && ((Zone)object).getZoneId() == zoneId)
2498 {
2499 result = (Zone)object;
2500 break;
2501 }
2502 }
2503 }
2504 return result;
2505 }
2506
2507
2508 /**
2509 * Find object by name. If multiple objects with same name exist,
2510 * it is not determined what object will be returned. Name comparison
2511 * is case-insensitive.
2512 *
2513 * @param name object name to find
2514 * @return object with matching name or null
2515 */
2516 public AbstractObject findObjectByName(final String name)
2517 {
2518 AbstractObject result = null;
2519 synchronized(objectList)
2520 {
2521 for(AbstractObject object : objectList.values())
2522 {
2523 if (object.getObjectName().equalsIgnoreCase(name))
2524 {
2525 result = object;
2526 break;
2527 }
2528 }
2529 }
2530 return result;
2531 }
2532
2533 /**
2534 * Find object by name using regular expression. If multiple objects with same name exist,
2535 * it is not determined what object will be returned. Name comparison is case-insensitive.
2536 *
2537 * @param pattern regular expression for matching object name
2538 * @return object with matching name or null
2539 */
2540 public AbstractObject findObjectByNamePattern(final String pattern)
2541 {
2542 AbstractObject result = null;
2543 Matcher matcher = Pattern.compile(pattern).matcher("");
2544 synchronized(objectList)
2545 {
2546 for(AbstractObject object : objectList.values())
2547 {
2548 matcher.reset(object.getObjectName());
2549 if (matcher.matches())
2550 {
2551 result = object;
2552 break;
2553 }
2554 }
2555 }
2556 return result;
2557 }
2558
2559 /**
2560 * Generic object find using filter. WIll return first object matching given filter.
2561 *
2562 * @param filter
2563 * @return first matching object or null
2564 */
2565 public AbstractObject findObject(ObjectFilter filter)
2566 {
2567 AbstractObject result = null;
2568 synchronized(objectList)
2569 {
2570 for(AbstractObject object : objectList.values())
2571 {
2572 if (filter.filter(object))
2573 {
2574 result = object;
2575 break;
2576 }
2577 }
2578 }
2579 return result;
2580 }
2581
2582 /**
2583 * Find all objects matching given filter.
2584 *
2585 * @param filter
2586 * @return list of matching objects (empty list if nothing found)
2587 */
2588 public List<AbstractObject> filterObjects(ObjectFilter filter)
2589 {
2590 List<AbstractObject> result = new ArrayList<AbstractObject>();
2591 synchronized(objectList)
2592 {
2593 for(AbstractObject object : objectList.values())
2594 {
2595 if (filter.filter(object))
2596 {
2597 result.add(object);
2598 }
2599 }
2600 }
2601 return result;
2602 }
2603
2604 /**
2605 * Get list of top-level objects matching given class filter. Class filter
2606 * may be null to ignore object class.
2607 *
2608 * @return List of all top matching level objects (either without parents or with
2609 * inaccessible parents)
2610 */
2611 public AbstractObject[] getTopLevelObjects(Set<Integer> classFilter)
2612 {
2613 HashSet<AbstractObject> list = new HashSet<AbstractObject>();
2614 synchronized(objectList)
2615 {
2616 for(AbstractObject object : objectList.values())
2617 {
2618 if ((classFilter != null) && !classFilter.contains(object.getObjectClass())) continue;
2619
2620 if (!object.hasParents())
2621 {
2622 list.add(object);
2623 }
2624 else
2625 {
2626 boolean hasParents = false;
2627 Iterator<Long> it = object.getParents();
2628 while(it.hasNext())
2629 {
2630 Long parent = it.next();
2631 if (classFilter != null)
2632 {
2633 AbstractObject p = objectList.get(parent);
2634 if ((p != null) && classFilter.contains(p.getObjectClass()))
2635 {
2636 hasParents = true;
2637 break;
2638 }
2639 }
2640 else
2641 {
2642 if (objectList.containsKey(parent))
2643 {
2644 hasParents = true;
2645 break;
2646 }
2647 }
2648 }
2649 if (!hasParents) list.add(object);
2650 }
2651 }
2652 }
2653 return list.toArray(new AbstractObject[list.size()]);
2654 }
2655
2656 /**
2657 * Get list of top-level objects.
2658 *
2659 * @return List of all top level objects (either without parents or with
2660 * inaccessible parents)
2661 */
2662 public AbstractObject[] getTopLevelObjects()
2663 {
2664 return getTopLevelObjects(null);
2665 }
2666
2667 /**
2668 * Get list of all objects
2669 *
2670 * @return List of all objects
2671 */
2672 public AbstractObject[] getAllObjects()
2673 {
2674 AbstractObject[] list;
2675
2676 synchronized(objectList)
2677 {
2678 list = objectList.values().toArray(new AbstractObject[objectList.size()]);
2679 }
2680 return list;
2681 }
2682
2683 /**
2684 * Get object name by ID.
2685 *
2686 * @param objectId object ID
2687 * @return object name if object is known, or string in form [<object_id>] for unknown objects
2688 */
2689 public String getObjectName(long objectId)
2690 {
2691 AbstractObject object = findObjectById(objectId);
2692 return (object != null) ? object.getObjectName() : ("[" + Long.toString(objectId) + "]");
2693 }
2694
2695 /**
2696 * Get list of active alarms. For accessing terminated alarms log view API should be used.
2697 *
2698 * @return Hash map containing alarms
2699 * @throws IOException if socket I/O error occurs
2700 * @throws NXCException if NetXMS server returns an error or operation was timed out
2701 */
2702 public HashMap<Long, Alarm> getAlarms() throws IOException, NXCException
2703 {
2704 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALL_ALARMS);
2705 final long rqId = msg.getMessageId();
2706 sendMessage(msg);
2707
2708 final HashMap<Long, Alarm> alarmList = new HashMap<Long, Alarm>(0);
2709 while(true)
2710 {
2711 msg = waitForMessage(NXCPCodes.CMD_ALARM_DATA, rqId);
2712 long alarmId = msg.getFieldAsInt32(NXCPCodes.VID_ALARM_ID);
2713 if (alarmId == 0)
2714 break; // ALARM_ID == 0 indicates end of list
2715 alarmList.put(alarmId, new Alarm(msg));
2716 }
2717
2718 return alarmList;
2719 }
2720
2721 /**
2722 * Get information about single active alarm. Terminated alarms cannot be accessed with this call.
2723 *
2724 * @param alarmId alarm ID
2725 * @return alarm object
2726 * @throws IOException if socket I/O error occurs
2727 * @throws NXCException if NetXMS server returns an error or operation was timed out
2728 */
2729 public Alarm getAlarm(long alarmId) throws IOException, NXCException
2730 {
2731 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM);
2732 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2733 sendMessage(msg);
2734 final NXCPMessage response = waitForRCC(msg.getMessageId());
2735 return new Alarm(response);
2736 }
2737
2738 /**
2739 * Get information about events related to single active alarm. Information for terminated alarms cannot be accessed with this call.
2740 * User must have "view alarms" permission on alarm's source node and "view event log" system-wide access.
2741 *
2742 * @param alarmId alarm ID
2743 * @return list of related events
2744 * @throws IOException if socket I/O error occurs
2745 * @throws NXCException if NetXMS server returns an error or operation was timed out
2746 */
2747 public List<EventInfo> getAlarmEvents(long alarmId) throws IOException, NXCException
2748 {
2749 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM_EVENTS);
2750 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2751 sendMessage(msg);
2752 final NXCPMessage response = waitForRCC(msg.getMessageId());
2753
2754 int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS);
2755 List<EventInfo> list = new ArrayList<EventInfo>(count);
2756 long varId = NXCPCodes.VID_ELEMENT_LIST_BASE;
2757 for(int i = 0; i < count; i++)
2758 {
2759 EventInfo parent = null;
2760 long rootId = response.getFieldAsInt64(varId + 1);
2761 if (rootId != 0)
2762 {
2763 for(EventInfo e : list)
2764 {
2765 if (e.getId() == rootId)
2766 {
2767 parent = e;
2768 break;
2769 }
2770 }
2771 }
2772 list.add(new EventInfo(response, varId, parent));
2773 varId += 10;
2774 }
2775 return list;
2776 }
2777
2778 /**
2779 * Acknowledge alarm.
2780 *
2781 * @param alarmId Identifier of alarm to be acknowledged.
2782 * @param sticky if set to true, acknowledged state will be made "sticky" (duplicate alarms with same key will not revert it back to outstanding)
2783 * @param time timeout for sticky acknowledge in seconds (0 for infinite)
2784 * @throws IOException if socket I/O error occurs
2785 * @throws NXCException if NetXMS server returns an error or operation was timed out
2786 */
2787 public void acknowledgeAlarm(final long alarmId, boolean sticky, int time) throws IOException, NXCException
2788 {
2789 NXCPMessage msg = newMessage(NXCPCodes.CMD_ACK_ALARM);
2790 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2791 msg.setFieldInt16(NXCPCodes.VID_STICKY_FLAG, sticky ? 1 : 0);
2792 msg.setFieldInt32(NXCPCodes.VID_TIMESTAMP, time);
2793 sendMessage(msg);
2794 waitForRCC(msg.getMessageId());
2795 }
2796
2797 /**
2798 * Acknowledge alarm.
2799 *
2800 * @param alarmId Identifier of alarm to be acknowledged.
2801 * @throws IOException if socket I/O error occurs
2802 * @throws NXCException if NetXMS server returns an error or operation was timed out
2803 */
2804 public void acknowledgeAlarm(final long alarmId) throws IOException, NXCException
2805 {
2806 acknowledgeAlarm(alarmId, false, 0);
2807 }
2808
2809 /**
2810 * Acknowledge alarm by helpdesk reference.
2811 *
2812 * @param helpdeskReference Helpdesk issue reference (e.g. JIRA issue key)
2813 * @throws IOException if socket I/O error occurs
2814 * @throws NXCException if NetXMS server returns an error or operation was timed out
2815 */
2816 public void acknowledgeAlarm(String helpdeskReference) throws IOException, NXCException
2817 {
2818 NXCPMessage msg = newMessage(NXCPCodes.CMD_ACK_ALARM);
2819 msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2820 sendMessage(msg);
2821 waitForRCC(msg.getMessageId());
2822 }
2823
2824 /**
2825 * Resolve alarm.
2826 *
2827 * @param alarmId Identifier of alarm to be resolved.
2828 * @throws IOException if socket I/O error occurs
2829 * @throws NXCException if NetXMS server returns an error or operation was timed out
2830 */
2831 public void resolveAlarm(final long alarmId) throws IOException, NXCException
2832 {
2833 NXCPMessage msg = newMessage(NXCPCodes.CMD_RESOLVE_ALARM);
2834 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2835 sendMessage(msg);
2836 waitForRCC(msg.getMessageId());
2837 }
2838
2839 /**
2840 * Resolve alarm by helpdesk reference.
2841 *
2842 * @param helpdeskReference Identifier of alarm to be resolved.
2843 * @throws IOException if socket I/O error occurs
2844 * @throws NXCException if NetXMS server returns an error or operation was timed out
2845 */
2846 public void resolveAlarm(final String helpdeskReference) throws IOException, NXCException
2847 {
2848 NXCPMessage msg = newMessage(NXCPCodes.CMD_RESOLVE_ALARM);
2849 msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2850 sendMessage(msg);
2851 waitForRCC(msg.getMessageId());
2852 }
2853
2854 /**
2855 * Terminate alarm.
2856 *
2857 * @param alarmId Identifier of alarm to be terminated.
2858 * @throws IOException if socket I/O error occurs
2859 * @throws NXCException if NetXMS server returns an error or operation was timed out
2860 */
2861 public void terminateAlarm(final long alarmId) throws IOException, NXCException
2862 {
2863 NXCPMessage msg = newMessage(NXCPCodes.CMD_TERMINATE_ALARM);
2864 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2865 sendMessage(msg);
2866 waitForRCC(msg.getMessageId());
2867 }
2868
2869 /**
2870 * Terminate alarm by helpdesk reference.
2871 *
2872 * @param helpdeskReference Identifier of alarm to be resolved.
2873 * @throws IOException if socket I/O error occurs
2874 * @throws NXCException if NetXMS server returns an error or operation was timed out
2875 */
2876 public void terminateAlarm(final String helpdeskReference) throws IOException, NXCException
2877 {
2878 NXCPMessage msg = newMessage(NXCPCodes.CMD_TERMINATE_ALARM);
2879 msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2880 sendMessage(msg);
2881 waitForRCC(msg.getMessageId());
2882 }
2883
2884 /**
2885 * Delete alarm.
2886 *
2887 * @param alarmId Identifier of alarm to be deleted.
2888 * @throws IOException if socket I/O error occurs
2889 * @throws NXCException if NetXMS server returns an error or operation was timed out
2890 */
2891 public void deleteAlarm(final long alarmId) throws IOException, NXCException
2892 {
2893 NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_ALARM);
2894 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2895 sendMessage(msg);
2896 waitForRCC(msg.getMessageId());
2897 }
2898
2899 /**
2900 * Open issue in helpdesk system from given alarm
2901 *
2902 * @param alarmId alarm identifier
2903 * @return helpdesk issue identifier
2904 * @throws IOException if socket I/O error occurs
2905 * @throws NXCException if NetXMS server returns an error or operation was timed out
2906 */
2907 public String openHelpdeskIssue(long alarmId) throws IOException, NXCException
2908 {
2909 NXCPMessage msg = newMessage(NXCPCodes.CMD_OPEN_HELPDESK_ISSUE);
2910 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId);
2911 sendMessage(msg);
2912 return waitForRCC(msg.getMessageId()).getFieldAsString(NXCPCodes.VID_HELPDESK_REF);
2913 }
2914
2915 /**
2916 * Get URL for helpdesk issue associated with given alarm
2917 *
2918 * @param alarmId
2919 * @return
2920 * @throws IOException if socket I/O error occurs
2921 * @throws NXCException if NetXMS server returns an error or operation was timed out
2922 */
2923 public String getHelpdeskIssueUrl(long alarmId) throws IOException, NXCException
2924 {
2925 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_HELPDESK_URL);
2926 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId);
2927 sendMessage(msg);
2928 return waitForRCC(msg.getMessageId()).getFieldAsString(NXCPCodes.VID_URL);
2929 }
2930
2931 /**
2932 * Unlink helpdesk issue from alarm. User must have OBJECT_ACCESS_UPDATE_ALARMS access right
2933 * on alarm's source object and SYSTEM_ACCESS_UNLINK_ISSUES system wide access right.
2934 *
2935 * @param helpdeskReference
2936 * @throws IOException if socket I/O error occurs
2937 * @throws NXCException if NetXMS server returns an error or operation was timed out
2938 */
2939 public void unlinkHelpdeskIssue(String helpdeskReference) throws IOException, NXCException
2940 {
2941 NXCPMessage msg = newMessage(NXCPCodes.CMD_UNLINK_HELPDESK_ISSUE);
2942 msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
2943 sendMessage(msg);
2944 waitForRCC(msg.getMessageId());
2945 }
2946
2947 /**
2948 * Unlink helpdesk issue from alarm. User must have OBJECT_ACCESS_UPDATE_ALARMS access right
2949 * on alarm's source object and SYSTEM_ACCESS_UNLINK_ISSUES system wide access right.
2950 *
2951 * @param helpdeskReference
2952 * @throws IOException if socket I/O error occurs
2953 * @throws NXCException if NetXMS server returns an error or operation was timed out
2954 */
2955 public void unlinkHelpdeskIssue(long alarmId) throws IOException, NXCException
2956 {
2957 NXCPMessage msg = newMessage(NXCPCodes.CMD_UNLINK_HELPDESK_ISSUE);
2958 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId);
2959 sendMessage(msg);
2960 waitForRCC(msg.getMessageId());
2961 }
2962
2963 /**
2964 * Get list of comments for given alarm.
2965 *
2966 * @param alarmId alarm ID
2967 * @return list of alarm comments
2968 * @throws IOException if socket I/O error occurs
2969 * @throws NXCException if NetXMS server returns an error or operation was timed out
2970 */
2971 public List<AlarmComment> getAlarmComments(long alarmId) throws IOException, NXCException
2972 {
2973 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM_COMMENTS);
2974 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
2975 sendMessage(msg);
2976
2977 final NXCPMessage response = waitForRCC(msg.getMessageId());
2978 int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS);
2979 final List<AlarmComment> comments = new ArrayList<AlarmComment>(count);
2980 long varId = NXCPCodes.VID_ELEMENT_LIST_BASE;
2981 for(int i = 0; i < count; i++)
2982 {
2983 comments.add(new AlarmComment(response, varId));
2984 varId += 10;
2985 }
2986 return comments;
2987 }
2988
2989 /**
2990 * Delete alarm comment.
2991 *
2992 * @param alarmId alarm ID
2993 * @param commentId comment ID
2994 * @throws IOException if socket I/O error occurs
2995 * @throws NXCException if NetXMS server returns an error or operation was timed out
2996 */
2997 public void deleteAlarmComment(long alarmId, long commentId) throws IOException, NXCException
2998 {
2999 NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_ALARM_COMMENT);
3000 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
3001 msg.setFieldInt32(NXCPCodes.VID_COMMENT_ID, (int) commentId);
3002 sendMessage(msg);
3003 waitForRCC(msg.getMessageId());
3004 }
3005
3006 /**
3007 * Create alarm comment.
3008 *
3009 * @param alarmId
3010 * @param text
3011 * @throws IOException
3012 * @throws NXCException
3013 */
3014 public void createAlarmComment(long alarmId, String text) throws IOException, NXCException
3015 {
3016 updateAlarmComment(alarmId, 0, text);
3017 }
3018
3019 /**
3020 * Create alarm comment by helpdesk reference.
3021 *
3022 * @param helpdeskReference
3023 * @param text
3024 * @throws IOException
3025 * @throws NXCException
3026 */
3027 public void createAlarmComment(final String helpdeskReference, String text) throws IOException, NXCException
3028 {
3029 NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_ALARM_COMMENT);
3030 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, 0);
3031 msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference);
3032 msg.setField(NXCPCodes.VID_COMMENTS, text);
3033 sendMessage(msg);
3034 waitForRCC(msg.getMessageId());
3035 }
3036
3037 /**
3038 * Update alarm comment.
3039 * If alarmId == 0 — new comment will be created.
3040 *
3041 * @param alarmId alarm ID
3042 * @param commentId comment ID or 0 for creating new comment
3043 * @param text message text
3044 * @throws IOException if socket I/O error occurs
3045 * @throws NXCException if NetXMS server returns an error or operation was timed out
3046 */
3047 public void updateAlarmComment(long alarmId, long commentId, String text) throws IOException, NXCException
3048 {
3049 NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_ALARM_COMMENT);
3050 msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int) alarmId);
3051 msg.setFieldInt32(NXCPCodes.VID_COMMENT_ID, (int) commentId);
3052 msg.setField(NXCPCodes.VID_COMMENTS, text);
3053 sendMessage(msg);
3054 waitForRCC(msg.getMessageId());
3055 }
3056
3057 /**
3058 * Changes state of alarm status flow. Strict or not - terminate state can be set only after
3059 * resolve state or after any state.
3060 *
3061 * @param state state of alarm status flow - strict or not (1 or 0)
3062 * @throws IOException if socket I/O error occurs
3063 * @throws NXCException if NetXMS server returns an error or operation was timed out
3064 */
3065 public void setAlarmFlowState(int state) throws IOException, NXCException
3066 {
3067 NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_ALARM_STATUS_FLOW);
3068 msg.setFieldInt32(NXCPCodes.VID_ALARM_STATUS_FLOW_STATE, state);
3069 sendMessage(msg);
3070 waitForRCC(msg.getMessageId());
3071 }
3072
3073 /**
3074 * Get server configuration variables
3075 *
3076 * @return
3077 * @throws IOException if socket I/O error occurs
3078 * @throws NXCException if NetXMS server returns an error or operation was timed out
3079 */
3080 public Map<String, ServerVariable> getServerVariables() throws IOException, NXCException
3081 {
3082 NXCPMessage request = newMessage(NXCPCodes.CMD_GET_CONFIG_VARLIST);
3083 sendMessage(request);
3084
3085 final NXCPMessage response = waitForRCC(request.getMessageId());
3086
3087 long id;
3088 int i, count = response.getFieldAsInt32(NXCPCodes.VID_NUM_VARIABLES);
3089 final HashMap<String, ServerVariable> varList = new HashMap<String, ServerVariable>(count);
3090 for(i = 0, id = NXCPCodes.VID_VARLIST_BASE; i < count; i++, id += 3)
3091 {
3092 String name = response.getFieldAsString(id);
3093 varList.put(name,
3094 new ServerVariable(name, response.getFieldAsString(id + 1), response.getFieldAsBoolean(id + 2)));
3095 }
3096
3097 return varList;
3098 }
3099
3100 /**
3101 * Get server public configuration variable
3102 *
3103 * @param name configuration variable name
3104 * @return value of requested configuration variable
3105 * @throws IOException if socket I/O error occurs
3106 * @throws NXCException if NetXMS server returns an error or operation was timed out
3107 */
3108 public String getPublicServerVariable(String name) throws IOException, NXCException
3109 {
3110 NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_PUBLIC_CONFIG_VAR);
3111 msg.setField(NXCPCodes.VID_NAME, name);
3112 sendMessage(msg);
3113 NXCPMessage response = waitForRCC(msg.getMessageId());
3114 return response.getFieldAsString(NXCPCodes.VID_VALUE);
3115 }
3116
3117 /**
3118 * Get server public configuration variable as boolen value
3119 *
3120 * @param name configuration variable name
3121 * @return value of requested configuration variable
3122 * @throws IOException if socket I/O error occurs
3123 * @throws NXCException if NetXMS server returns an error or operation was timed out
3124 */
3125 public boolean getPublicServerVariableAsBoolean(String name) throws IOException, NXCException
3126 {
3127 String value = getPublicServerVariable(name);
3128 if ((value.equalsIgnoreCase("true")) || (value.equalsIgnoreCase("yes")))
3129 return true;
3130 if ((value.equalsIgnoreCase("false")) || (value.equalsIgnoreCase("no")))
3131 return false;
3132 try
3133 {
3134 int n = Integer.parseInt(value);
3135 return n != 0;
3136 }
3137 catch(NumberFormatException e)
3138 {
3139 return false;
3140 }
3141 }
3142
3143 /**
3144 * Set server configuration variable
3145 *
3146 * @param name
3147 * @param value
3148 * @throws IOException if socket I/O error occurs
3149 * @throws NXCException if NetXMS server returns an error or operation was timed out
3150 */
3151 public void setServerVariable(final String name, final String value) throws IOException, NXCException
3152 {
3153 NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_CONFIG_VARIABLE);
3154 msg.setField(NXCPCodes.VID_NAME, name);
3155 msg.setField(NXCPCodes.VID_VALUE, value);
3156 sendMessage(msg);
3157 waitForRCC(msg.getMessageId());
3158 }
3159
3160 /**
3161 * Delete server configuration variable
3162 *
3163 * @param name
3164 * @throws IOException if socket I/O error occurs
3165 * @throws NXCException if NetXMS server returns an error or operation was timed out
3166 */
3167 public void deleteServerVariable(final String name) throws IOException, NXCException
3168 {
3169 NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_CONFIG_VARIABLE);
3170 msg.setField(NXCPCodes.VID_NAME, name);
3171 sendMessage(msg);
3172 waitForRCC(msg.getMessageId());
3173 }
3174
3175 /**
3176 * Get server config CLOB
3177 *
3178 * @param name
3179 * @return
3180 * @throws IOException if socket I/O error occurs
3181 * @throws NXCException if NetXMS server returns an error or operation was timed out
3182 */
3183 public String getServerConfigClob(final String name) throws IOException, NXCException
3184 {
3185 final NXCPMessage msg = newMessage(NXCPCodes.CMD_CONFIG_GET_CLOB);
3186 msg.setField(NXCPCodes.VID_NAME, name);
3187 sendMessage(msg);
3188 final NXCPMessage response = waitForRCC(msg.getMessageId());
3189 return response.getFieldAsString(NXCPCodes.VID_VALUE);
3190 }
3191
3192 /**
3193 * Set server config CLOB
3194 *
3195 * @param name
3196 * @param value
3197 * @throws IOException if socket I/O error occurs