All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netxms.client.NXCSession Maven / Gradle / Ivy

There is a newer version: 5.0.6
Show newest version
/**
 * NetXMS - open source network management system
 * Copyright (C) 2003-2024 Victor Kirhenshtein
 * 

* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *

* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. *

* You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.netxms.client; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.SignatureException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.netxms.base.EncryptionContext; import org.netxms.base.GeoLocation; import org.netxms.base.InetAddressEx; import org.netxms.base.MacAddress; import org.netxms.base.NXCPCodes; import org.netxms.base.NXCPDataInputStream; import org.netxms.base.NXCPException; import org.netxms.base.NXCPMessage; import org.netxms.base.NXCPMessageReceiver; import org.netxms.base.NXCPMsgWaitQueue; import org.netxms.base.VersionInfo; import org.netxms.client.agent.config.AgentConfiguration; import org.netxms.client.agent.config.AgentConfigurationHandle; import org.netxms.client.asset.AssetAttribute; import org.netxms.client.businessservices.BusinessServiceCheck; import org.netxms.client.businessservices.BusinessServiceTicket; import org.netxms.client.constants.AggregationFunction; import org.netxms.client.constants.AuthenticationType; import org.netxms.client.constants.BackgroundTaskState; import org.netxms.client.constants.DataOrigin; import org.netxms.client.constants.DataType; import org.netxms.client.constants.HistoricalDataType; import org.netxms.client.constants.ObjectPollType; import org.netxms.client.constants.ObjectStatus; import org.netxms.client.constants.RCC; import org.netxms.client.dashboards.DashboardElement; import org.netxms.client.datacollection.ChartDciConfig; import org.netxms.client.datacollection.ConditionDciInfo; import org.netxms.client.datacollection.DCOStatusHolder; import org.netxms.client.datacollection.DataCollectionConfiguration; import org.netxms.client.datacollection.DataCollectionItem; import org.netxms.client.datacollection.DataCollectionObject; import org.netxms.client.datacollection.DataCollectionTable; import org.netxms.client.datacollection.DciData; import org.netxms.client.datacollection.DciDataRow; import org.netxms.client.datacollection.DciInfo; import org.netxms.client.datacollection.DciLastValue; import org.netxms.client.datacollection.DciPushData; import org.netxms.client.datacollection.DciSummaryTable; import org.netxms.client.datacollection.DciSummaryTableColumn; import org.netxms.client.datacollection.DciSummaryTableDescriptor; import org.netxms.client.datacollection.DciValue; import org.netxms.client.datacollection.GraphDefinition; import org.netxms.client.datacollection.GraphFolder; import org.netxms.client.datacollection.MeasurementUnit; import org.netxms.client.datacollection.PerfTabDci; import org.netxms.client.datacollection.PredictionEngine; import org.netxms.client.datacollection.RemoteChangeListener; import org.netxms.client.datacollection.SimpleDciValue; import org.netxms.client.datacollection.Threshold; import org.netxms.client.datacollection.ThresholdStateChange; import org.netxms.client.datacollection.ThresholdViolationSummary; import org.netxms.client.datacollection.TransformationTestResult; import org.netxms.client.datacollection.WebServiceDefinition; import org.netxms.client.datacollection.WinPerfObject; import org.netxms.client.events.Alarm; import org.netxms.client.events.AlarmCategory; import org.netxms.client.events.AlarmComment; import org.netxms.client.events.BulkAlarmStateChangeData; import org.netxms.client.events.Event; import org.netxms.client.events.EventInfo; import org.netxms.client.events.EventProcessingPolicy; import org.netxms.client.events.EventProcessingPolicyRule; import org.netxms.client.events.EventReference; import org.netxms.client.events.EventTemplate; import org.netxms.client.events.SyslogRecord; import org.netxms.client.log.Log; import org.netxms.client.maps.MapDCIInstance; import org.netxms.client.maps.NetworkMapLink; import org.netxms.client.maps.NetworkMapPage; import org.netxms.client.maps.configs.SingleDciConfig; import org.netxms.client.maps.elements.NetworkMapElement; import org.netxms.client.maps.elements.NetworkMapObject; import org.netxms.client.market.Repository; import org.netxms.client.mt.MappingTable; import org.netxms.client.mt.MappingTableDescriptor; import org.netxms.client.objects.AbstractNode; import org.netxms.client.objects.AbstractObject; import org.netxms.client.objects.AccessPoint; import org.netxms.client.objects.Asset; import org.netxms.client.objects.AssetGroup; import org.netxms.client.objects.AssetRoot; import org.netxms.client.objects.BusinessService; import org.netxms.client.objects.BusinessServicePrototype; import org.netxms.client.objects.BusinessServiceRoot; import org.netxms.client.objects.Chassis; import org.netxms.client.objects.Cluster; import org.netxms.client.objects.ClusterResource; import org.netxms.client.objects.Condition; import org.netxms.client.objects.Container; import org.netxms.client.objects.Dashboard; import org.netxms.client.objects.DashboardGroup; import org.netxms.client.objects.DashboardRoot; import org.netxms.client.objects.DependentNode; import org.netxms.client.objects.EntireNetwork; import org.netxms.client.objects.GenericObject; import org.netxms.client.objects.Interface; import org.netxms.client.objects.MobileDevice; import org.netxms.client.objects.MutableObjectCategory; import org.netxms.client.objects.NetworkMap; import org.netxms.client.objects.NetworkMapGroup; import org.netxms.client.objects.NetworkMapRoot; import org.netxms.client.objects.NetworkService; import org.netxms.client.objects.Node; import org.netxms.client.objects.ObjectCategory; import org.netxms.client.objects.Rack; import org.netxms.client.objects.Sensor; import org.netxms.client.objects.ServiceRoot; import org.netxms.client.objects.Subnet; import org.netxms.client.objects.Template; import org.netxms.client.objects.TemplateGroup; import org.netxms.client.objects.TemplateRoot; import org.netxms.client.objects.UnknownObject; import org.netxms.client.objects.VPNConnector; import org.netxms.client.objects.Zone; import org.netxms.client.objects.configs.CustomAttribute; import org.netxms.client.objects.configs.PassiveRackElement; import org.netxms.client.objects.interfaces.NodeItemPair; import org.netxms.client.objects.queries.ObjectQuery; import org.netxms.client.objects.queries.ObjectQueryResult; import org.netxms.client.objecttools.ObjectContextBase; import org.netxms.client.objecttools.ObjectTool; import org.netxms.client.objecttools.ObjectToolDetails; import org.netxms.client.objecttools.ObjectToolFolder; import org.netxms.client.packages.PackageDeploymentListener; import org.netxms.client.packages.PackageInfo; import org.netxms.client.reporting.ReportDefinition; import org.netxms.client.reporting.ReportRenderFormat; import org.netxms.client.reporting.ReportResult; import org.netxms.client.reporting.ReportingJob; import org.netxms.client.reporting.ReportingJobConfiguration; import org.netxms.client.server.AgentFile; import org.netxms.client.server.ServerConsoleListener; import org.netxms.client.server.ServerFile; import org.netxms.client.server.ServerJob; import org.netxms.client.server.ServerJobIdUpdater; import org.netxms.client.server.ServerVariable; import org.netxms.client.snmp.SnmpTrap; import org.netxms.client.snmp.SnmpTrapLogRecord; import org.netxms.client.snmp.SnmpUsmCredential; import org.netxms.client.snmp.SnmpValue; import org.netxms.client.snmp.SnmpWalkListener; import org.netxms.client.topology.ArpCacheEntry; import org.netxms.client.topology.ConnectionPoint; import org.netxms.client.topology.FdbEntry; import org.netxms.client.topology.NetworkPath; import org.netxms.client.topology.OSPFInfo; import org.netxms.client.topology.Route; import org.netxms.client.topology.VlanInfo; import org.netxms.client.topology.WirelessStation; import org.netxms.client.users.AbstractUserObject; import org.netxms.client.users.ResponsibleUser; import org.netxms.client.users.TwoFactorAuthenticationMethod; import org.netxms.client.users.User; import org.netxms.client.users.UserGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jcraft.jzlib.Deflater; import com.jcraft.jzlib.JZlib; /** * Communication session with NetXMS server. */ public class NXCSession { // DCI resolve flags public static final int DCI_RES_SEARCH_NAME = 0x01; // Various public constants public static final int DEFAULT_CONN_PORT = 4701; // Core notification channels public static final String CHANNEL_AGENT_TUNNELS = "Core.AgentTunnels"; public static final String CHANNEL_ALARMS = "Core.Alarms"; public static final String CHANNEL_AUDIT_LOG = "Core.Audit"; public static final String CHANNEL_DC_THRESHOLDS = "Core.DC.Thresholds"; public static final String CHANNEL_GEO_AREAS = "Core.GeoAreas"; public static final String CHANNEL_EVENTS = "Core.Events"; public static final String CHANNEL_OBJECTS = "Core.Objects"; public static final String CHANNEL_SNMP_TRAPS = "Core.SNMP.Traps"; public static final String CHANNEL_SYSLOG = "Core.Syslog"; public static final String CHANNEL_USERDB = "Core.UserDB"; // Object sync options public static final int OBJECT_SYNC_NOTIFY = 0x0001; public static final int OBJECT_SYNC_WAIT = 0x0002; // Configuration import options public static final int CFG_IMPORT_REPLACE_EVENTS = 0x0001; public static final int CFG_IMPORT_REPLACE_ACTIONS = 0x0002; public static final int CFG_IMPORT_REPLACE_TEMPLATES = 0x0004; public static final int CFG_IMPORT_REPLACE_TRAPS = 0x0008; public static final int CFG_IMPORT_REPLACE_SCRIPTS = 0x0010; public static final int CFG_IMPORT_REPLACE_SUMMARY_TABLES = 0x0020; public static final int CFG_IMPORT_REPLACE_OBJECT_TOOLS = 0x0040; public static final int CFG_IMPORT_REPLACE_EPP_RULES = 0x0080; public static final int CFG_IMPORT_REPLACE_TEMPLATE_NAMES_LOCATIONS = 0x0100; public static final int CFG_IMPORT_DELETE_EMPTY_TEMPLATE_GROUPS = 0x0200; public static final int CFG_IMPORT_REPLACE_WEB_SVCERVICE_DEFINITIONS = 0x0400; public static final int CFG_IMPORT_REPLACE_AM_DEFINITIONS = 0x0800; // Address list IDs public static final int ADDRESS_LIST_DISCOVERY_TARGETS = 1; public static final int ADDRESS_LIST_DISCOVERY_FILTER = 2; // Server components public static final int SERVER_COMPONENT_DISCOVERY_MANAGER = 1; // Client types public static final int DESKTOP_CLIENT = 0; public static final int WEB_CLIENT = 1; public static final int MOBILE_CLIENT = 2; public static final int TABLET_CLIENT = 3; public static final int APPLICATION_CLIENT = 4; // Private constants private static final int CLIENT_CHALLENGE_SIZE = 256; private static final int MAX_DCI_DATA_ROWS = 200000; private static final int MAX_DCI_STRING_VALUE_LENGTH = 256; private static final int RECEIVED_FILE_TTL = 300000; // 300 seconds private static final int FILE_BUFFER_SIZE = 32768; // 32KB // Logger private static Logger logger = LoggerFactory.getLogger(NXCSession.class); // Internal synchronization objects private final Semaphore syncObjects = new Semaphore(1); private final Semaphore syncUserDB = new Semaphore(1); // Connection-related attributes private String connAddress; private int connPort; private boolean connUseEncryption; private String connClientInfo = "nxjclient/" + VersionInfo.version(); private int clientType = DESKTOP_CLIENT; private String clientAddress = null; private String clientLanguage = "en"; private boolean ignoreProtocolVersion = false; // Information about logged in user private int sessionId; private int userId; private String userName; private AuthenticationType authenticationMethod; private long userSystemRights; private boolean passwordExpired; private int graceLogins; // Internal communication data private Socket socket = null; private NXCPMsgWaitQueue msgWaitQueue = null; private ReceiverThread recvThread = null; private HousekeeperThread housekeeperThread = null; private AtomicLong requestId = new AtomicLong(1); private boolean connected = false; private boolean disconnected = false; private boolean serverConsoleConnected = false; private Integer serverConsoleConnectionCount = 0; private Object serverConsoleConnectionLock = new Object(); private boolean allowCompression = false; private EncryptionContext encryptionContext = null; private Throwable receiverStopCause = null; // Communication parameters private int defaultRecvBufferSize = 4194304; // Default is 4MB private int maxRecvBufferSize = 33554432; // Max is 32MB private int connectTimeout = 10000; // Default is 10 seconds private int commandTimeout = 30000; // Default is 30 seconds private int serverCommandOutputTimeout = 60000; // Notification listeners and queue private LinkedBlockingQueue notificationQueue = new LinkedBlockingQueue(8192); private Set listeners = new HashSet(0); private Set consoleListeners = new HashSet(0); private Map progressListeners = new HashMap(0); // Message subscriptions private Map messageSubscriptions = new HashMap(0); // Received files private Map receivedFiles = new HashMap(); // Received file updates(for file monitoring) private Map receivedFileUpdates = new HashMap(); // Server information private ProtocolVersion protocolVersion; private String serverVersion = "(unknown)"; private String serverBuild = "(unknown)"; private long serverId = 0; private String serverTimeZone; private byte[] serverChallenge = new byte[CLIENT_CHALLENGE_SIZE]; private boolean zoningEnabled = false; private boolean helpdeskLinkActive = false; private String tileServerURL; private String dateFormat; private String timeFormat; private String shortTimeFormat; private int defaultDciRetentionTime; private int defaultDciPollingInterval; private boolean strictAlarmStatusFlow; private boolean timedAlarmAckEnabled; private int minViewRefreshInterval; private long serverTime = System.currentTimeMillis(); private long serverTimeRecvTime = System.currentTimeMillis(); private Set serverComponents = new HashSet(0); private String serverName; private String serverColor; private String objectMaintenancePredefinedPeriods; // Configuration hints private Map clientConfigurationHints = new HashMap(); // Objects private Map objectList = new HashMap(); private Map objectListGUID = new HashMap(); private Map zoneList = new HashMap(); private Map objectCategories = new HashMap(); private boolean objectsSynchronized = false; private Set responsibleUserTags = new HashSet(); // Users private Map userDatabase = new HashMap(); private Map userDatabaseGUID = new HashMap(); private Set missingUsers = new HashSet(); // users that cannot be synchronized private boolean userDatabaseSynchronized = false; private Set userSyncList = new HashSet(); private List callbackList = new ArrayList(); // Event objects private Map eventTemplates = new HashMap(); private boolean eventTemplatesSynchronized = false; // Alarm categories private Map alarmCategories = new HashMap(); private boolean alarmCategoriesSynchronized = false; // Message of the day private String messageOfTheDay; // Registered license problems private LicenseProblem[] licenseProblems = null; // Cached list of prediction engines private List predictionEngines = null; // TCP proxies private Map tcpProxies = new HashMap(); private AtomicInteger tcpProxyChannelId = new AtomicInteger(1); private boolean clientAssignedTcpProxyId = false; // Set of objects whose child objects were already synchronized private Set synchronizedObjectSet = new HashSet(); // OUI cache private OUICache ouiCache; // Asset management schema private Map assetManagementSchema = new HashMap(); /** * Message subscription class */ final protected static class MessageSubscription { protected int messageCode; protected long messageId; /** * @param messageCode The message code * @param messageId The message ID */ protected MessageSubscription(int messageCode, long messageId) { this.messageCode = messageCode; this.messageId = messageId; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + messageCode; result = prime * result + (int)(messageId ^ (messageId >>> 32)); return result; } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MessageSubscription other = (MessageSubscription)obj; if (messageCode != other.messageCode) return false; if (messageId != other.messageId) return false; return true; } } /** * Receiver thread for NXCSession */ private class ReceiverThread extends Thread { ReceiverThread() { super("Network Message Receiver"); setDaemon(true); start(); } @Override public void run() { final NXCPMessageReceiver receiver = new NXCPMessageReceiver(defaultRecvBufferSize, maxRecvBufferSize); InputStream in; try { in = socket.getInputStream(); } catch(IOException e) { return; // Stop receiver thread if input stream cannot be obtained } int errorCount = 0; while(socket.isConnected()) { try { NXCPMessage msg = receiver.receiveMessage(in, encryptionContext); errorCount = 0; switch(msg.getMessageCode()) { case NXCPCodes.CMD_REQUEST_SESSION_KEY: setupEncryption(msg); break; case NXCPCodes.CMD_KEEPALIVE: serverTime = msg.getFieldAsInt64(NXCPCodes.VID_TIMESTAMP) * 1000; serverTimeRecvTime = System.currentTimeMillis(); break; case NXCPCodes.CMD_OBJECT: case NXCPCodes.CMD_OBJECT_UPDATE: if (!msg.getFieldAsBoolean(NXCPCodes.VID_IS_DELETED)) { final AbstractObject obj = createObjectFromMessage(msg); synchronized(objectList) { objectList.put(obj.getObjectId(), obj); objectListGUID.put(obj.getGuid(), obj); if (obj instanceof Zone) zoneList.put(((Zone)obj).getUIN(), (Zone)obj); } if (msg.getMessageCode() == NXCPCodes.CMD_OBJECT_UPDATE) { sendNotification(new SessionNotification(SessionNotification.OBJECT_CHANGED, obj.getObjectId(), obj)); } } else { long objectId = msg.getFieldAsInt32(NXCPCodes.VID_OBJECT_ID); synchronized(objectList) { AbstractObject object = objectList.get(objectId); if (object != null) { objectListGUID.remove(object.getGuid()); objectList.remove(objectId); if (object instanceof Zone) zoneList.remove(((Zone)object).getUIN()); } } sendNotification(new SessionNotification(SessionNotification.OBJECT_DELETED, objectId)); } break; case NXCPCodes.CMD_OBJECT_LIST_END: completeSync(syncObjects); break; case NXCPCodes.CMD_OBJECT_CATEGORY_UPDATE: processObjectCategoryUpdate(msg); break; case NXCPCodes.CMD_GEO_AREA_UPDATE: processGeoAreaUpdate(msg); break; case NXCPCodes.CMD_USER_DATA: final User user = new User(msg); synchronized(userDatabase) { if (user.isDeleted()) { AbstractUserObject o = userDatabase.remove(user.getId()); if (o != null) userDatabaseGUID.remove(o.getGuid()); missingUsers.add(user.getId()); } else { userDatabase.put(user.getId(), user); userDatabaseGUID.put(user.getGuid(), user); missingUsers.remove(user.getId()); } } break; case NXCPCodes.CMD_GROUP_DATA: final UserGroup group = new UserGroup(msg); synchronized(userDatabase) { if (group.isDeleted()) { AbstractUserObject o = userDatabase.remove(group.getId()); if (o != null) userDatabaseGUID.remove(o.getGuid()); missingUsers.add(group.getId()); } else { userDatabase.put(group.getId(), group); userDatabaseGUID.put(group.getGuid(), group); missingUsers.add(group.getId()); } } break; case NXCPCodes.CMD_USER_DB_EOF: completeSync(syncUserDB); break; case NXCPCodes.CMD_USER_DB_UPDATE: processUserDBUpdate(msg); break; case NXCPCodes.CMD_ALARM_UPDATE: sendNotification(new SessionNotification( msg.getFieldAsInt32(NXCPCodes.VID_NOTIFICATION_CODE) + SessionNotification.NOTIFY_BASE, new Alarm(msg))); break; case NXCPCodes.CMD_BULK_ALARM_STATE_CHANGE: processBulkAlarmStateChange(msg); break; case NXCPCodes.CMD_JOB_CHANGE_NOTIFICATION: sendNotification(new SessionNotification(SessionNotification.JOB_CHANGE, new ServerJob(msg))); break; case NXCPCodes.CMD_FILE_DATA: processFileData(msg); break; case NXCPCodes.CMD_FILE_MONITORING: processFileUpdate(msg); break; case NXCPCodes.CMD_ABORT_FILE_TRANSFER: processFileTransferError(msg); break; case NXCPCodes.CMD_NOTIFY: processNotificationMessage(msg, true); break; case NXCPCodes.CMD_RS_NOTIFY: processNotificationMessage(msg, false); break; case NXCPCodes.CMD_EVENTLOG_RECORDS: processNewEvents(msg); break; case NXCPCodes.CMD_TRAP_LOG_RECORDS: processNewTraps(msg); break; case NXCPCodes.CMD_SYSLOG_RECORDS: processSyslogRecords(msg); break; case NXCPCodes.CMD_ACTION_DB_UPDATE: processActionConfigChange(msg); break; case NXCPCodes.CMD_EVENT_DB_UPDATE: processEventConfigChange(msg); break; case NXCPCodes.CMD_TRAP_CFG_UPDATE: processTrapConfigChange(msg); break; case NXCPCodes.CMD_ADM_MESSAGE: processConsoleOutput(msg); break; case NXCPCodes.CMD_IMAGE_LIBRARY_UPDATE: processImageLibraryUpdate(msg); break; case NXCPCodes.CMD_GRAPH_UPDATE: GraphDefinition graph = GraphDefinition.createGraphSettings(msg, NXCPCodes.VID_GRAPH_LIST_BASE); sendNotification(new SessionNotification(SessionNotification.PREDEFINED_GRAPHS_CHANGED, graph.getId(), graph)); break; case NXCPCodes.CMD_ALARM_CATEGORY_UPDATE: processAlarmCategoryConfigChange(msg); break; case NXCPCodes.CMD_THRESHOLD_UPDATE: processThresholdChange(msg); break; case NXCPCodes.CMD_TCP_PROXY_DATA: processTcpProxyData((int)msg.getMessageId(), msg.getBinaryData()); break; case NXCPCodes.CMD_CLOSE_TCP_PROXY: processTcpProxyClosure(msg.getFieldAsInt32(NXCPCodes.VID_CHANNEL_ID), msg.getFieldAsInt32(NXCPCodes.VID_RCC)); break; case NXCPCodes.CMD_MODIFY_NODE_DCI: DataCollectionObject dco; int type = msg.getFieldAsInt32(NXCPCodes.VID_DCOBJECT_TYPE); switch(type) { case DataCollectionObject.DCO_TYPE_ITEM: dco = new DataCollectionItem(null, msg); break; case DataCollectionObject.DCO_TYPE_TABLE: dco = new DataCollectionTable(null, msg); break; default: dco = null; break; } sendNotification( new SessionNotification(SessionNotification.DCI_UPDATE, msg.getFieldAsInt64(NXCPCodes.VID_OBJECT_ID), dco)); break; case NXCPCodes.CMD_DELETE_NODE_DCI: sendNotification( new SessionNotification(SessionNotification.DCI_DELETE, msg.getFieldAsInt64(NXCPCodes.VID_OBJECT_ID), (Long)msg.getFieldAsInt64(NXCPCodes.VID_DCI_ID))); break; case NXCPCodes.CMD_SET_DCI_STATUS: int itemCount = msg.getFieldAsInt32(NXCPCodes.VID_NUM_ITEMS); final long[] itemList = new long[itemCount]; int pos = 0; for(int i = 0; i < itemCount; i++) { itemList[pos++] = msg.getFieldAsInt32(NXCPCodes.VID_ITEM_LIST + i); } sendNotification(new SessionNotification(SessionNotification.DCI_STATE_CHANGE, msg.getFieldAsInt64(NXCPCodes.VID_OBJECT_ID), new DCOStatusHolder(itemList, msg.getFieldAsInt32(NXCPCodes.VID_DCI_STATUS)))); break; case NXCPCodes.CMD_UPDATE_AGENT_POLICY: sendNotification(new SessionNotification(SessionNotification.POLICY_MODIFIED, msg.getFieldAsInt64(NXCPCodes.VID_TEMPLATE_ID), new AgentPolicy(msg))); break; case NXCPCodes.CMD_DELETE_AGENT_POLICY: sendNotification(new SessionNotification(SessionNotification.POLICY_DELETED, msg.getFieldAsInt64(NXCPCodes.VID_TEMPLATE_ID), msg.getFieldAsUUID(NXCPCodes.VID_GUID))); break; case NXCPCodes.CMD_UPDATE_SYSTEM_ACCESS_RIGHTS: userSystemRights = msg.getFieldAsInt64(NXCPCodes.VID_USER_SYS_RIGHTS); sendNotification(new SessionNotification(SessionNotification.SYSTEM_ACCESS_CHANGED, userSystemRights)); break; case NXCPCodes.CMD_UPDATE_BIZSVC_CHECK: sendNotification( new SessionNotification(SessionNotification.BIZSVC_CHECK_MODIFIED, msg.getFieldAsInt64(NXCPCodes.VID_CHECK_LIST_BASE), new BusinessServiceCheck(msg, NXCPCodes.VID_CHECK_LIST_BASE))); break; case NXCPCodes.CMD_DELETE_BIZSVC_CHECK: sendNotification(new SessionNotification(SessionNotification.BIZSVC_CHECK_DELETED, msg.getFieldAsInt64(NXCPCodes.VID_CHECK_ID))); break; case NXCPCodes.CMD_AGENT_TUNNEL_UPDATE: sendNotification( new SessionNotification(msg.getFieldAsInt32(NXCPCodes.VID_NOTIFICATION_CODE) + SessionNotification.NOTIFY_BASE, new AgentTunnel(msg, NXCPCodes.VID_ELEMENT_LIST_BASE))); break; case NXCPCodes.CMD_UPDATE_ASSET_ATTRIBUTE: AssetAttribute attr = new AssetAttribute(msg, NXCPCodes.VID_AM_ATTRIBUTES_BASE); sendNotification(new SessionNotification(SessionNotification.AM_ATTRIBUTE_UPDATED, 0, attr)); synchronized(assetManagementSchema) { assetManagementSchema.put(attr.getName(), attr); } break; case NXCPCodes.CMD_DELETE_ASSET_ATTRIBUTE: String attrName = msg.getFieldAsString(NXCPCodes.VID_NAME); sendNotification(new SessionNotification(SessionNotification.AM_ATTRIBUTE_DELETED, 0, attrName)); synchronized(assetManagementSchema) { assetManagementSchema.remove(attrName); } break; default: // Check subscriptions synchronized(messageSubscriptions) { MessageSubscription s = new MessageSubscription(msg.getMessageCode(), msg.getMessageId()); MessageHandler handler = messageSubscriptions.get(s); if (handler != null) { try { if (handler.processMessage(msg)) msg = null; } catch(Exception e) { logger.error("Exception in message handler", e); } if (handler.isComplete()) messageSubscriptions.remove(s); else handler.setLastMessageTimestamp(System.currentTimeMillis()); } } if (msg != null) { if (msg.getMessageCode() >= 0x1000) { // Custom message sendNotification(new SessionNotification(SessionNotification.CUSTOM_MESSAGE, msg)); } msgWaitQueue.putMessage(msg); } break; } } catch(IOException e) { if (!disconnected) { logger.debug("Receiver error", e); receiverStopCause = e; } break; // Stop on read errors } catch(NXCPException e) { logger.debug("Receiver error", e); if (e.getErrorCode() == NXCPException.SESSION_CLOSED) { receiverStopCause = e; break; } errorCount++; } catch(NXCException e) { logger.debug("Receiver error", e); if (e.getErrorCode() == RCC.ENCRYPTION_ERROR) { receiverStopCause = e; break; } errorCount++; } if (errorCount > 100) { receiverStopCause = new NXCPException(NXCPException.FATAL_PROTOCOL_ERROR); break; } } synchronized(tcpProxies) { Throwable cause = (receiverStopCause != null) ? receiverStopCause : new NXCPException(NXCPException.SESSION_CLOSED); for(TcpProxy p : tcpProxies.values()) p.abort(cause); } if (!disconnected) disconnect(SessionNotification.CONNECTION_BROKEN); logger.info("Network receiver thread stopped"); msgWaitQueue.shutdown(); } /** * Process server console output * * @param msg notification message */ private void processConsoleOutput(NXCPMessage msg) { final String text = msg.getFieldAsString(NXCPCodes.VID_MESSAGE); synchronized(consoleListeners) { for(ServerConsoleListener l : consoleListeners) { l.onConsoleOutput(text); } } } /** * Process event notification messages. * * @param msg NXCP message */ private void processNewEvents(final NXCPMessage msg) { int count = msg.getFieldAsInt32(NXCPCodes.VID_NUM_RECORDS); int order = msg.getFieldAsInt32(NXCPCodes.VID_RECORDS_ORDER); long varId = NXCPCodes.VID_EVENTLOG_MSG_BASE; for(int i = 0; i < count; i++) { Event event = new Event(msg, varId); sendNotification(new SessionNotification(SessionNotification.NEW_EVENTLOG_RECORD, order, event)); } } /** * Process SNMP trap notification messages. * * @param msg NXCP message */ private void processNewTraps(final NXCPMessage msg) { int count = msg.getFieldAsInt32(NXCPCodes.VID_NUM_RECORDS); int order = msg.getFieldAsInt32(NXCPCodes.VID_RECORDS_ORDER); long varId = NXCPCodes.VID_TRAP_LOG_MSG_BASE; for(int i = 0; i < count; i++) { SnmpTrapLogRecord trap = new SnmpTrapLogRecord(msg, varId); sendNotification(new SessionNotification(SessionNotification.NEW_SNMP_TRAP, order, trap)); } } /** * Process syslog messages. * * @param msg NXCP message */ private void processSyslogRecords(final NXCPMessage msg) { int count = msg.getFieldAsInt32(NXCPCodes.VID_NUM_RECORDS); int order = msg.getFieldAsInt32(NXCPCodes.VID_RECORDS_ORDER); long varId = NXCPCodes.VID_SYSLOG_MSG_BASE; for(int i = 0; i < count; i++) { SyslogRecord record = new SyslogRecord(msg, varId); sendNotification(new SessionNotification(SessionNotification.NEW_SYSLOG_RECORD, order, record)); } } /** * Process CMD_BULK_ALARM_STATE_CHANGE notification message * * @param msg NXCP message */ private void processBulkAlarmStateChange(final NXCPMessage msg) { int code = msg.getFieldAsInt32(NXCPCodes.VID_NOTIFICATION_CODE) + SessionNotification.NOTIFY_BASE; sendNotification(new SessionNotification(code, new BulkAlarmStateChangeData(msg))); } /** * Process CMD_NOTIFY message * * @param msg NXCP message */ private void processNotificationMessage(final NXCPMessage msg, boolean shiftCode) { int code = msg.getFieldAsInt32(NXCPCodes.VID_NOTIFICATION_CODE); if (shiftCode) code += SessionNotification.NOTIFY_BASE; long data = msg.getFieldAsInt64(NXCPCodes.VID_NOTIFICATION_DATA); switch(code) { case SessionNotification.ALARM_STATUS_FLOW_CHANGED: strictAlarmStatusFlow = ((int)data != 0); break; case SessionNotification.RELOAD_EVENT_DB: if (eventTemplatesSynchronized) { resyncEventTemplates(); } break; case SessionNotification.SESSION_KILLED: case SessionNotification.SERVER_SHUTDOWN: case SessionNotification.CONNECTION_BROKEN: backgroundDisconnect(code); return; // backgroundDisconnect will send disconnect notification case SessionNotification.OBJECT_CATEGORY_DELETED: synchronized(objectCategories) { objectCategories.remove((int)data); } break; } sendNotification(new SessionNotification(code, data)); } /** * Process CMD_FILE_MONITORING message * * @param msg NXCP message */ private void processFileUpdate(final NXCPMessage msg) { UUID monitorId = msg.getFieldAsUUID(NXCPCodes.VID_MONITOR_ID); String newData = msg.getFieldAsString(NXCPCodes.VID_FILE_DATA); synchronized(receivedFileUpdates) { String existingData = receivedFileUpdates.get(monitorId); receivedFileUpdates.put(monitorId, (existingData != null) ? existingData + newData : newData); receivedFileUpdates.notifyAll(); } } /** * Process file data * * @param msg */ private void processFileData(final NXCPMessage msg) { long id = msg.getMessageId(); NXCReceivedFile file; synchronized(receivedFiles) { file = receivedFiles.get(id); if (file == null) { file = new NXCReceivedFile(id); receivedFiles.put(id, file); } } int bytes = file.writeData(msg.getBinaryData(), msg.isCompressedStream()); notifyProgressListener(id, bytes); if (msg.isEndOfFile()) { file.close(); synchronized(receivedFiles) { receivedFiles.notifyAll(); } } } /** * Process file transfer error * * @param msg */ private void processFileTransferError(final NXCPMessage msg) { long id = msg.getMessageId(); NXCReceivedFile file; synchronized(receivedFiles) { file = receivedFiles.get(id); if (file == null) { file = new NXCReceivedFile(id); receivedFiles.put(id, file); } file.abortTransfer(msg.getFieldAsBoolean(NXCPCodes.VID_JOB_CANCELLED)); receivedFiles.notifyAll(); } } /** * Process updates in user database * * @param msg Notification message */ private void processUserDBUpdate(final NXCPMessage msg) { final int code = msg.getFieldAsInt32(NXCPCodes.VID_UPDATE_TYPE); final long id = msg.getFieldAsInt64(NXCPCodes.VID_USER_ID); AbstractUserObject object = null; switch(code) { case SessionNotification.USER_DB_OBJECT_CREATED: case SessionNotification.USER_DB_OBJECT_MODIFIED: object = ((id & 0x40000000) != 0) ? new UserGroup(msg) : new User(msg); synchronized(userDatabase) { userDatabase.put(id, object); userDatabaseGUID.put(object.getGuid(), object); missingUsers.remove(id); } break; case SessionNotification.USER_DB_OBJECT_DELETED: synchronized(userDatabase) { object = userDatabase.get(id); if (object != null) { userDatabase.remove(id); userDatabaseGUID.remove(object.getGuid()); } missingUsers.add(id); } break; } // Send notification if changed object was found in local database copy // or added to it and notification code was known if (object != null) sendNotification(new SessionNotification(SessionNotification.USER_DB_CHANGED, code, object)); } /** * Process server notification on SNMP trap configuration change * * @param msg notification message */ private void processTrapConfigChange(final NXCPMessage msg) { int code = msg.getFieldAsInt32(NXCPCodes.VID_NOTIFICATION_CODE) + SessionNotification.NOTIFY_BASE; long id = msg.getFieldAsInt64(NXCPCodes.VID_TRAP_ID); SnmpTrap trap = (code != SessionNotification.TRAP_CONFIGURATION_DELETED) ? new SnmpTrap(msg) : null; sendNotification(new SessionNotification(code, id, trap)); } /** * Process server notification on action configuration change * * @param msg notification message */ private void processActionConfigChange(final NXCPMessage msg) { int code = msg.getFieldAsInt32(NXCPCodes.VID_NOTIFICATION_CODE) + SessionNotification.NOTIFY_BASE; long id = msg.getFieldAsInt64(NXCPCodes.VID_ACTION_ID); ServerAction action = (code != SessionNotification.ACTION_DELETED) ? new ServerAction(msg) : null; sendNotification(new SessionNotification(code, id, action)); } /** * Process server notification on event configuration change * * @param msg notification message */ private void processEventConfigChange(final NXCPMessage msg) { int code = msg.getFieldAsInt32(NXCPCodes.VID_NOTIFICATION_CODE) + SessionNotification.NOTIFY_BASE; long eventCode = msg.getFieldAsInt64(NXCPCodes.VID_EVENT_CODE); EventTemplate tmpl = (code != SessionNotification.EVENT_TEMPLATE_DELETED) ? new EventTemplate(msg, NXCPCodes.VID_ELEMENT_LIST_BASE) : null; if (eventTemplatesSynchronized) { synchronized(eventTemplates) { if (code == SessionNotification.EVENT_TEMPLATE_DELETED) { eventTemplates.remove(eventCode); } else { eventTemplates.put(tmpl.getCode(), tmpl); } } } sendNotification(new SessionNotification(code, tmpl == null ? eventCode : tmpl.getCode(), tmpl)); } /** * Process server notification on image library change * * @param msg notification message */ private void processImageLibraryUpdate(NXCPMessage msg) { final UUID imageGuid = msg.getFieldAsUUID(NXCPCodes.VID_GUID); final int flags = msg.getFieldAsInt32(NXCPCodes.VID_FLAGS); sendNotification(new SessionNotification(SessionNotification.IMAGE_LIBRARY_CHANGED, flags == 0 ? SessionNotification.IMAGE_UPDATED : SessionNotification.IMAGE_DELETED, imageGuid)); } /** * Process object category update * * @param msg notification message */ private void processObjectCategoryUpdate(NXCPMessage msg) { ObjectCategory category = new ObjectCategory(msg, NXCPCodes.VID_ELEMENT_LIST_BASE); synchronized(objectCategories) { objectCategories.put(category.getId(), category); } sendNotification(new SessionNotification(SessionNotification.OBJECT_CATEGORY_UPDATED, category.getId(), category)); } /** * Process geographical area update * * @param msg notification message */ private void processGeoAreaUpdate(NXCPMessage msg) { GeoArea area = new GeoArea(msg, NXCPCodes.VID_ELEMENT_LIST_BASE); sendNotification(new SessionNotification(SessionNotification.GEO_AREA_UPDATED, area.getId(), area)); } /** * Process server notification on threshold change * * @param msg notification message */ public void processThresholdChange(NXCPMessage msg) { sendNotification(new SessionNotification(SessionNotification.THRESHOLD_STATE_CHANGED, msg.getFieldAsInt64(NXCPCodes.VID_OBJECT_ID), new ThresholdStateChange(msg))); } /** * Process server notification on alarm category configuration change * * @param msg notification message */ private void processAlarmCategoryConfigChange(final NXCPMessage msg) { int code = msg.getFieldAsInt32(NXCPCodes.VID_NOTIFICATION_CODE) + SessionNotification.NOTIFY_BASE; long categoryId = msg.getFieldAsInt64(NXCPCodes.VID_ELEMENT_LIST_BASE); AlarmCategory ac = (code != SessionNotification.ALARM_CATEGORY_DELETED) ? new AlarmCategory(msg, NXCPCodes.VID_ELEMENT_LIST_BASE) : null; if (alarmCategoriesSynchronized) { synchronized(alarmCategories) { if (code == SessionNotification.ALARM_CATEGORY_DELETED) { alarmCategories.remove(categoryId); } else { alarmCategories.put(categoryId, ac); } } } sendNotification(new SessionNotification(code, categoryId, ac)); } /** * Process TCP proxy data * * @param channelId proxy channel ID * @param data received data block */ private void processTcpProxyData(int channelId, byte[] data) { TcpProxy proxy; synchronized(tcpProxies) { proxy = tcpProxies.get(channelId); } if (proxy != null) { proxy.processRemoteData(data); } else { logger.debug("Received TCP proxy data for unknown channel ID " + channelId); } } /** * Process TCP proxy closure. * * @param channelId proxy channel ID */ private void processTcpProxyClosure(int channelId, int rcc) { TcpProxy proxy; synchronized(tcpProxies) { proxy = tcpProxies.remove(channelId); } if (proxy != null) { if (rcc == RCC.SUCCESS) proxy.localClose(); else proxy.abort(new NXCException(rcc)); } } } /** * Housekeeper thread - cleans received files, etc. * * @author Victor */ private class HousekeeperThread extends Thread { private boolean stopFlag = false; HousekeeperThread() { setDaemon(true); start(); } /** * @see java.lang.Thread#run() */ @Override public void run() { while(!stopFlag) { try { sleep(1000); } catch(InterruptedException e) { } long currTime = System.currentTimeMillis(); // Check for old entries in received files synchronized(receivedFiles) { Iterator it = receivedFiles.values().iterator(); while(it.hasNext()) { NXCReceivedFile file = it.next(); if (file.getTimestamp() + RECEIVED_FILE_TTL < currTime) { file.getFile().delete(); it.remove(); } } } // Check timeouts on message subscriptions synchronized(messageSubscriptions) { Iterator> it = messageSubscriptions.entrySet().iterator(); while(it.hasNext()) { Entry e = it.next(); MessageHandler h = e.getValue(); if (currTime - h.getLastMessageTimestamp() > h.getMessageWaitTimeout()) { h.setExpired(); it.remove(); } } } } } /** * @param stopFlag the stopFlag to set */ public void setStopFlag(boolean stopFlag) { this.stopFlag = stopFlag; } } /** * Notification processor */ private class NotificationProcessor extends Thread { private SessionListener[] cachedListenerList = new SessionListener[0]; NotificationProcessor() { setName("Session Notification Processor"); setDaemon(true); start(); } /** * @see java.lang.Thread#run() */ @Override public void run() { while(true) { SessionNotification n; try { n = notificationQueue.take(); } catch(InterruptedException e) { continue; } if (n.getCode() == SessionNotification.STOP_PROCESSING_THREAD) break; if (n.getCode() == SessionNotification.UPDATE_LISTENER_LIST) { synchronized(listeners) { cachedListenerList = listeners.toArray(new SessionListener[listeners.size()]); } continue; } // loop must be on listeners set copy to prevent // possible deadlock when one of the listeners calls // syncExec on UI thread while UI thread trying to add // new listener and stays locked inside addListener for(SessionListener l : cachedListenerList) { try { l.notificationHandler(n); } catch(Exception e) { logger.error("Unhandled exception in notification handler", e); } } } cachedListenerList = null; } } /** * User synchronization thread */ class BackgroundUserSync extends Thread { public BackgroundUserSync() { setName("BackgroundUserSync"); setDaemon(true); start(); } /** * @see java.lang.Thread#run() */ @Override public void run() { while(true) { synchronized(userSyncList) { while(userSyncList.isEmpty()) { try { userSyncList.wait(); } catch(InterruptedException e) { } } } // Delay actual sync in case more synchronization requests will come try { Thread.sleep(200); } catch(InterruptedException e) { } Set userSyncListCopy; List callbackListCopy; synchronized(userSyncList) { userSyncListCopy = userSyncList; userSyncList = new HashSet(); callbackListCopy = callbackList; callbackList = new ArrayList(); } try { syncMissingUsers(userSyncListCopy); for(Runnable cb : callbackListCopy) cb.run(); } catch(Exception e) { logger.error("Exception while synchronizing user database objects", e); } } } } /** * Create session object that will connect to given address on default port (4701) without encryption. * * @param connAddress server host name or IP address */ public NXCSession(String connAddress) { this(connAddress, DEFAULT_CONN_PORT, false); } /** * Create session object that will connect to given address on given port without encryption. * * @param connAddress server host name or IP address * @param connPort TCP port */ public NXCSession(String connAddress, int connPort) { this(connAddress, connPort, false); } /** * Create session object that will connect to given address on given port. * * @param connAddress server host name or IP address * @param connPort TCP port * @param connUseEncryption setup encrypted session if true */ public NXCSession(String connAddress, int connPort, boolean connUseEncryption) { this.connAddress = connAddress; this.connPort = connPort; this.connUseEncryption = connUseEncryption; ouiCache = new OUICache(this); } /** * Create custom object from NXCP message. May be overridden by derived classes to create custom * NetXMS objects. This method called before standard object creation, so it can be used for * overriding standard object classes. If this method returns null, standard object * creation mechanism will be used. Default implementation will always return null. * * @param objectClass NetXMS object class ID * @param msg Source NXCP message * @return NetXMS object or null if object cannot be created */ protected AbstractObject createCustomObjectFromMessage(int objectClass, NXCPMessage msg) { return null; } /** * Create object from message * * @param msg Source NXCP message * @return NetXMS object */ private AbstractObject createObjectFromMessage(NXCPMessage msg) { final int objectClass = msg.getFieldAsInt32(NXCPCodes.VID_OBJECT_CLASS); AbstractObject object = createCustomObjectFromMessage(objectClass, msg); if (object != null) return object; switch(objectClass) { case AbstractObject.OBJECT_ACCESSPOINT: object = new AccessPoint(msg, this); break; case AbstractObject.OBJECT_ASSET: object = new Asset(msg, this); break; case AbstractObject.OBJECT_ASSETGROUP: object = new AssetGroup(msg, this); break; case AbstractObject.OBJECT_ASSETROOT: object = new AssetRoot(msg, this); break; case AbstractObject.OBJECT_BUSINESSSERVICE: object = new BusinessService(msg, this); break; case AbstractObject.OBJECT_BUSINESSSERVICEPROTOTYPE: object = new BusinessServicePrototype(msg, this); break; case AbstractObject.OBJECT_BUSINESSSERVICEROOT: object = new BusinessServiceRoot(msg, this); break; case AbstractObject.OBJECT_CHASSIS: object = new Chassis(msg, this); break; case AbstractObject.OBJECT_CLUSTER: object = new Cluster(msg, this); break; case AbstractObject.OBJECT_CONDITION: object = new Condition(msg, this); break; case AbstractObject.OBJECT_CONTAINER: object = new Container(msg, this); break; case AbstractObject.OBJECT_DASHBOARDGROUP: object = new DashboardGroup(msg, this); break; case AbstractObject.OBJECT_DASHBOARD: object = new Dashboard(msg, this); break; case AbstractObject.OBJECT_DASHBOARDROOT: object = new DashboardRoot(msg, this); break; case AbstractObject.OBJECT_INTERFACE: object = new Interface(msg, this); break; case AbstractObject.OBJECT_MOBILEDEVICE: object = new MobileDevice(msg, this); break; case AbstractObject.OBJECT_NETWORK: object = new EntireNetwork(msg, this); break; case AbstractObject.OBJECT_NETWORKMAP: object = new NetworkMap(msg, this); break; case AbstractObject.OBJECT_NETWORKMAPGROUP: object = new NetworkMapGroup(msg, this); break; case AbstractObject.OBJECT_NETWORKMAPROOT: object = new NetworkMapRoot(msg, this); break; case AbstractObject.OBJECT_NETWORKSERVICE: object = new NetworkService(msg, this); break; case AbstractObject.OBJECT_NODE: object = new Node(msg, this); break; case AbstractObject.OBJECT_RACK: object = new Rack(msg, this); break; case AbstractObject.OBJECT_SENSOR: object = new Sensor(msg, this); break; case AbstractObject.OBJECT_SERVICEROOT: object = new ServiceRoot(msg, this); break; case AbstractObject.OBJECT_SUBNET: object = new Subnet(msg, this); break; case AbstractObject.OBJECT_TEMPLATE: object = new Template(msg, this); break; case AbstractObject.OBJECT_TEMPLATEGROUP: object = new TemplateGroup(msg, this); break; case AbstractObject.OBJECT_TEMPLATEROOT: object = new TemplateRoot(msg, this); break; case AbstractObject.OBJECT_VPNCONNECTOR: object = new VPNConnector(msg, this); break; case AbstractObject.OBJECT_ZONE: object = new Zone(msg, this); break; default: object = new GenericObject(msg, this); break; } return object; } /** * Setup encryption * * @param msg CMD_REQUEST_SESSION_KEY message * @throws IOException * @throws NXCException */ private void setupEncryption(NXCPMessage msg) throws IOException, NXCException { final NXCPMessage response = new NXCPMessage(NXCPCodes.CMD_SESSION_KEY, msg.getMessageId()); response.setEncryptionDisabled(true); try { encryptionContext = EncryptionContext.createInstance(msg); response.setField(NXCPCodes.VID_SESSION_KEY, encryptionContext.getEncryptedSessionKey()); response.setField(NXCPCodes.VID_SESSION_IV, encryptionContext.getEncryptedIv()); response.setFieldInt16(NXCPCodes.VID_CIPHER, encryptionContext.getCipher()); response.setFieldInt16(NXCPCodes.VID_KEY_LENGTH, encryptionContext.getKeyLength()); response.setFieldInt16(NXCPCodes.VID_IV_LENGTH, encryptionContext.getIvLength()); response.setFieldInt32(NXCPCodes.VID_RCC, RCC.SUCCESS); logger.debug("Cipher selected: " + EncryptionContext.getCipherName(encryptionContext.getCipher())); logger.debug("Server key fingerprint: " + encryptionContext.getServerKeyFingerprint()); } catch(Exception e) { logger.error("Failed to create encryption context", e); response.setFieldInt32(NXCPCodes.VID_RCC, RCC.NO_CIPHERS); } sendMessage(response); } /** * Wait for synchronization completion */ private void waitForSync(final Semaphore syncObject, final int timeout) throws NXCException { if (timeout == 0) { syncObject.acquireUninterruptibly(); } else { long actualTimeout = timeout; boolean success = false; while(actualTimeout > 0) { long startTime = System.currentTimeMillis(); try { if (syncObject.tryAcquire(actualTimeout, TimeUnit.MILLISECONDS)) { success = true; syncObject.release(); break; } } catch(InterruptedException e) { } actualTimeout -= System.currentTimeMillis() - startTime; } if (!success) throw new NXCException(RCC.TIMEOUT); } } /** * Report synchronization completion * * @param syncObject Synchronization object */ private void completeSync(final Semaphore syncObject) { syncObject.release(); } /** * Add notification listener * * @param listener Listener to add */ public void addListener(SessionListener listener) { boolean changed; synchronized(listeners) { changed = listeners.add(listener); } if (changed) notificationQueue.offer(new SessionNotification(SessionNotification.UPDATE_LISTENER_LIST)); } /** * Remove notification listener * * @param listener Listener to remove */ public void removeListener(SessionListener listener) { boolean changed; synchronized(listeners) { changed = listeners.remove(listener); } if (changed) notificationQueue.offer(new SessionNotification(SessionNotification.UPDATE_LISTENER_LIST)); } /** * Add server console listener * * @param listener The ServerConsoleListener to add */ public void addConsoleListener(ServerConsoleListener listener) { synchronized(consoleListeners) { consoleListeners.add(listener); } } /** * Remove server console listener * * @param listener The ServerConsoleListener to remove */ public void removeConsoleListener(ServerConsoleListener listener) { synchronized(consoleListeners) { consoleListeners.remove(listener); } } /** * Subscribe to specific messages * * @param messageCode The message code * @param messageId The message ID * @param handler The message handler */ public void addMessageSubscription(int messageCode, long messageId, MessageHandler handler) { synchronized(messageSubscriptions) { messageSubscriptions.put(new MessageSubscription(messageCode, messageId), handler); } } /** * Remove message subscription * * @param messageCode The message code * @param messageId The message ID */ public void removeMessageSubscription(int messageCode, long messageId) { synchronized(messageSubscriptions) { messageSubscriptions.remove(new MessageSubscription(messageCode, messageId)); } } /** * Call notification handlers on all registered listeners * * @param n Notification object */ protected void sendNotification(SessionNotification n) { if (!notificationQueue.offer(n)) { logger.warn("Notification processing queue is full"); } } /** * Send message to server * * @param msg Message to sent * @throws IOException in case of socket communication failure * @throws NXCException in case of encryption error */ public synchronized void sendMessage(final NXCPMessage msg) throws IOException, NXCException { if (socket == null) { throw new IllegalStateException("Not connected to the server. Did you forgot to call connect() first?"); } final OutputStream outputStream = socket.getOutputStream(); byte[] message; if ((encryptionContext != null) && !msg.isEncryptionDisabled()) { try { message = encryptionContext.encryptMessage(msg, allowCompression); } catch(GeneralSecurityException e) { throw new NXCException(RCC.ENCRYPTION_ERROR); } } else { message = msg.createNXCPMessage(allowCompression); } outputStream.write(message); } /** * Send "abort file transfer" message * * @param requestId request ID * @throws IOException if socket I/O error occurs * @throws NXCException if operation was timed out */ private void abortFileTransfer(long requestId) throws IOException, NXCException { NXCPMessage msg = new NXCPMessage(NXCPCodes.CMD_ABORT_FILE_TRANSFER, requestId); msg.setBinaryMessage(true); msg.setBinaryData(new byte[0]); sendMessage(msg); } /** * Send file over NXCP * * @param requestId request ID * @param file source file to be sent * @param listener progress listener * @param allowStreamCompression true if data stream compression is allowed * @param offset offset to start data send or 0 if from the start * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ protected void sendFile(final long requestId, final File file, ProgressListener listener, boolean allowStreamCompression, long offset) throws IOException, NXCException { if (listener != null) listener.setTotalWorkAmount(file.length()); InputStream inputStream; try { inputStream = new BufferedInputStream(new FileInputStream(file)); } catch(IOException e) { abortFileTransfer(requestId); throw e; } sendFileStream(requestId, inputStream, listener, allowStreamCompression && (file.length() > 1024), offset); inputStream.close(); } /** * Send block of data as binary message * * @param requestId request ID * @param data file data * @param listener progress listener * @param allowStreamCompression true if data stream compression is allowed * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ protected void sendFile(final long requestId, final byte[] data, ProgressListener listener, boolean allowStreamCompression) throws IOException, NXCException { if (listener != null) listener.setTotalWorkAmount(data.length); final InputStream inputStream = new ByteArrayInputStream(data); sendFileStream(requestId, inputStream, listener, allowStreamCompression, 0); inputStream.close(); } /** * Send binary message, data loaded from provided input stream and splitted * into chunks of {@value FILE_BUFFER_SIZE} bytes * * @param requestId request ID * @param inputStream data input stream * @param listener progress listener * @param allowStreamCompression true if data stream compression is allowed * @param offset offset to start data send or 0 if from the start * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ private void sendFileStream(final long requestId, final InputStream inputStream, ProgressListener listener, boolean allowStreamCompression, long offset) throws IOException, NXCException { NXCPMessage msg = new NXCPMessage(NXCPCodes.CMD_FILE_DATA, requestId); msg.setBinaryMessage(true); inputStream.skip(offset); Deflater compressor = allowStreamCompression ? new Deflater(9) : null; msg.setStream(true, allowStreamCompression); final byte[] buffer = new byte[FILE_BUFFER_SIZE]; try { long bytesSent = 0; while(true) { final int bytesRead = inputStream.read(buffer); if (bytesRead < FILE_BUFFER_SIZE) { msg.setEndOfFile(true); } if ((compressor != null) && (bytesRead > 0)) { byte[] compressedData = new byte[compressor.deflateBound(bytesRead) + 4]; compressor.setInput(buffer, 0, bytesRead, false); compressor.setOutput(compressedData, 4, compressedData.length - 4); if (compressor.deflate(JZlib.Z_SYNC_FLUSH) != JZlib.Z_OK) throw new NXCException(RCC.IO_ERROR); int length = compressedData.length - compressor.getAvailOut(); byte[] payload = Arrays.copyOf(compressedData, length); payload[0] = 2; // DEFLATE method payload[1] = 0; // reserved payload[2] = (byte)((bytesRead >> 8) & 0xFF); // uncompressed length, high bits payload[3] = (byte)(bytesRead & 0xFF); // uncompressed length, low bits msg.setBinaryData(payload); } else { msg.setBinaryData((bytesRead > 0) ? Arrays.copyOf(buffer, bytesRead) : new byte[0]); } sendMessage(msg); bytesSent += (bytesRead == -1) ? 0 : bytesRead; if (listener != null) listener.markProgress(bytesSent); if (bytesRead < FILE_BUFFER_SIZE) break; } if (compressor != null) compressor.deflateEnd(); } catch(Exception e) { abortFileTransfer(requestId); throw e; } } /** * Wait for message with specific code and id. * * @param code Message code * @param id Message id * @param timeout Wait timeout in milliseconds * @return Message object * @throws NXCException if message was not arrived within timeout interval */ public NXCPMessage waitForMessage(final int code, final long id, final int timeout) throws NXCException { final NXCPMessage msg = msgWaitQueue.waitForMessage(code, id, timeout); if (msg == null) { throw (receiverStopCause != null) ? new NXCException(RCC.COMM_FAILURE, receiverStopCause) : new NXCException(RCC.TIMEOUT); } return msg; } /** * Wait for message with specific code and id. * * @param code Message code * @param id Message id * @return Message object * @throws NXCException if message was not arrived within timeout interval */ public NXCPMessage waitForMessage(final int code, final long id) throws NXCException { return waitForMessage(code, id, msgWaitQueue.getDefaultTimeout()); } /** * Wait for CMD_REQUEST_COMPLETED message with given id using default timeout * * @param id Message id * @return received message * @throws NXCException if message was not arrived within timeout interval or contains RCC other than RCC.SUCCESS */ public NXCPMessage waitForRCC(final long id) throws NXCException { return waitForRCC(id, msgWaitQueue.getDefaultTimeout()); } /** * Wait for CMD_REQUEST_COMPLETED message with given id * * @param id Message id * @param timeout Timeout in milliseconds * @return received message * @throws NXCException if message was not arrived within timeout interval or contains RCC other than RCC.SUCCESS */ public NXCPMessage waitForRCC(final long id, final int timeout) throws NXCException { final NXCPMessage msg = waitForMessage(NXCPCodes.CMD_REQUEST_COMPLETED, id, timeout); final int rcc = msg.getFieldAsInt32(NXCPCodes.VID_RCC); if (rcc != RCC.SUCCESS && rcc != RCC.FILE_APPEND_POSSIBLE) { long[] relatedObjects = msg.getFieldAsUInt32Array(NXCPCodes.VID_OBJECT_LIST); String description; if ((rcc == RCC.COMPONENT_LOCKED) && (msg.findField(NXCPCodes.VID_LOCKED_BY) != null)) { description = msg.getFieldAsString(NXCPCodes.VID_LOCKED_BY); } else if (msg.findField(NXCPCodes.VID_ERROR_TEXT) != null) { description = msg.getFieldAsString(NXCPCodes.VID_ERROR_TEXT); } else if (msg.findField(NXCPCodes.VID_VALUE) != null) { description = msg.getFieldAsString(NXCPCodes.VID_VALUE); } else { description = null; } throw new NXCException(rcc, description, relatedObjects); } return msg; } /** * Create new NXCP message with unique id * * @param code Message code * @return New message object */ public final NXCPMessage newMessage(int code) { return new NXCPMessage(code, requestId.getAndIncrement()); } /** * Wait for specific file to arrive * * @param id Message ID * @param timeout Timeout (since arrival of last received file part) in milliseconds to consider file transfer as timed out * @return Received file or null in case of failure */ public ReceivedFile waitForFile(final long id, final int timeout) { File file = null; int status = ReceivedFile.FAILED; long timestamp = System.currentTimeMillis(); while(true) { synchronized(receivedFiles) { NXCReceivedFile rf = receivedFiles.get(id); if (rf != null) { if (rf.getStatus() != NXCReceivedFile.OPEN) { if (rf.getStatus() == NXCReceivedFile.RECEIVED) { file = rf.getFile(); status = ReceivedFile.SUCCESS; } break; } timestamp = rf.getTimestamp(); } if (System.currentTimeMillis() - timestamp > timeout) { status = ReceivedFile.TIMEOUT; break; } try { receivedFiles.wait(timeout); } catch(InterruptedException e) { } } } return new ReceivedFile(file, status); } /** * Wait for update from specific file monitor. * * @param monitorId file monitor ID (previously returned by downloadFileFromAgent * @param timeout Wait timeout in milliseconds * @return Received tail string or null in case of failure */ public String waitForFileUpdate(UUID monitorId, final int timeout) { int timeRemaining = timeout; String data = null; while(timeRemaining > 0) { synchronized(receivedFileUpdates) { data = receivedFileUpdates.get(monitorId); if (data != null) { receivedFileUpdates.remove(monitorId); break; } long startTime = System.currentTimeMillis(); try { receivedFileUpdates.wait(timeRemaining); } catch(InterruptedException e) { } timeRemaining -= System.currentTimeMillis() - startTime; } } return data; } /** * Execute simple commands (without arguments and only returning RCC) * * @param command Command code * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ protected void executeSimpleCommand(int command) throws IOException, NXCException { final NXCPMessage msg = newMessage(command); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Receive table from server. * * @param requestId request ID * @param msgCode Message code * @return Received table * @throws NXCException if operation was timed out */ public Table receiveTable(long requestId, int msgCode) throws NXCException { NXCPMessage msg = waitForMessage(msgCode, requestId); Table table = new Table(msg); while(!msg.isEndOfSequence()) { msg = waitForMessage(msgCode, requestId); table.addDataFromMessage(msg); } return table; } /** * Connect to NetMS server. Establish connection with the server and set up encryption if required. * Only base protocol version check will be performed. Login must be performed before using session * after successful connect. * * @throws IOException if socket I/O error occurs * @throws UnknownHostException if the host is unknown * @throws NXCException if NetXMS server returns an error or operation was timed out * @throws IllegalStateException if the state is illegal */ public void connect() throws IOException, UnknownHostException, NXCException, IllegalStateException { connect(null); } /** * Connect to NetMS server. Establish connection with the server and set up encryption if required. * Versions of protocol components given in *componentVersions* will be validated. Login must be * performed before using session after successful connect. * * @param componentVersions The versions of the components * @throws IOException if socket I/O error occurs * @throws UnknownHostException if the host is unknown * @throws NXCException if NetXMS server returns an error or operation was timed out * @throws IllegalStateException if the state is illegal */ public void connect(int[] componentVersions) throws IOException, UnknownHostException, NXCException, IllegalStateException { if (connected) throw new IllegalStateException("Session already connected"); if (disconnected) throw new IllegalStateException("Session already disconnected and cannot be reused"); encryptionContext = null; logger.info("Connecting to " + connAddress + ":" + connPort); try { socket = new Socket(); socket.connect(new InetSocketAddress(connAddress, connPort), connectTimeout); msgWaitQueue = new NXCPMsgWaitQueue(commandTimeout); recvThread = new ReceiverThread(); housekeeperThread = new HousekeeperThread(); new NotificationProcessor(); new BackgroundUserSync(); // get server information logger.debug("Connection established, retrieving server info"); NXCPMessage request = newMessage(NXCPCodes.CMD_GET_SERVER_INFO); sendMessage(request); NXCPMessage response = waitForMessage(NXCPCodes.CMD_REQUEST_COMPLETED, request.getMessageId()); protocolVersion = new ProtocolVersion(response); if (!ignoreProtocolVersion) { if (!protocolVersion.isCorrectVersion(ProtocolVersion.INDEX_BASE) || ((componentVersions != null) && !validateProtocolVersions(componentVersions))) { logger.warn("Connection failed (" + protocolVersion.toString() + ")"); throw new NXCException(RCC.BAD_PROTOCOL, protocolVersion.toString()); } } else { logger.info("Protocol version ignored"); } serverVersion = response.getFieldAsString(NXCPCodes.VID_SERVER_VERSION); serverBuild = response.getFieldAsString(NXCPCodes.VID_SERVER_BUILD); serverId = response.getFieldAsInt64(NXCPCodes.VID_SERVER_ID); serverTimeZone = response.getFieldAsString(NXCPCodes.VID_TIMEZONE); serverTime = response.getFieldAsInt64(NXCPCodes.VID_TIMESTAMP) * 1000; serverTimeRecvTime = System.currentTimeMillis(); serverChallenge = response.getFieldAsBinary(NXCPCodes.VID_CHALLENGE); tileServerURL = response.getFieldAsString(NXCPCodes.VID_TILE_SERVER_URL); if (tileServerURL != null) { if (!tileServerURL.endsWith("/")) tileServerURL = tileServerURL.concat("/"); } else { tileServerURL = "http://tile.openstreetmap.org/"; } dateFormat = response.getFieldAsString(NXCPCodes.VID_DATE_FORMAT); if ((dateFormat == null) || (dateFormat.length() == 0)) dateFormat = "dd.MM.yyyy"; timeFormat = response.getFieldAsString(NXCPCodes.VID_TIME_FORMAT); if ((timeFormat == null) || (timeFormat.length() == 0)) timeFormat = "HH:mm:ss"; shortTimeFormat = response.getFieldAsString(NXCPCodes.VID_SHORT_TIME_FORMAT); if ((shortTimeFormat == null) || (shortTimeFormat.length() == 0)) shortTimeFormat = "HH:mm"; int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_COMPONENTS); long fieldId = NXCPCodes.VID_COMPONENT_LIST_BASE; for(int i = 0; i < count; i++) serverComponents.add(response.getFieldAsString(fieldId++)); // Setup encryption if required if (connUseEncryption) { request = newMessage(NXCPCodes.CMD_REQUEST_ENCRYPTION); request.setFieldInt16(NXCPCodes.VID_USE_X509_KEY_FORMAT, 1); sendMessage(request); waitForRCC(request.getMessageId()); } logger.info("Connected to server version " + serverVersion + " (build " + serverBuild + ")"); connected = true; } finally { if (!connected) disconnect(SessionNotification.USER_DISCONNECT); } } /** * Login to server using login name and password. * * @param login login name * @param password password * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out * @throws IllegalStateException if the state is illegal */ public void login(String login, String password) throws NXCException, IOException, IllegalStateException { login(AuthenticationType.PASSWORD, login, password, null, null, null); } /** * Login to server using authentication token. * * @param token authentication token * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out * @throws IllegalStateException if the state is illegal */ public void login(String token) throws NXCException, IOException, IllegalStateException { login(AuthenticationType.TOKEN, token, null, null, null, null); } /** * Login to server using certificate. * * @param login login name * @param certificate user's certificate * @param signature user's digital signature * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out * @throws IllegalStateException if the state is illegal */ public void login(String login, Certificate certificate, Signature signature) throws NXCException, IOException, IllegalStateException { login(AuthenticationType.CERTIFICATE, login, null, certificate, signature, null); } /** * Login to server. * * @param authType authentication type * @param login login name * @param password password * @param certificate user's certificate * @param signature user's digital signature * @param twoFactorAuthenticationCallback callback for handling two-factor authentication if requested by server * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out * @throws IllegalStateException if the state is illegal */ public void login(AuthenticationType authType, String login, String password, Certificate certificate, Signature signature, TwoFactorAuthenticationCallback twoFactorAuthenticationCallback) throws NXCException, IOException, IllegalStateException { if (!connected) throw new IllegalStateException("Session not connected"); if (disconnected) throw new IllegalStateException("Session already disconnected and cannot be reused"); authenticationMethod = authType; userName = login; NXCPMessage request = newMessage(NXCPCodes.CMD_LOGIN); request.setFieldInt16(NXCPCodes.VID_AUTH_TYPE, authType.getValue()); request.setField(NXCPCodes.VID_LOGIN_NAME, login); if ((authType == AuthenticationType.PASSWORD) || (authType == AuthenticationType.SSO_TICKET)) { request.setField(NXCPCodes.VID_PASSWORD, password); } else if (authType == AuthenticationType.CERTIFICATE) { if ((serverChallenge == null) || (signature == null) || (certificate == null)) { throw new NXCException(RCC.ENCRYPTION_ERROR); } byte[] signedChallenge = signChallenge(signature, serverChallenge); request.setField(NXCPCodes.VID_SIGNATURE, signedChallenge); try { request.setField(NXCPCodes.VID_CERTIFICATE, certificate.getEncoded()); } catch(CertificateEncodingException e) { throw new NXCException(RCC.ENCRYPTION_ERROR); } } if (twoFactorAuthenticationCallback != null) { byte[] token = twoFactorAuthenticationCallback.getTrustedDeviceToken(serverId, login); if ((token != null) && (token.length != 0)) request.setField(NXCPCodes.VID_TRUSTED_DEVICE_TOKEN, token); } request.setField(NXCPCodes.VID_LIBNXCL_VERSION, VersionInfo.version()); request.setField(NXCPCodes.VID_CLIENT_INFO, connClientInfo); request.setField(NXCPCodes.VID_OS_INFO, System.getProperty("os.name") + " " + System.getProperty("os.version")); request.setFieldInt16(NXCPCodes.VID_CLIENT_TYPE, clientType); if (clientAddress != null) { logger.debug("Client address provided: " + clientAddress); request.setField(NXCPCodes.VID_CLIENT_ADDRESS, clientAddress); } if (clientLanguage != null) request.setField(NXCPCodes.VID_LANGUAGE, clientLanguage); request.setFieldInt16(NXCPCodes.VID_ENABLE_COMPRESSION, 1); sendMessage(request); NXCPMessage response = waitForMessage(NXCPCodes.CMD_REQUEST_COMPLETED, request.getMessageId()); int rcc = response.getFieldAsInt32(NXCPCodes.VID_RCC); logger.debug("CMD_LOGIN_RESP received, RCC=" + rcc); if ((rcc == RCC.NEED_2FA) && (twoFactorAuthenticationCallback != null)) { logger.info("Two factor authentication requested by server"); List methods = response.getStringListFromFields(NXCPCodes.VID_2FA_METHOD_LIST_BASE, NXCPCodes.VID_2FA_METHOD_COUNT); boolean trustedDevicesAllowed = response.getFieldAsBoolean(NXCPCodes.VID_TRUSTED_DEVICES_ALLOWED); int selectedMethod = twoFactorAuthenticationCallback.selectMethod(methods); if (selectedMethod < 0) { logger.debug("2FA method selection cancelled by user"); throw new NXCException(RCC.OPERATION_CANCELLED); } logger.debug("Selected 2FA method " + selectedMethod); if ((selectedMethod >= 0) && (selectedMethod < methods.size())) { request = newMessage(NXCPCodes.CMD_2FA_PREPARE_CHALLENGE); request.setField(NXCPCodes.VID_2FA_METHOD, methods.get(selectedMethod)); sendMessage(request); response = waitForMessage(NXCPCodes.CMD_REQUEST_COMPLETED, request.getMessageId()); rcc = response.getFieldAsInt32(NXCPCodes.VID_RCC); logger.debug("Two factor challenge preparation completed, RCC=" + rcc); if (rcc == RCC.SUCCESS) { String challenge = response.getFieldAsString(NXCPCodes.VID_CHALLENGE); String qrLabel = response.getFieldAsString(NXCPCodes.VID_QR_LABEL); String userResponse = twoFactorAuthenticationCallback.getUserResponse(challenge, qrLabel, trustedDevicesAllowed); if (userResponse == null) { logger.debug("2FA response read cancelled by user"); throw new NXCException(RCC.OPERATION_CANCELLED); } request = newMessage(NXCPCodes.CMD_2FA_VALIDATE_RESPONSE); request.setField(NXCPCodes.VID_2FA_RESPONSE, userResponse); sendMessage(request); response = waitForMessage(NXCPCodes.CMD_REQUEST_COMPLETED, request.getMessageId()); rcc = response.getFieldAsInt32(NXCPCodes.VID_RCC); logger.debug("Two factor validation response received, RCC=" + rcc); if ((rcc == RCC.SUCCESS) && trustedDevicesAllowed && response.isFieldPresent(NXCPCodes.VID_TRUSTED_DEVICE_TOKEN)) { byte[] token = response.getFieldAsBinary(NXCPCodes.VID_TRUSTED_DEVICE_TOKEN); if ((token != null) && (token.length > 0)) twoFactorAuthenticationCallback.saveTrustedDeviceToken(serverId, login, token); } } } } if (rcc != RCC.SUCCESS) { logger.warn("Login failed, RCC=" + rcc); throw new NXCException(rcc); } userId = response.getFieldAsInt32(NXCPCodes.VID_USER_ID); sessionId = response.getFieldAsInt32(NXCPCodes.VID_SESSION_ID); userSystemRights = response.getFieldAsInt64(NXCPCodes.VID_USER_SYS_RIGHTS); passwordExpired = response.getFieldAsBoolean(NXCPCodes.VID_CHANGE_PASSWD_FLAG); graceLogins = response.getFieldAsInt32(NXCPCodes.VID_GRACE_LOGINS); zoningEnabled = response.getFieldAsBoolean(NXCPCodes.VID_ZONING_ENABLED); helpdeskLinkActive = response.getFieldAsBoolean(NXCPCodes.VID_HELPDESK_LINK_ACTIVE); clientAssignedTcpProxyId = response.getFieldAsBoolean(NXCPCodes.VID_TCP_PROXY_CLIENT_CID); // Server may send updated user name if (response.isFieldPresent(NXCPCodes.VID_USER_NAME)) userName = response.getFieldAsString(NXCPCodes.VID_USER_NAME); defaultDciPollingInterval = response.getFieldAsInt32(NXCPCodes.VID_POLLING_INTERVAL); if (defaultDciPollingInterval == 0) defaultDciPollingInterval = 60; defaultDciRetentionTime = response.getFieldAsInt32(NXCPCodes.VID_RETENTION_TIME); if (defaultDciRetentionTime == 0) defaultDciRetentionTime = 30; minViewRefreshInterval = response.getFieldAsInt32(NXCPCodes.VID_VIEW_REFRESH_INTERVAL); if (minViewRefreshInterval <= 0) minViewRefreshInterval = 200; strictAlarmStatusFlow = response.getFieldAsBoolean(NXCPCodes.VID_ALARM_STATUS_FLOW_STATE); timedAlarmAckEnabled = response.getFieldAsBoolean(NXCPCodes.VID_TIMED_ALARM_ACK_ENABLED); serverCommandOutputTimeout = response.getFieldAsInt32(NXCPCodes.VID_SERVER_COMMAND_TIMEOUT) * 1000; serverColor = response.getFieldAsString(NXCPCodes.VID_SERVER_COLOR); serverName = response.getFieldAsString(NXCPCodes.VID_SERVER_NAME); if ((serverName == null) || serverName.isEmpty()) serverName = connAddress; objectMaintenancePredefinedPeriods = response.getFieldAsString(NXCPCodes.VID_OBJ_MAINT_PREDEF_TIMES); // compatibility with 2.2.x before 2.2.6 int count = response.getFieldAsInt32(NXCPCodes.VID_ALARM_LIST_DISP_LIMIT); clientConfigurationHints.put("AlarmList.DisplayLimit", Integer.toString(count)); count = response.getFieldAsInt32(NXCPCodes.VID_CONFIG_HINT_COUNT); if (count > 0) { long fieldId = NXCPCodes.VID_CONFIG_HINT_LIST_BASE; for(int i = 0; i < count; i++) { String key = response.getFieldAsString(fieldId++); String value = response.getFieldAsString(fieldId++); clientConfigurationHints.put(key, value); logger.info("Configuration hint: " + key + " = " + value); } } messageOfTheDay = response.getFieldAsString(NXCPCodes.VID_MESSAGE_OF_THE_DAY); String tags = response.getFieldAsString(NXCPCodes.VID_RESPONSIBLE_USER_TAGS); if (tags != null) { String[] elements = tags.split(","); for(String e : elements) { responsibleUserTags.add(e.trim()); } } count = response.getFieldAsInt32(NXCPCodes.VID_LICENSE_PROBLEM_COUNT); if (count > 0) { licenseProblems = new LicenseProblem[count]; long fieldId = NXCPCodes.VID_LICENSE_PROBLEM_BASE; for(int i = 0; i < count; i++) { licenseProblems[i] = new LicenseProblem(response, fieldId); fieldId++; logger.warn("License problem reported by server: " + licenseProblems[i].getDescription()); } } allowCompression = response.getFieldAsBoolean(NXCPCodes.VID_ENABLE_COMPRESSION); logger.info("Succesfully logged in, userId=" + userId); } /** * Disconnect session in background * * @param reason disconnect reason (appropriate session notification code) */ private void backgroundDisconnect(final int reason) { Thread t = new Thread(new Runnable() { @Override public void run() { disconnect(reason); } }, "NXCSession disconnect"); t.setDaemon(true); t.start(); } /** * Disconnect from server. * * @param reason disconnect reason (appropriate session notification code) */ synchronized private void disconnect(int reason) { if (disconnected) return; logger.debug("Session disconnect requested (reason=" + reason + ")"); disconnected = true; if (socket != null) { logger.debug("Closing TCP socket"); try { socket.shutdownInput(); socket.shutdownOutput(); } catch(IOException e) { } try { socket.close(); } catch(IOException e) { } } // cause notification processing thread to stop notificationQueue.clear(); if (reason != SessionNotification.USER_DISCONNECT) notificationQueue.offer(new SessionNotification(reason)); notificationQueue.offer(new SessionNotification(SessionNotification.STOP_PROCESSING_THREAD)); if (recvThread != null) { logger.debug("Waiting for receiver thread shutdown"); while(recvThread.isAlive()) { try { recvThread.join(); } catch(InterruptedException e) { } } recvThread = null; } if (housekeeperThread != null) { logger.debug("Waiting for housekeepeer thread shutdown"); housekeeperThread.setStopFlag(true); while(housekeeperThread.isAlive()) { try { housekeeperThread.join(); } catch(InterruptedException e) { } } housekeeperThread = null; } if (msgWaitQueue != null) { logger.debug("Shutdown message wait queue"); msgWaitQueue.shutdown(); msgWaitQueue = null; } connected = false; socket = null; listeners.clear(); consoleListeners.clear(); messageSubscriptions.clear(); receivedFiles.clear(); receivedFileUpdates.clear(); objectList.clear(); objectListGUID.clear(); zoneList.clear(); eventTemplates.clear(); userDatabase.clear(); userDatabaseGUID.clear(); alarmCategories.clear(); tcpProxies.clear(); logger.debug("Session disconnect completed"); } /** * Disconnect from server. */ public void disconnect() { disconnect(SessionNotification.USER_DISCONNECT); } /** * Get connection state * * @return connection state */ public boolean isConnected() { return connected; } /** * Get encryption state for current session. * * @return true if session is encrypted */ public boolean isEncrypted() { return connUseEncryption; } /** * Get the state of protocol version check * * @return true if protocol version should not be checked */ public boolean isIgnoreProtocolVersion() { return ignoreProtocolVersion; } /** * If set to true, protocol version is not checked at connect. * * @param ignoreProtocolVersion true if protocol version should not be checked */ public void setIgnoreProtocolVersion(boolean ignoreProtocolVersion) { this.ignoreProtocolVersion = ignoreProtocolVersion; } /** * Validate protocol versions * * @param versions the protocol versions * @return true if protocol versions are valid */ public boolean validateProtocolVersions(int[] versions) { if (protocolVersion == null) return false; for(int index : versions) if (!protocolVersion.isCorrectVersion(index)) return false; return true; } /** * Get default receiver buffer size. * * @return Default receiver buffer size in bytes. */ public int getDefaultRecvBufferSize() { return defaultRecvBufferSize; } /** * Get max receiver buffer size. * * @return Max receiver buffer size in bytes. */ public int getMaxRecvBufferSize() { return maxRecvBufferSize; } /** * Set receiver buffer size. This method should be called before connect(). It will not have any effect after * connect(). * * @param defaultBufferSize default size of receiver buffer in bytes. * @param maxBufferSize max size of receiver buffer in bytes. */ public void setRecvBufferSize(int defaultBufferSize, int maxBufferSize) { this.defaultRecvBufferSize = defaultBufferSize; this.maxRecvBufferSize = maxBufferSize; } /** * Get server address * * @return Server address */ public String getServerAddress() { return connAddress; } /** * Get NetXMS server version. * * @return Server version */ public String getServerVersion() { return serverVersion; } /** * Get NetXMS server build information. * * @return Server version */ public String getServerBuild() { return serverBuild; } /** * Get NetXMS server UID. * * @return Server UID */ public long getServerId() { return serverId; } /** * Get server time zone. * * @return server's time zone string */ public String getServerTimeZone() { return serverTimeZone; } /** * Get server name * * @return the serverName */ public String getServerName() { return serverName; } /** * Get server identification colour * * @return the serverColor */ public String getServerColor() { return serverColor; } /** * Get server time * * @return the serverTime */ public long getServerTime() { long offset = System.currentTimeMillis() - serverTimeRecvTime; return serverTime + offset; } /** * @return the objectMaintenancePredefinedPeriods */ public String getObjectMaintenancePredefinedPeriods() { return objectMaintenancePredefinedPeriods; } /** * @return the serverChallenge */ public byte[] getServerChallenge() { return serverChallenge; } /** * Check if server component with given id is registered * * @param componentId The component ID * @return true if server component is registered */ public boolean isServerComponentRegistered(String componentId) { return serverComponents.contains(componentId); } /** * Get list of registered server components * * @return Array of registered server components */ public String[] getRegisteredServerComponents() { return serverComponents.toArray(new String[serverComponents.size()]); } /** * Get server URL * * @return the tileServerURL */ public String getTileServerURL() { return tileServerURL; } /** * Get the state of zoning * * @return true if zoning is enabled */ public boolean isZoningEnabled() { return zoningEnabled; } /** * Get status of helpdesk integration module on server. * * @return true if helpdesk integration module loaded on server */ public boolean isHelpdeskLinkActive() { return helpdeskLinkActive; } /** * Get client information string * * @return The client information */ public String getClientInfo() { return connClientInfo; } /** * Set client information string * * @param connClientInfo The client info to set */ public void setClientInfo(final String connClientInfo) { this.connClientInfo = connClientInfo; } /** * Set command execution timeout. * * @param commandTimeout New command timeout */ public void setCommandTimeout(final int commandTimeout) { this.commandTimeout = commandTimeout; } /** * Set connect call timeout (must be set before connect call) * * @param connectTimeout connect timeout in milliseconds */ public void setConnectTimeout(int connectTimeout) { this.connectTimeout = connectTimeout; } /** * Get identifier of logged in user. * * @return Identifier of logged in user */ public int getUserId() { return userId; } /** * Get the current user name * * @return the userName */ public String getUserName() { return userName; } /** * Get the current authentication method * * @return the authenticationMethod */ public AuthenticationType getAuthenticationMethod() { return authenticationMethod; } /** * Get system-wide rights of currently logged in user. * * @return System-wide rights of currently logged in user */ public long getUserSystemRights() { return userSystemRights; } /** * Get message of the day if server config is set * * @return Message of the day */ public String getMessageOfTheDay() { return messageOfTheDay; } /** * Get list of license problems reported by server. This method will always return null for community edition server. * * @return list of license problems reported by server or null if there are none */ public LicenseProblem[] getLicenseProblems() { return licenseProblems; } /** * Check if server has any license problems. * * @return true if server has any license problems */ public boolean hasLicenseProblems() { return (licenseProblems != null) && (licenseProblems.length > 0); } /** * Check if password is expired for currently logged in user. * * @return true if password is expired */ public boolean isPasswordExpired() { return passwordExpired; } /** * Get number of remaining grace logins * * @return number of remaining grace logins */ public int getGraceLogins() { return graceLogins; } /** * Get maximum number of records allowed to be displayed in alarm list * * @return The limit of alarms displayed */ public int getAlarmListDisplayLimit() { return getClientConfigurationHintAsInt("AlarmList.DisplayLimit", 4096); } /** * Get client configuration hint as string * * @param name hint name * @param defaultValue default value (returned if given hint was not provided by server) * @return hint value as provided by server or default value */ public String getClientConfigurationHint(String name, String defaultValue) { String v = clientConfigurationHints.get(name); return (v != null) ? v : defaultValue; } /** * Get client configuration hint as string * * @param name hint name * @return hint value as provided by server or null */ public String getClientConfigurationHint(String name) { return getClientConfigurationHint(name, null); } /** * Get client configuration hint as integer * * @param name hint name * @param defaultValue default value (returned if given hint was not provided by server or is not valid integer) * @return hint value as provided by server or default value */ public int getClientConfigurationHintAsInt(String name, int defaultValue) { String v = clientConfigurationHints.get(name); if (v == null) return defaultValue; try { return Integer.parseInt(v); } catch(NumberFormatException e) { return defaultValue; } } /** * Get client configuration hint as boolean * * @param name hint name * @param defaultValue default value (returned if given hint was not provided by server or is not valid boolean) * @return hint value as provided by server or default value */ public boolean getClientConfigurationHintAsBoolean(String name, boolean defaultValue) { String v = clientConfigurationHints.get(name); if (v == null) return defaultValue; if (v.equalsIgnoreCase("true")) return true; if (v.equalsIgnoreCase("false")) return false; try { return Integer.parseInt(v) != 0; } catch(NumberFormatException e) { return defaultValue; } } /** * Get allowed tags for responsible users. * * @return allowed tags for responsible users */ public Set getResponsibleUserTags() { return new HashSet(responsibleUserTags); } /** * Synchronize object categories * * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncObjectCategories() throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_OBJECT_CATEGORIES); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); synchronized(objectCategories) { objectCategories.clear(); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < count; i++, fieldId += 10) { ObjectCategory category = new ObjectCategory(response, fieldId); objectCategories.put(category.getId(), category); } } } /** * Get object category by ID * * @param categoryId object category ID * @return object category or null */ public ObjectCategory getObjectCategory(int categoryId) { synchronized(objectCategories) { return objectCategories.get(categoryId); } } /** * Get all object categories. * * @return all object categories */ public List getObjectCategories() { synchronized(objectCategories) { return new ArrayList(objectCategories.values()); } } /** * Modify object category. * * @param category updated category object * @return ID of category object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public int modifyObjectCategory(MutableObjectCategory category) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_MODIFY_OBJECT_CATEGORY); category.fillMessage(msg); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsInt32(NXCPCodes.VID_CATEGORY_ID); } /** * Delete object category. This method will fail if category is in use (set to at least one object) unless forceDelete * parameter set to true. * * @param categoryId category ID * @param forceDelete force deletion flag - if set to true category will be deleted even if in use * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteObjectCategory(int categoryId, boolean forceDelete) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_OBJECT_CATEGORY); msg.setFieldInt32(NXCPCodes.VID_CATEGORY_ID, categoryId); msg.setField(NXCPCodes.VID_FORCE_DELETE, forceDelete); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Synchronizes NetXMS objects between server and client. After successful * sync, subscribe client to object change notifications. * * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncObjects() throws IOException, NXCException { syncObjects(true); } /** * Synchronizes NetXMS objects between server and client. After successful * sync, subscribe client to object change notifications. * * @param syncNodeComponents defines if node components should be synced * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncObjects(boolean syncNodeComponents) throws IOException, NXCException { syncObjectCategories(); syncObjects.acquireUninterruptibly(); NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_OBJECTS); msg.setField(NXCPCodes.VID_SYNC_NODE_COMPONENTS, syncNodeComponents); sendMessage(msg); waitForRCC(msg.getMessageId()); waitForSync(syncObjects, commandTimeout * 10); objectsSynchronized = objectsSynchronized || syncNodeComponents; sendNotification(new SessionNotification(SessionNotification.OBJECT_SYNC_COMPLETED)); subscribe(CHANNEL_OBJECTS); } /** * Synchronizes selected object set with the server. * * @param objects identifiers of objects need to be synchronized * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncObjectSet(long[] objects) throws IOException, NXCException { syncObjectSet(objects, 0); } /** * Synchronizes selected object set with the server. The following options are accepted: * OBJECT_SYNC_NOTIFY - send object update notification for each received object * OBJECT_SYNC_WAIT - wait until all requested objects received * * @param objects identifiers of objects need to be synchronized * @param options sync options (see above) * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncObjectSet(long[] objects, int options) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_SELECTED_OBJECTS); msg.setFieldInt16(NXCPCodes.VID_FLAGS, options); msg.setFieldInt32(NXCPCodes.VID_NUM_OBJECTS, objects.length); msg.setField(NXCPCodes.VID_OBJECT_LIST, objects); sendMessage(msg); waitForRCC(msg.getMessageId()); if ((options & OBJECT_SYNC_WAIT) != 0) waitForRCC(msg.getMessageId()); } /** * Synchronize only those objects from given set which are not synchronized yet. * * @param objects identifiers of objects need to be synchronized * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncMissingObjects(long[] objects) throws IOException, NXCException { syncMissingObjects(objects, 0); } /** * Synchronize only those objects from given set which are not synchronized yet. * Accepts all options which are valid for syncObjectSet. * * @param objects identifiers of objects need to be synchronized * @param options sync options (see comments for syncObjectSet) * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncMissingObjects(long[] objects, int options) throws IOException, NXCException { final long[] syncList = Arrays.copyOf(objects, objects.length); int count = syncList.length; synchronized(objectList) { for(int i = 0; i < syncList.length; i++) { if (objectList.containsKey(syncList[i])) { syncList[i] = 0; count--; } } } if (count > 0) { syncObjectSet(syncList, options); } } /** * Synchronize only those objects from given set which are not synchronized yet. * Accepts all options which are valid for syncObjectSet. * * @param objects identifiers of objects need to be synchronized * @param options sync options (see comments for syncObjectSet) * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncMissingObjects(List objects, int options) throws IOException, NXCException { final long[] syncList = new long[objects.size()]; for (int i = 0; i < objects.size(); i++) syncList[i] = objects.get(i); int count = syncList.length; synchronized(objectList) { for(int i = 0; i < syncList.length; i++) { if (objectList.containsKey(syncList[i])) { syncList[i] = 0; count--; } } } if (count > 0) { syncObjectSet(syncList, options); } } /** * Sync children of given object. * * @param object parent object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncChildren(AbstractObject object) throws NXCException, IOException { if (objectsSynchronized) return; boolean syncRequired; synchronized(synchronizedObjectSet) { syncRequired = !synchronizedObjectSet.contains(object.getObjectId()); } if (syncRequired) { syncMissingObjects(object.getChildIdList(), NXCSession.OBJECT_SYNC_WAIT); synchronized(synchronizedObjectSet) { synchronizedObjectSet.add(object.getObjectId()); } } } /** * Returns true if children are already synchronized for given object. * * @param id object id * @return true if children are synchronized */ public boolean areChildrenSynchronized(long id) { synchronized(synchronizedObjectSet) { return objectsSynchronized || synchronizedObjectSet.contains(id); } } /** * Find object by regex * * @param regex for object name * @return list of matching objects */ public List findObjectByRegex(String regex) { List objects = new ArrayList(); Matcher matcher = Pattern.compile(regex).matcher(""); synchronized(objectList) { for(AbstractObject o : objectList.values()) { matcher.reset(o.getObjectName()); if (matcher.matches()) objects.add(o); } } return objects; } /** * Find NetXMS object by it's identifier. * * @param id Object identifier * @return Object with given ID or null if object cannot be found */ public AbstractObject findObjectById(final long id) { synchronized(objectList) { return objectList.get(id); } } /** * Find NetXMS object by it's identifier or return wait an object to wait on * * @param id Object identifier * @return Object to wait on if object not found. If object is found it will be already set inside */ public FutureObject findFutureObjectById(final long id) { final FutureObject object; synchronized(objectList) { AbstractObject result = objectList.get(id); if (result == null) { object = new FutureObject(); addListener(new SessionListener() { @Override public void notificationHandler(SessionNotification n) { if (n.code == SessionNotification.OBJECT_CHANGED && n.subCode == id) { synchronized(object) { object.setObject((AbstractObject)n.object); object.notifyAll(); } removeListener(this); } } }); } else { object = new FutureObject(result); } } return object; } /** * Find NetXMS object by it's identifier and execute provided callback once found * * @param id Object identifier * @param callback callback to be called when object is found */ public void findObjectAsync(final long id, ObjectCreationListener callback) { if (callback == null) return; synchronized(objectList) { AbstractObject object = objectList.get(id); if (object == null) { addListener(new SessionListener() { @Override public void notificationHandler(SessionNotification n) { if (n.code == SessionNotification.OBJECT_CHANGED && n.subCode == id) { callback.objectCreated(findObjectById(id)); removeListener(this); } } }); } else { callback.objectCreated((AbstractObject)object); } } } /** * Find NetXMS object by it's identifier with additional class checking. * * @param id object identifier * @param requiredClass required object class * @param Object * @return Object with given ID or null if object cannot be found or is not an instance of required class */ @SuppressWarnings("unchecked") public T findObjectById(final long id, final Class requiredClass) { AbstractObject object = findObjectById(id); return requiredClass.isInstance(object) ? (T)object : null; } /** * Find multiple NetXMS objects by identifiers * * @param idList array of object identifiers * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers * @return list of found objects */ public List findMultipleObjects(final long[] idList, boolean returnUnknown) { return findMultipleObjects(idList, null, returnUnknown); } /** * Find multiple NetXMS objects by identifiers * * @param idList array of object identifiers * @param classFilter class filter for objects, or null to disable filtering * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers * @return list of found objects */ public List findMultipleObjects(final long[] idList, Class classFilter, boolean returnUnknown) { List result = new ArrayList(idList.length); synchronized(objectList) { for(int i = 0; i < idList.length; i++) { final AbstractObject object = objectList.get(idList[i]); if ((object != null) && ((classFilter == null) || classFilter.isInstance(object))) { result.add(object); } else if (returnUnknown) { result.add(new UnknownObject(idList[i], this)); } } } return result; } /** * Find multiple NetXMS objects by identifiers * * @param idList collection of object identifiers * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers * @return array of found objects */ public List findMultipleObjects(final Collection idList, boolean returnUnknown) { return findMultipleObjects(idList, null, returnUnknown); } /** * Find multiple NetXMS objects by identifiers * * @param idList collection of object identifiers * @param classFilter class filter for objects, or null to disable filtering * @param returnUnknown if true, this method will return UnknownObject placeholders for unknown object identifiers * @return array of found objects */ public List findMultipleObjects(final Collection idList, Class classFilter, boolean returnUnknown) { List result = new ArrayList(idList.size()); synchronized(objectList) { for(Long id : idList) { final AbstractObject object = objectList.get(id); if ((object != null) && ((classFilter == null) || classFilter.isInstance(object))) { result.add(object); } else if (returnUnknown) { result.add(new UnknownObject(id, this)); } } } return result; } /** * Find NetXMS object by it's GUID. * * @param guid Object GUID * @return Object with given ID or null if object cannot be found */ public AbstractObject findObjectByGUID(final UUID guid) { synchronized(objectList) { return objectListGUID.get(guid); } } /** * Find NetXMS object by it's GUID with additional class checking. * * @param guid object GUID * @param requiredClass required object class * @param Object * @return Object with given ID or null if object cannot be found or is not an instance of required class */ @SuppressWarnings("unchecked") public T findObjectByGUID(final UUID guid, final Class requiredClass) { AbstractObject object = findObjectByGUID(guid); return requiredClass.isInstance(object) ? (T)object : null; } /** * Find zone object by zone UIN (unique identification number). * * @param zoneUIN zone UIN to find * @return zone object or null */ public Zone findZone(int zoneUIN) { synchronized(objectList) { return zoneList.get(zoneUIN); } } /** * Get all accessible zone objects * * @return list of all accessible zone objects */ public List getAllZones() { synchronized(objectList) { return new ArrayList(zoneList.values()); } } /** * Find object by name. If multiple objects with same name exist, * it is not determined what object will be returned. Name comparison * is case-insensitive. * * @param name object name to find * @return object with matching name or null */ public AbstractObject findObjectByName(final String name) { AbstractObject result = null; synchronized(objectList) { for(AbstractObject object : objectList.values()) { if (object.getObjectName().equalsIgnoreCase(name)) { result = object; break; } } } return result; } /** * Find object by name with object filter. Name comparison * is case-insensitive. * * @param name object name to find * @param filter TODO * @return object with matching name or null */ public AbstractObject findObjectByName(final String name, ObjectFilter filter) { AbstractObject result = null; synchronized(objectList) { for(AbstractObject object : objectList.values()) { if (object.getObjectName().equalsIgnoreCase(name) && filter.filter(object)) { result = object; break; } } } return result; } /** * Find object by name using regular expression. If multiple objects with same name exist, * it is not determined what object will be returned. Name comparison is case-insensitive. * * @param pattern regular expression for matching object name * @return object with matching name or null */ public AbstractObject findObjectByNamePattern(final String pattern) { AbstractObject result = null; Matcher matcher = Pattern.compile(pattern).matcher(""); synchronized(objectList) { for(AbstractObject object : objectList.values()) { matcher.reset(object.getObjectName()); if (matcher.matches()) { result = object; break; } } } return result; } /** * Generic object find using filter. WIll return first object matching given filter. * * @param filter ObjectFilter to filter the result * @return first matching object or null */ public AbstractObject findObject(ObjectFilter filter) { AbstractObject result = null; synchronized(objectList) { for(AbstractObject object : objectList.values()) { if (filter.filter(object)) { result = object; break; } } } return result; } /** * Find all objects matching given filter. * * @param filter ObjectFilter to filter the result * @return list of matching objects (empty list if nothing found) */ public List filterObjects(ObjectFilter filter) { List result = new ArrayList(); synchronized(objectList) { for(AbstractObject object : objectList.values()) { if (filter.filter(object)) { result.add(object); } } } return result; } /** * Get list of top-level objects matching given class filter. Class filter * may be null to ignore object class. * * @param classFilter To filter the classes * @return List of all top matching level objects (either without parents or with * inaccessible parents) */ public AbstractObject[] getTopLevelObjects(Set classFilter) { HashSet list = new HashSet(); synchronized(objectList) { for(AbstractObject object : objectList.values()) { if ((classFilter != null) && !classFilter.contains(object.getObjectClass())) continue; if (!object.hasParents()) { list.add(object); } else { boolean hasParents = false; Iterator it = object.getParents(); while(it.hasNext()) { Long parent = it.next(); if (classFilter != null) { AbstractObject p = objectList.get(parent); if ((p != null) && classFilter.contains(p.getObjectClass())) { hasParents = true; break; } } else { if (objectList.containsKey(parent)) { hasParents = true; break; } } } if (!hasParents) list.add(object); } } } return list.toArray(new AbstractObject[list.size()]); } /** * Get list of top-level objects. * * @return List of all top level objects (either without parents or with * inaccessible parents) */ public AbstractObject[] getTopLevelObjects() { return getTopLevelObjects(null); } /** * Get list of all objects * * @return List of all objects */ public List getAllObjects() { synchronized(objectList) { return new ArrayList(objectList.values()); } } /** * Get object name by ID. * * @param objectId object ID * @return object name if object is known, or string in form [<object_id>] for unknown objects */ public String getObjectName(long objectId) { AbstractObject object = findObjectById(objectId); return (object != null) ? object.getObjectName() : ("[" + Long.toString(objectId) + "]"); } /** * Get object name with alias by ID. * * @param objectId object ID * @return object name with alias if object is known, or string in form [<object_id>] for unknown objects */ public String getObjectNameWithAlias(long objectId) { AbstractObject object = findObjectById(objectId); return (object != null) ? object.getNameWithAlias() : ("[" + Long.toString(objectId) + "]"); } /** * Get zone name by UIN * * @param zoneUIN zone UIN * @return zone name */ public String getZoneName(int zoneUIN) { Zone zone = findZone(zoneUIN); return (zone != null) ? zone.getObjectName() : ("[" + Long.toString(zoneUIN) + "]"); } /** * Query objects on server side * * @param query query to execute * @return list of matching objects * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List queryObjects(String query) throws IOException, NXCException { NXCPMessage request = newMessage(NXCPCodes.CMD_QUERY_OBJECTS); request.setField(NXCPCodes.VID_QUERY, query); sendMessage(request); NXCPMessage response = waitForRCC(request.getMessageId()); return findMultipleObjects(response.getFieldAsUInt32Array(NXCPCodes.VID_OBJECT_LIST), false); } /** * Query objects on server side and read certain object properties. Available properties are the same as in corresponding NXSL * objects or computed properties set using "with" statement in query. If readAllComputedProperties is set to * true then all computed properties will be retrieved in addition to those explicitly listed. * * @param query query to execute * @param properties object properties to read * @param orderBy list of properties for ordering result set (can be null) * @param inputFields set of input fields provided by user (can be null) * @param readAllComputedProperties if set to true, query will return all computed properties in addition to * properties explicitly listed in properties parameter * @param limit limit number of records (0 for unlimited) * @return list of matching objects * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List queryObjectDetails(String query, List properties, List orderBy, Map inputFields, boolean readAllComputedProperties, int limit) throws IOException, NXCException { NXCPMessage request = newMessage(NXCPCodes.CMD_QUERY_OBJECT_DETAILS); request.setField(NXCPCodes.VID_QUERY, query); if (properties != null) request.setFieldsFromStringCollection(properties, NXCPCodes.VID_FIELD_LIST_BASE, NXCPCodes.VID_FIELDS); if (orderBy != null) request.setFieldsFromStringCollection(orderBy, NXCPCodes.VID_ORDER_FIELD_LIST_BASE, NXCPCodes.VID_ORDER_FIELDS); if (inputFields != null) request.setFieldsFromStringMap(inputFields, NXCPCodes.VID_INPUT_FIELD_BASE, NXCPCodes.VID_INPUT_FIELD_COUNT); request.setFieldInt32(NXCPCodes.VID_RECORD_LIMIT, limit); request.setField(NXCPCodes.VID_READ_ALL_FIELDS, readAllComputedProperties); sendMessage(request); NXCPMessage response = waitForRCC(request.getMessageId()); long[] objects = response.getFieldAsUInt32Array(NXCPCodes.VID_OBJECT_LIST); List results = new ArrayList(objects.length); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < objects.length; i++) { Map values = response.getStringMapFromFields(fieldId + 1, fieldId); AbstractObject object = findObjectById(objects[i]); if (object != null) { results.add(new ObjectQueryResult(object, values)); } fieldId += values.size() * 2 + 1; } return results; } /** * Get list of configured object queries. * * @return list of configured object queries * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getObjectQueries() throws IOException, NXCException { NXCPMessage request = newMessage(NXCPCodes.CMD_GET_OBJECT_QUERIES); sendMessage(request); NXCPMessage response = waitForRCC(request.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); List queries = new ArrayList(count); long[] fieldId = new long[] { NXCPCodes.VID_ELEMENT_LIST_BASE }; for(int i = 0; i < count; i++) queries.add(new ObjectQuery(response, fieldId)); return queries; } /** * Modify object query. If query ID is 0 new query object will be created and assigned ID will be returned. * * @param query query to create or modify * @return assigned query ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public int modifyObjectQuery(ObjectQuery query) throws IOException, NXCException { NXCPMessage request = newMessage(NXCPCodes.CMD_MODIFY_OBJECT_QUERY); query.fillMessage(request); sendMessage(request); NXCPMessage response = waitForRCC(request.getMessageId()); return response.getFieldAsInt32(NXCPCodes.VID_QUERY_ID); } /** * Delete predefined object query. * * @param queryId query ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteObjectQuery(int queryId) throws IOException, NXCException { NXCPMessage request = newMessage(NXCPCodes.CMD_DELETE_OBJECT_QUERY); request.setFieldInt32(NXCPCodes.VID_QUERY_ID, queryId); sendMessage(request); waitForRCC(request.getMessageId()); } /** * Get list of active alarms. For accessing terminated alarms log view API should be used. * * @return Hash map containing alarms * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public HashMap getAlarms() throws IOException, NXCException { NXCPMessage request = newMessage(NXCPCodes.CMD_GET_ALL_ALARMS); final long rqId = request.getMessageId(); sendMessage(request); final HashMap alarmList = new HashMap(0); while(true) { request = waitForMessage(NXCPCodes.CMD_ALARM_DATA, rqId); long alarmId = request.getFieldAsInt32(NXCPCodes.VID_ALARM_ID); if (alarmId == 0) break; // ALARM_ID == 0 indicates end of list alarmList.put(alarmId, new Alarm(request)); } return alarmList; } /** * Get information about single active alarm. Terminated alarms cannot be accessed with this call. * * @param alarmId alarm ID * @return alarm object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Alarm getAlarm(long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return new Alarm(response); } /** * Get information about events related to single active alarm. Information for terminated alarms cannot be accessed with this call. * User must have "view alarms" permission on alarm's source node and "view event log" system-wide access. * * @param alarmId alarm ID * @return list of related events * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getAlarmEvents(long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM_EVENTS); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); List list = new ArrayList(count); long varId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < count; i++) { EventInfo parent = null; long rootId = response.getFieldAsInt64(varId + 1); if (rootId != 0) { for(EventInfo e : list) { if (e.getId() == rootId) { parent = e; break; } } } list.add(new EventInfo(response, varId, parent)); varId += 10; } return list; } /** * Acknowledge alarm. * * @param alarmId Identifier of alarm to be acknowledged. * @param sticky if set to true, acknowledged state will be made "sticky" (duplicate alarms with same key will not revert it back to outstanding) * @param time timeout for sticky acknowledge in seconds (0 for infinite) * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void acknowledgeAlarm(final long alarmId, boolean sticky, int time) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_ACK_ALARM); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); msg.setFieldInt16(NXCPCodes.VID_STICKY_FLAG, sticky ? 1 : 0); msg.setFieldInt32(NXCPCodes.VID_TIMESTAMP, time); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Acknowledge alarm. * * @param alarmId Identifier of alarm to be acknowledged. * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void acknowledgeAlarm(final long alarmId) throws IOException, NXCException { acknowledgeAlarm(alarmId, false, 0); } /** * Acknowledge alarm by helpdesk reference. * * @param helpdeskReference Helpdesk issue reference (e.g. JIRA issue key) * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void acknowledgeAlarm(String helpdeskReference) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_ACK_ALARM); msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Resolve alarm. * * @param alarmId Identifier of alarm to be resolved. * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void resolveAlarm(final long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_RESOLVE_ALARM); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Resolve alarm by helpdesk reference. * * @param helpdeskReference Identifier of alarm to be resolved. * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void resolveAlarm(final String helpdeskReference) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_RESOLVE_ALARM); msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Terminate alarm. * * @param alarmId Identifier of alarm to be terminated. * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void terminateAlarm(final long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_TERMINATE_ALARM); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Terminate alarm by helpdesk reference. * * @param helpdeskReference Identifier of alarm to be resolved. * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void terminateAlarm(final String helpdeskReference) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_TERMINATE_ALARM); msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference); sendMessage(msg); waitForRCC(msg.getMessageId()); } private Map bulkAlarmOperation(int cmd, List alarmIds) throws IOException, NXCException { NXCPMessage msg = newMessage(cmd); msg.setField(NXCPCodes.VID_ALARM_ID_LIST, alarmIds.toArray(new Long[alarmIds.size()])); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); Map operationFails = new HashMap(); // Returned alarm ID`s if there were any failed operations if (response.findField(NXCPCodes.VID_ALARM_ID_LIST) != null) { for(int i = 0; i < response.getFieldAsUInt32ArrayEx(NXCPCodes.VID_ALARM_ID_LIST).length; i++) { operationFails.put(response.getFieldAsUInt32ArrayEx(NXCPCodes.VID_ALARM_ID_LIST)[i], (Integer)response.getFieldAsUInt32ArrayEx(NXCPCodes.VID_FAIL_CODE_LIST)[i].intValue()); } } return operationFails; } /** * Bulk terminate alarms. * * @param alarmIds Identifiers of alarms to be terminated. * @return true if all alarms were terminated, false if some, or all, were not terminated * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map bulkResolveAlarms(List alarmIds) throws IOException, NXCException { return bulkAlarmOperation(NXCPCodes.CMD_BULK_RESOLVE_ALARMS, alarmIds); } /** * Bulk terminate alarms. * * @param alarmIds Identifiers of alarms to be terminated. * @return true if all alarms were terminated, false if some, or all, were not terminated * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map bulkTerminateAlarms(List alarmIds) throws IOException, NXCException { return bulkAlarmOperation(NXCPCodes.CMD_BULK_TERMINATE_ALARMS, alarmIds); } /** * Delete alarm. * * @param alarmId Identifier of alarm to be deleted. * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteAlarm(final long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_ALARM); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Open issue in helpdesk system from given alarm * * @param alarmId alarm identifier * @return helpdesk issue identifier * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String openHelpdeskIssue(long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_OPEN_HELPDESK_ISSUE); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); return waitForRCC(msg.getMessageId()).getFieldAsString(NXCPCodes.VID_HELPDESK_REF); } /** * Get URL for helpdesk issue associated with given alarm * * @param alarmId The ID of alarm * @return URL of helpdesk issue * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String getHelpdeskIssueUrl(long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_HELPDESK_URL); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); return waitForRCC(msg.getMessageId()).getFieldAsString(NXCPCodes.VID_URL); } /** * Unlink helpdesk issue from alarm. User must have OBJECT_ACCESS_UPDATE_ALARMS access right * on alarm's source object and SYSTEM_ACCESS_UNLINK_ISSUES system wide access right. * * @param helpdeskReference The helpdesk reference * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void unlinkHelpdeskIssue(String helpdeskReference) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UNLINK_HELPDESK_ISSUE); msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Unlink helpdesk issue from alarm. User must have OBJECT_ACCESS_UPDATE_ALARMS access right * on alarm's source object and SYSTEM_ACCESS_UNLINK_ISSUES system wide access right. * * @param alarmId alarm id * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void unlinkHelpdeskIssue(long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UNLINK_HELPDESK_ISSUE); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get list of comments for given alarm. * * @param alarmId alarm ID * @return list of alarm comments * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getAlarmComments(long alarmId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM_COMMENTS); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); final List comments = new ArrayList(count); long varId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < count; i++) { comments.add(new AlarmComment(response, varId)); varId += 10; } return comments; } /** * Delete alarm comment. * * @param alarmId alarm ID * @param commentId comment ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteAlarmComment(long alarmId, long commentId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_ALARM_COMMENT); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); msg.setFieldInt32(NXCPCodes.VID_COMMENT_ID, (int)commentId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Create alarm comment. * * @param alarmId The alarm ID * @param text The comment text * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void createAlarmComment(long alarmId, String text) throws IOException, NXCException { updateAlarmComment(alarmId, 0, text); } /** * Create alarm comment by helpdesk reference. * * @param helpdeskReference The helpdesk reference * @param text The reference text * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void createAlarmComment(final String helpdeskReference, String text) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_ALARM_COMMENT); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, 0); msg.setField(NXCPCodes.VID_HELPDESK_REF, helpdeskReference); msg.setField(NXCPCodes.VID_COMMENTS, text); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Update alarm comment. * If alarmId == 0 — new comment will be created. * * @param alarmId alarm ID * @param commentId comment ID or 0 for creating new comment * @param text message text * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void updateAlarmComment(long alarmId, long commentId, String text) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_ALARM_COMMENT); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); msg.setFieldInt32(NXCPCodes.VID_COMMENT_ID, (int)commentId); msg.setField(NXCPCodes.VID_COMMENTS, text); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Changes state of alarm status flow. Strict or not - terminate state can be set only after * resolve state or after any state. * * @param state state of alarm status flow - strict or not (1 or 0) * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setAlarmFlowState(int state) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_ALARM_STATUS_FLOW); msg.setFieldInt32(NXCPCodes.VID_ALARM_STATUS_FLOW_STATE, state); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get server configuration variables * * @return The server variables * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map getServerVariables() throws IOException, NXCException { NXCPMessage request = newMessage(NXCPCodes.CMD_GET_CONFIG_VARLIST); sendMessage(request); final NXCPMessage response = waitForRCC(request.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_VARIABLES); final HashMap varList = new HashMap(count); long id = NXCPCodes.VID_VARLIST_BASE; for(int i = 0; i < count; i++, id += 10) { ServerVariable v = new ServerVariable(response, id); varList.put(v.getName(), v); } count = response.getFieldAsInt32(NXCPCodes.VID_NUM_VALUES); for(int i = 0; i < count; i++) { ServerVariable var = varList.get(response.getFieldAsString(id++)); if (var != null) var.addPossibleValue(response, id); id += 2; } return varList; } /** * Get server public configuration variable * * @param name configuration variable name * @return value of requested configuration variable * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String getPublicServerVariable(String name) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_PUBLIC_CONFIG_VAR); msg.setField(NXCPCodes.VID_NAME, name); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsString(NXCPCodes.VID_VALUE); } /** * Get server public configuration variable as a int * * @param name configuration variable name * @return value of requested configuration variable * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public int getPublicServerVariableAsInt(String name) throws IOException, NXCException { return Integer.parseInt(getPublicServerVariable(name)); } /** * Get server public configuration variable as boolen value * * @param name configuration variable name * @return value of requested configuration variable * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public boolean getPublicServerVariableAsBoolean(String name) throws IOException, NXCException { String value = getPublicServerVariable(name); if ((value.equalsIgnoreCase("true")) || (value.equalsIgnoreCase("yes"))) return true; if ((value.equalsIgnoreCase("false")) || (value.equalsIgnoreCase("no"))) return false; try { int n = Integer.parseInt(value); return n != 0; } catch(NumberFormatException e) { return false; } } /** * Set server configuration variable * * @param name The name of the variable * @param value The value of the variable * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setServerVariable(final String name, final String value) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_CONFIG_VARIABLE); msg.setField(NXCPCodes.VID_NAME, name); msg.setField(NXCPCodes.VID_VALUE, value); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Delete server configuration variable * * @param name The name of the variable * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteServerVariable(final String name) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_CONFIG_VARIABLE); msg.setField(NXCPCodes.VID_NAME, name); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Set server configuration variables to default * * @param varList The list of variables * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setDefaultServerValues(List varList) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_CONFIG_TO_DEFAULT); long base = NXCPCodes.VID_VARLIST_BASE; for(ServerVariable v : varList) msg.setField(base++, v.getName()); msg.setFieldInt32(NXCPCodes.VID_NUM_VARIABLES, varList.size()); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get server config CLOB * * @param name The name of the config * @return The config CLOB * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String getServerConfigClob(final String name) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_CONFIG_GET_CLOB); msg.setField(NXCPCodes.VID_NAME, name); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsString(NXCPCodes.VID_VALUE); } /** * Set server config CLOB * * @param name The name to set * @param value The value to set * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setServerConfigClob(final String name, final String value) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_CONFIG_SET_CLOB); msg.setField(NXCPCodes.VID_NAME, name); msg.setField(NXCPCodes.VID_VALUE, value); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Subscribe to notification channel. Each subscribe call should be matched by unsubscribe call. * Calling subscribe on already subscribed channel will increase internal counter, and subscription * will be cancelled when this counter returns back to 0. * * @param channel Notification channel to subscribe to. * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void subscribe(String channel) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_CHANGE_SUBSCRIPTION); msg.setField(NXCPCodes.VID_NAME, channel); msg.setFieldInt16(NXCPCodes.VID_OPERATION, 1); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Unsubscribe from notification channel. * * @param channel Notification channel to unsubscribe from. * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void unsubscribe(String channel) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_CHANGE_SUBSCRIPTION); msg.setField(NXCPCodes.VID_NAME, channel); msg.setFieldInt16(NXCPCodes.VID_OPERATION, 0); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Synchronize user database and subscribe to user change notifications * * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncUserDatabase() throws IOException, NXCException { syncUserDB.acquireUninterruptibly(); NXCPMessage msg = newMessage(NXCPCodes.CMD_LOAD_USER_DB); sendMessage(msg); waitForRCC(msg.getMessageId()); waitForSync(syncUserDB, commandTimeout * 10); userDatabaseSynchronized = true; subscribe(CHANNEL_USERDB); } /** * Subscribe to user change notifications * * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void subscribeToUserDBUpdates() throws IOException, NXCException { subscribe(CHANNEL_USERDB); } /** * Synchronize users by id if does not exist * * @param users list of user id's to synchronize * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncUserSet(Set users) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_SELECTED_USERS); msg.setFieldInt32(NXCPCodes.VID_NUM_OBJECTS, users.size()); msg.setField(NXCPCodes.VID_OBJECT_LIST, users); sendMessage(msg); // First request completion message will indicate successful sync start waitForRCC(msg.getMessageId()); // Server will send second completion message when all user database objects were sent back waitForRCC(msg.getMessageId()); // Check that each user from set was synchronized and add update missing list synchronized(userDatabase) { for(Long id : users) { if (userDatabase.containsKey(id)) missingUsers.remove(id); else missingUsers.add(id); } } } /** * Synchronize only objects that were not yet synchronized * * @param users set of user IDs to sync * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out * @return true if synchronization was completed and false if synchronization is not needed */ public boolean syncMissingUsers(Set users) throws IOException, NXCException { if (userDatabaseSynchronized) return false; final Set syncSet = new HashSet(); synchronized(userDatabase) { for(Long id : users) { if (!userDatabase.containsKey(id)) syncSet.add(id); } } if (!syncSet.isEmpty()) syncUserSet(syncSet); return !syncSet.isEmpty(); } /** * Check if user database is synchronized with client * * @return true if user database is synchronized with client */ public boolean isUserDatabaseSynchronized() { return userDatabaseSynchronized; } /** * Find multiple users by list of IDs * * @param ids of user DBObjects to find * @return list of found users */ public List findUserDBObjectsByIds(final Collection ids) { List users = new ArrayList(); synchronized(userDatabase) { for(Long l : ids) { AbstractUserObject user = userDatabase.get(l); if (user != null) users.add(user); } } return users; } /** * Find user or group by ID. If full user database synchronization was not done this method may return null for existing user * that is not yet synchronized with the client. In such case client library will initiate background synchronization of that * user object. If provided callback is not null it will be executed when synchronization is complete. * * @param id The user database object ID * @param callback synchronization completion callback (may be null) * @return User object with given ID or null if such user does not exist or not synchronized with client. */ public AbstractUserObject findUserDBObjectById(final long id, Runnable callback) { AbstractUserObject object = null; boolean needSync = false; synchronized(userDatabase) { object = userDatabase.get(id); if ((object == null) && !userDatabaseSynchronized && !missingUsers.contains(id)) needSync = true; } if (needSync) { synchronized(userSyncList) { userSyncList.add(id); if (callback != null) callbackList.add(callback); userSyncList.notifyAll(); } } return object; } /** * Find user or group by GUID * * @param guid The user DBObject GUID * @return User object with given GUID or null if such user does not exist */ public AbstractUserObject findUserDBObjectByGUID(final UUID guid) { synchronized(userDatabase) { return userDatabaseGUID.get(guid); } } /** * Get list of all user database objects * * @return List of all user database objects */ public AbstractUserObject[] getUserDatabaseObjects() { AbstractUserObject[] list; synchronized(userDatabase) { Collection values = userDatabase.values(); list = values.toArray(new AbstractUserObject[values.size()]); } return list; } /** * Create user or group on server * * @param name Login name for new user * @return ID assigned to newly created user * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ private long createUserDBObject(final String name, final boolean isGroup) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_CREATE_USER); msg.setField(NXCPCodes.VID_USER_NAME, name); msg.setField(NXCPCodes.VID_IS_GROUP, isGroup); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsInt64(NXCPCodes.VID_USER_ID); } /** * Create user on server * * @param name Login name for new user * @return ID assigned to newly created user * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long createUser(final String name) throws IOException, NXCException { return createUserDBObject(name, false); } /** * Create user group on server * * @param name Name for new user group * @return ID assigned to newly created user group * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long createUserGroup(final String name) throws IOException, NXCException { return createUserDBObject(name, true); } /** * Delete user or group on server * * @param id User or group ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteUserDBObject(final long id) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_USER); msg.setFieldInt32(NXCPCodes.VID_USER_ID, (int)id); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Set password for user * * @param id User ID * @param newPassword New password * @param oldPassword Old password * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setUserPassword(final long id, final String newPassword, final String oldPassword) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_PASSWORD); msg.setFieldInt32(NXCPCodes.VID_USER_ID, (int)id); msg.setField(NXCPCodes.VID_PASSWORD, newPassword); if (oldPassword != null) msg.setField(NXCPCodes.VID_OLD_PASSWORD, oldPassword); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Validate password for currently logged in user * * @param password password to validate * @return true if password is valid * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public boolean validateUserPassword(String password) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_VALIDATE_PASSWORD); msg.setField(NXCPCodes.VID_PASSWORD, password); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsBoolean(NXCPCodes.VID_PASSWORD_IS_VALID); } /** * Modify user database object * * @param object User data * @param fields bit mask indicating fields to modify * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void modifyUserDBObject(final AbstractUserObject object, final int fields) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_USER); msg.setFieldInt32(NXCPCodes.VID_FIELDS, fields); object.fillMessage(msg); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Modify user database object * * @param object User data * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void modifyUserDBObject(final AbstractUserObject object) throws IOException, NXCException { modifyUserDBObject(object, 0x7FFFFFFF); } /** * Detach user from LDAP * * @param userId user ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void detachUserFromLdap(long userId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DETACH_LDAP_USER); msg.setFieldInt32(NXCPCodes.VID_USER_ID, (int)userId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Set custom attribute for currently logged in user. Server will allow to change * only attributes whose name starts with dot. * * @param name Attribute's name * @param value New attribute's value * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setAttributeForCurrentUser(final String name, final String value) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_CURRENT_USER_ATTR); msg.setField(NXCPCodes.VID_NAME, name); msg.setField(NXCPCodes.VID_VALUE, value); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get custom attribute for currently logged in user. If attribute is not set, empty string will * be returned. * * @param name Attribute's name * @return Attribute's value * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String getAttributeForCurrentUser(final String name) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_CURRENT_USER_ATTR); msg.setField(NXCPCodes.VID_NAME, name); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsString(NXCPCodes.VID_VALUE); } /** * Find all DCIs matching given creteria. * * @param objectId if specific object needed (set to 0 if match by object name is needed) * @param objectName regular expression to match object name (not used if object ID is not 0) * @param dciName regular expression to match DCI name * @param flags find flags * @return list of all found DCIs and their last values * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List findMatchingDCI(long objectId, String objectName, String dciName, int flags) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_MATCHING_DCI); if (objectId != 0) msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); else msg.setField(NXCPCodes.VID_OBJECT_NAME, objectName); msg.setField(NXCPCodes.VID_DCI_NAME, dciName); msg.setFieldInt32(NXCPCodes.VID_FLAGS, flags); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ITEMS); List result = new ArrayList(count); Long base = NXCPCodes.VID_DCI_VALUES_BASE; for(int i = 0; i < count; i++, base += 50) { result.add(new SimpleDciValue(response, base)); } return result; } /** * Get last DCI values for given node * * @param nodeId ID of the node to get DCI values for * @param objectTooltipOnly if set to true, only DCIs with DCF_SHOW_ON_OBJECT_TOOLTIP flag set are returned * @param overviewOnly if set to true, only DCIs with DCF_SHOW_IN_OBJECT_OVERVIEW flag set are returned * @param includeNoValueObjects if set to true, objects with no value (like instance discovery DCIs) will be returned as well * @return List of DCI values * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DciValue[] getLastValues(final long nodeId, boolean objectTooltipOnly, boolean overviewOnly, boolean includeNoValueObjects) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_LAST_VALUES); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setField(NXCPCodes.VID_OBJECT_TOOLTIP_ONLY, objectTooltipOnly); msg.setField(NXCPCodes.VID_OVERVIEW_ONLY, overviewOnly); msg.setField(NXCPCodes.VID_INCLUDE_NOVALUE_OBJECTS, includeNoValueObjects); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ITEMS); DciValue[] list = new DciValue[count]; long base = NXCPCodes.VID_DCI_VALUES_BASE; for(int i = 0; i < count; i++, base += 50) { list[i] = DciValue.createFromMessage(response, base); } return list; } /** * Get last DCI values for given node * * @param nodeId ID of the node to get DCI values for * @return List of DCI values * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DciValue[] getLastValues(final long nodeId) throws IOException, NXCException { return getLastValues(nodeId, false, false, false); } /** * Get tooltip last values for all objects * * @param nodeList list of node IDs * @return map with node id to DCI last values * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map getTooltipLastValues(Set nodeList) throws IOException, NXCException { Map cachedDciValues = new HashMap(); final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_TOOLTIP_LAST_VALUES); msg.setField(NXCPCodes.VID_OBJECT_LIST, nodeList.toArray(new Long[nodeList.size()])); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ITEMS); long base = NXCPCodes.VID_DCI_VALUES_BASE; List values = null; Long nodeId = 0L; for (int i = 0; i < count; i++, base += 50) { DciValue v = (DciValue)new SimpleDciValue(response, base); if(nodeId != v.getNodeId()) { if (nodeId != 0) { cachedDciValues.put(nodeId, values.toArray(new DciValue[values.size()])); } values = new ArrayList(); nodeId = v.getNodeId(); } values.add(v); } if (nodeId != 0) { cachedDciValues.put(nodeId, values.toArray(new DciValue[values.size()])); } return cachedDciValues; } /** * Get last DCI values for given Map DCI Instance list * * @param mapDcis List with Map DCI Instances * @return List of DCI values * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DciValue[] getLastValues(Set mapDcis) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_DCI_VALUES); long base = NXCPCodes.VID_DCI_VALUES_BASE; msg.setFieldInt32(NXCPCodes.VID_NUM_ITEMS, mapDcis.size()); for(MapDCIInstance item : mapDcis) { item.fillMessage(msg, base); base += 10; } return doLastValuesRequest(msg); } /** * Get last DCI values for given Single Dci Config list * * @param dciConfig List with Single Dci Configs * @return List of DCI values * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DciValue[] getLastValues(List dciConfig) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_DCI_VALUES); long base = NXCPCodes.VID_DCI_VALUES_BASE; msg.setFieldInt32(NXCPCodes.VID_NUM_ITEMS, dciConfig.size()); for(SingleDciConfig c : dciConfig) { c.fillMessage(msg, base); base += 10; } return doLastValuesRequest(msg); } /** * Send request for last values using prepared message * * @param msg NXCP message to send * @return The DCI values * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ private DciValue[] doLastValuesRequest(NXCPMessage msg) throws IOException, NXCException { sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ITEMS); DciValue[] list = new DciValue[count]; long fieldId = NXCPCodes.VID_DCI_VALUES_BASE; for(int i = 0; i < count; i++, fieldId += 50) { list[i] = (DciValue)new SimpleDciValue(response, fieldId); } return list; } /** * Get active thresholds * * @param dciConfig Dci config * @return list of active thresholds * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getActiveThresholds(List dciConfig) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ACTIVE_THRESHOLDS); long base = NXCPCodes.VID_DCI_VALUES_BASE; msg.setFieldInt32(NXCPCodes.VID_NUM_ITEMS, dciConfig.size()); for(SingleDciConfig c : dciConfig) { c.fillMessage(msg, base); base += 10; } sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_THRESHOLDS); List list = new ArrayList(count); base = NXCPCodes.VID_DCI_THRESHOLD_BASE; for(int i = 0; i < count; i++, base += 20) { list.add(new Threshold(response, base)); } return list; } /** * Get last value for given table DCI on given node * * @param nodeId ID of the node to get DCI values for * @param dciId DCI ID * @return Table object with last values for table DCI * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Table getTableLastValues(final long nodeId, final long dciId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_TABLE_LAST_VALUE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt32(NXCPCodes.VID_DCI_ID, (int)dciId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return new Table(response); } /** * Get last value for given table or single valued DCI on given node * * @param nodeId ID of the node to get DCI values for * @param dciId DCI ID * @return Last value object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DciLastValue getDciLastValue(final long nodeId, final long dciId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_DCI_LAST_VALUE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt32(NXCPCodes.VID_DCI_ID, (int)dciId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return new DciLastValue(response); } /** * Get list of DCIs configured to be shown on performance tab in console for given node. * * @param nodeId Node object ID * @return List of performance tab DCIs * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getPerfTabItems(final long nodeId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_PERFTAB_DCI_LIST); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ITEMS); List list = new ArrayList(count); long baseId = NXCPCodes.VID_SYSDCI_LIST_BASE; for(int i = 0; i < count; i++, baseId += 50) list.add(new PerfTabDci(response, baseId, nodeId)); return list; } /** * Get threshold violation summary for all nodes under given parent object. Parent object could * be container, subnet, zone, entire network, or infrastructure service root. * * @param objectId parent object ID * @return list of threshold violation summary objects for all nodes below given root * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getThresholdSummary(final long objectId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_THRESHOLD_SUMMARY); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); List list = new ArrayList(); long varId = NXCPCodes.VID_THRESHOLD_BASE; while(response.getFieldAsInt64(varId) != 0) { final ThresholdViolationSummary t = new ThresholdViolationSummary(response, varId); list.add(t); varId += 50 * t.getDciList().size() + 2; } return list; } /** * Parse data from raw message CMD_DCI_DATA. * This method is intended for calling by client internal methods only. It made public to * allow access from client extensions. * * @param input Raw data * @param data Data object to add rows to * @return number of received data rows */ public int parseDataRows(final byte[] input, DciData data) { final NXCPDataInputStream inputStream = new NXCPDataInputStream(input); int rows = 0; DciDataRow row = null; try { inputStream.skipBytes(4); // DCI ID rows = inputStream.readInt(); final DataType dataType = DataType.getByValue(inputStream.readInt()); data.setDataType(dataType); inputStream.skipBytes(4); // padding for(int i = 0; i < rows; i++) { long timestamp = inputStream.readUnsignedInt() * 1000; // convert to milliseconds Object value; switch(dataType) { case INT32: value = Long.valueOf(inputStream.readInt()); break; case UINT32: case COUNTER32: value = Long.valueOf(inputStream.readUnsignedInt()); break; case INT64: case UINT64: case COUNTER64: inputStream.skipBytes(4); // padding value = Long.valueOf(inputStream.readLong()); break; case FLOAT: inputStream.skipBytes(4); // padding value = Double.valueOf(inputStream.readDouble()); break; case STRING: StringBuilder sb = new StringBuilder(256); int count; for(count = MAX_DCI_STRING_VALUE_LENGTH; count > 0; count--) { char ch = inputStream.readChar(); if (ch == 0) { count--; break; } sb.append(ch); } inputStream.skipBytes(count * 2); value = sb.toString(); break; default: value = null; break; } if (timestamp > 0) { row = new DciDataRow(new Date(timestamp), value); data.addDataRow(row); } else { // raw value for previous entry if (row != null) row.setRawValue(value); } } } catch(IOException e) { } inputStream.close(); return rows; } /** * Get collected DCI data from server. Please note that you should specify * either row count limit or time from/to limit. * * @param nodeId Node ID * @param dciId DCI ID * @param instance instance value (for table DCI only) * @param dataColumn name of column to retrieve data from (for table DCI only) * @param from Start of time range or null for no limit * @param to End of time range or null for no limit * @param maxRows Maximum number of rows to retrieve or 0 for no limit * @param valueType TODO * @return DCI data set * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ private DciData getCollectedDataInternal(long nodeId, long dciId, String instance, String dataColumn, Date from, Date to, int maxRows, HistoricalDataType valueType) throws IOException, NXCException { NXCPMessage msg; if (instance != null) // table DCI { msg = newMessage(NXCPCodes.CMD_GET_TABLE_DCI_DATA); msg.setField(NXCPCodes.VID_INSTANCE, instance); msg.setField(NXCPCodes.VID_DATA_COLUMN, dataColumn); } else { msg = newMessage((valueType == HistoricalDataType.FULL_TABLE) ? NXCPCodes.CMD_GET_TABLE_DCI_DATA : NXCPCodes.CMD_GET_DCI_DATA); } msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt32(NXCPCodes.VID_DCI_ID, (int)dciId); msg.setFieldInt16(NXCPCodes.VID_HISTORICAL_DATA_TYPE, valueType.getValue()); DciData data = new DciData(nodeId, dciId); int timeFrom = (from != null) ? (int)(from.getTime() / 1000) : 0; int timeTo = (to != null) ? (int)(to.getTime() / 1000) : 0; // If full table values are requested, each value will be sent in separate message if (valueType == HistoricalDataType.FULL_TABLE) { msg.setFieldInt32(NXCPCodes.VID_MAX_ROWS, maxRows); msg.setFieldInt32(NXCPCodes.VID_TIME_FROM, timeFrom); msg.setFieldInt32(NXCPCodes.VID_TIME_TO, timeTo); sendMessage(msg); waitForRCC(msg.getMessageId()); while(true) { NXCPMessage response = waitForMessage(NXCPCodes.CMD_DCI_DATA, msg.getMessageId()); long timestamp = response.getFieldAsInt64(NXCPCodes.VID_TIMESTAMP) * 1000L; // Convert to milliseconds if (timestamp == 0) break; // End of value list indicator data.addDataRow(new DciDataRow(new Date(timestamp), new Table(response))); } } else { int rowsReceived, rowsRemaining = maxRows; do { msg.setMessageId(requestId.getAndIncrement()); msg.setFieldInt32(NXCPCodes.VID_MAX_ROWS, maxRows); msg.setFieldInt32(NXCPCodes.VID_TIME_FROM, timeFrom); msg.setFieldInt32(NXCPCodes.VID_TIME_TO, timeTo); sendMessage(msg); waitForRCC(msg.getMessageId()); NXCPMessage response = waitForMessage(NXCPCodes.CMD_DCI_DATA, msg.getMessageId()); if (!response.isBinaryMessage()) throw new NXCException(RCC.INTERNAL_ERROR); rowsReceived = parseDataRows(response.getBinaryData(), data); if (((rowsRemaining == 0) || (rowsRemaining > MAX_DCI_DATA_ROWS)) && (rowsReceived == MAX_DCI_DATA_ROWS)) { // adjust boundaries for next request if (rowsRemaining > 0) rowsRemaining -= rowsReceived; // Rows goes in newest to oldest order, so if we need to // retrieve additional data, we should update timeTo limit if (to != null) { DciDataRow row = data.getLastValue(); if (row != null) { // There should be only one value per second, so we set // last row's timestamp - 1 second as new boundary timeTo = (int)(row.getTimestamp().getTime() / 1000) - 1; } } } } while(rowsReceived == MAX_DCI_DATA_ROWS); } return data; } /** * Get collected DCI data from server. Please note that you should specify * either row count limit or time from/to limit. * * @param nodeId Node ID * @param dciId DCI ID * @param from Start of time range or null for no limit * @param to End of time range or null for no limit * @param maxRows Maximum number of rows to retrieve or 0 for no limit * @param valueType TODO * @return DCI data set * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DciData getCollectedData(long nodeId, long dciId, Date from, Date to, int maxRows, HistoricalDataType valueType) throws IOException, NXCException { return getCollectedDataInternal(nodeId, dciId, null, null, from, to, maxRows, valueType); } /** * Get collected table DCI data from server. Please note that you should specify * either row count limit or time from/to limit. * * @param nodeId Node ID * @param dciId DCI ID * @param instance instance value * @param dataColumn name of column to retrieve data from * @param from Start of time range or null for no limit * @param to End of time range or null for no limit * @param maxRows Maximum number of rows to retrieve or 0 for no limit * @return DCI data set * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DciData getCollectedTableData(long nodeId, long dciId, String instance, String dataColumn, Date from, Date to, int maxRows) throws IOException, NXCException { if (instance == null || dataColumn == null) throw new NXCException(RCC.INVALID_ARGUMENT); return getCollectedDataInternal(nodeId, dciId, instance, dataColumn, from, to, maxRows, HistoricalDataType.PROCESSED); } /** * Clear collected data for given DCI * * @param nodeId Node object ID * @param dciId DCI ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void clearCollectedData(long nodeId, long dciId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_CLEAR_DCI_DATA); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt32(NXCPCodes.VID_DCI_ID, (int)dciId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Delete collected data entry for given DCI * * @param nodeId Node object ID * @param dciId DCI ID * @param timestamp timestamp of entry * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteDciEntry(long nodeId, long dciId, long timestamp) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_DCI_ENTRY); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt32(NXCPCodes.VID_DCI_ID, (int)dciId); msg.setFieldInt32(NXCPCodes.VID_TIMESTAMP, (int)timestamp); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Start recalculation of DCI values using preserver raw values. * * @param objectId object ID * @param dciId DCI ID * @return assigned job ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long recalculateDCIValues(long objectId, long dciId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_RECALCULATE_DCI_VALUES); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setFieldInt32(NXCPCodes.VID_DCI_ID, (int)dciId); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsInt64(NXCPCodes.VID_JOB_ID); } /** * Force DCI poll for given DCI * * @param nodeId Node object ID * @param dciId DCI ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void forceDCIPoll(long nodeId, long dciId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_FORCE_DCI_POLL); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt32(NXCPCodes.VID_DCI_ID, (int)dciId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get list of thresholds configured for given DCI * * @param nodeId Node object ID * @param dciId DCI ID * @return List of configured thresholds * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Threshold[] getThresholds(final long nodeId, final long dciId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_DCI_THRESHOLDS); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt32(NXCPCodes.VID_DCI_ID, (int)dciId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_THRESHOLDS); final Threshold[] list = new Threshold[count]; long fieldId = NXCPCodes.VID_DCI_THRESHOLD_BASE; for(int i = 0; i < count; i++) { list[i] = new Threshold(response, fieldId); fieldId += 20; } return list; } /** * Get names for given DCI list * * @param nodeIds node identifiers * @param dciIds DCI identifiers (length must match length of node identifiers list) * @return array of resolved DCI names * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map dciIdsToNames(List nodeIds, List dciIds) throws IOException, NXCException { if (nodeIds.isEmpty()) return new HashMap(); final NXCPMessage msg = newMessage(NXCPCodes.CMD_RESOLVE_DCI_NAMES); msg.setFieldInt32(NXCPCodes.VID_NUM_ITEMS, nodeIds.size()); msg.setField(NXCPCodes.VID_NODE_LIST, nodeIds); msg.setField(NXCPCodes.VID_DCI_LIST, dciIds); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); Map result = new HashMap(); int size = response.getFieldAsInt32(NXCPCodes.VID_NUM_ITEMS); long fieldId = NXCPCodes.VID_DCI_LIST_BASE; for(int i = 0; i < size; i++) { result.put(response.getFieldAsInt64(fieldId), new DciInfo(response.getFieldAsString(fieldId + 1), response.getFieldAsString(fieldId + 2))); fieldId += 3; } return result; } /** * Get names for given DCI list * * @param itemList list of items to resolved * @return map of DCI id to DCI description * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map dciIdsToNames(Collection itemList) throws IOException, NXCException { if (itemList.isEmpty()) return new HashMap(); List nodeIds = new ArrayList(); List dciIds = new ArrayList(); for(NodeItemPair nodeItem : itemList) { if (nodeItem.getNodeId() != 0 && nodeItem.getDciId() != 0) { nodeIds.add(nodeItem.getNodeId()); dciIds.add(nodeItem.getDciId()); } } return dciIdsToNames(nodeIds, dciIds); } /** * Get DCI ID for given DCI name * * @param nodeId node object identifier * @param dciName DCI name * @return id of DCI with given name * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long dciNameToId(long nodeId, String dciName) throws IOException, NXCException { if (nodeId == 0 || dciName == null || dciName.isEmpty()) return 0; DciValue[] list = getLastValues(nodeId); for(DciValue dciValue : list) { if (dciValue.getName().equals(dciName)) return dciValue.getId(); } return 0; } /** * Query parameter immediately. This call will cause server to do actual call * to managed node and will return current value for given parameter. Result * is not cached. * * @param nodeId node object ID * @param origin parameter's origin (NetXMS agent, SNMP, etc.) * @param name parameter's name * @return current parameter's value * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String queryParameter(long nodeId, DataOrigin origin, String name) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_QUERY_PARAMETER); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt16(NXCPCodes.VID_DCI_SOURCE_TYPE, origin.getValue()); msg.setField(NXCPCodes.VID_NAME, name); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsString(NXCPCodes.VID_VALUE); } /** * Query agent's table immediately. This call will cause server to do actual * call to managed node and will return current value for given table. Result * is not cached. * * @param nodeId node object ID * @param name table's name * @return current table's value * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Table queryAgentTable(long nodeId, String name) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_QUERY_TABLE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setField(NXCPCodes.VID_NAME, name); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return new Table(response); } /** * Hook method to allow adding of custom object creation data to NXCP message. * Default implementation does nothing. * * @param data object creation data passed to createObject * @param userData user-defined data for object creation passed to createObject * @param msg NXCP message that will be sent to server */ protected void createCustomObject(NXCObjectCreationData data, Object userData, NXCPMessage msg) { } /** * Create new NetXMS object. * * @param data Object creation data * @param userData User-defined data for custom object creation * @return ID of new object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long createObject(final NXCObjectCreationData data, final Object userData) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_CREATE_OBJECT); // Common attributes msg.setFieldInt32(NXCPCodes.VID_PARENT_ID, (int)data.getParentId()); msg.setFieldInt16(NXCPCodes.VID_OBJECT_CLASS, data.getObjectClass()); msg.setField(NXCPCodes.VID_OBJECT_NAME, data.getName()); if ((data.getObjectAlias() != null) && !data.getObjectAlias().isEmpty()) msg.setField(NXCPCodes.VID_ALIAS, data.getObjectAlias()); msg.setFieldInt32(NXCPCodes.VID_ZONE_UIN, data.getZoneUIN()); msg.setFieldInt32(NXCPCodes.VID_ASSET_ID, (int)data.getAssetId()); if (data.getComments() != null) msg.setField(NXCPCodes.VID_COMMENTS, data.getComments()); // Class-specific attributes switch(data.getObjectClass()) { case AbstractObject.OBJECT_ASSET: if (data.getAssetProperties() != null) msg.setFieldsFromStringMap(data.getAssetProperties(), NXCPCodes.VID_ASSET_PROPERTIES_BASE, NXCPCodes.VID_NUM_ASSET_PROPERTIES); break; case AbstractObject.OBJECT_CHASSIS: msg.setFieldInt32(NXCPCodes.VID_CONTROLLER_ID, (int)data.getControllerId()); break; case AbstractObject.OBJECT_INTERFACE: msg.setField(NXCPCodes.VID_MAC_ADDR, data.getMacAddress().getValue()); msg.setField(NXCPCodes.VID_IP_ADDRESS, data.getIpAddress()); msg.setFieldInt32(NXCPCodes.VID_IF_TYPE, data.getIfType()); msg.setFieldInt32(NXCPCodes.VID_IF_INDEX, data.getIfIndex()); msg.setFieldInt32(NXCPCodes.VID_PHY_CHASSIS, data.getChassis()); msg.setFieldInt32(NXCPCodes.VID_PHY_MODULE, data.getModule()); msg.setFieldInt32(NXCPCodes.VID_PHY_PIC, data.getPIC()); msg.setFieldInt32(NXCPCodes.VID_PHY_PORT, data.getPort()); msg.setFieldInt16(NXCPCodes.VID_IS_PHYS_PORT, data.isPhysicalPort() ? 1 : 0); break; case AbstractObject.OBJECT_MOBILEDEVICE: msg.setField(NXCPCodes.VID_DEVICE_ID, data.getDeviceId()); break; case AbstractObject.OBJECT_NODE: if (data.getPrimaryName() != null) msg.setField(NXCPCodes.VID_PRIMARY_NAME, data.getPrimaryName()); msg.setField(NXCPCodes.VID_IP_ADDRESS, data.getIpAddress()); msg.setFieldInt16(NXCPCodes.VID_AGENT_PORT, data.getAgentPort()); msg.setFieldInt16(NXCPCodes.VID_SNMP_PORT, data.getSnmpPort()); msg.setFieldInt16(NXCPCodes.VID_ETHERNET_IP_PORT, data.getEtherNetIpPort()); msg.setFieldInt16(NXCPCodes.VID_MODBUS_TCP_PORT, data.getModbusTcpPort()); msg.setFieldInt16(NXCPCodes.VID_MODBUS_UNIT_ID, data.getModbusUnitId()); msg.setFieldInt16(NXCPCodes.VID_SSH_PORT, data.getSshPort()); msg.setFieldInt32(NXCPCodes.VID_CREATION_FLAGS, data.getCreationFlags()); msg.setFieldInt32(NXCPCodes.VID_AGENT_PROXY, (int)data.getAgentProxyId()); msg.setFieldInt32(NXCPCodes.VID_SNMP_PROXY, (int)data.getSnmpProxyId()); msg.setFieldInt32(NXCPCodes.VID_MQTT_PROXY, (int)data.getMqttProxyId()); msg.setFieldInt32(NXCPCodes.VID_ETHERNET_IP_PROXY, (int)data.getEtherNetIpProxyId()); msg.setFieldInt32(NXCPCodes.VID_MODBUS_PROXY, (int)data.getModbusProxyId()); msg.setFieldInt32(NXCPCodes.VID_ICMP_PROXY, (int)data.getIcmpProxyId()); msg.setFieldInt32(NXCPCodes.VID_SSH_PROXY, (int)data.getSshProxyId()); msg.setField(NXCPCodes.VID_SSH_LOGIN, data.getSshLogin()); msg.setField(NXCPCodes.VID_SSH_PASSWORD, data.getSshPassword()); msg.setFieldInt32(NXCPCodes.VID_WEB_SERVICE_PROXY, (int)data.getWebServiceProxyId()); break; case AbstractObject.OBJECT_NETWORKMAP: msg.setFieldInt16(NXCPCodes.VID_MAP_TYPE, data.getMapType()); msg.setField(NXCPCodes.VID_SEED_OBJECTS, data.getSeedObjectIds()); msg.setFieldInt32(NXCPCodes.VID_FLAGS, (int)data.getFlags()); break; case AbstractObject.OBJECT_NETWORKSERVICE: msg.setFieldInt16(NXCPCodes.VID_SERVICE_TYPE, data.getServiceType()); msg.setFieldInt16(NXCPCodes.VID_IP_PROTO, data.getIpProtocol()); msg.setFieldInt16(NXCPCodes.VID_IP_PORT, data.getIpPort()); msg.setField(NXCPCodes.VID_SERVICE_REQUEST, data.getRequest()); msg.setField(NXCPCodes.VID_SERVICE_RESPONSE, data.getResponse()); msg.setFieldInt16(NXCPCodes.VID_CREATE_STATUS_DCI, data.isCreateStatusDci() ? 1 : 0); break; case AbstractObject.OBJECT_RACK: msg.setFieldInt16(NXCPCodes.VID_HEIGHT, data.getHeight()); break; case AbstractObject.OBJECT_SENSOR: msg.setFieldInt32(NXCPCodes.VID_SENSOR_FLAGS, data.getFlags()); msg.setField(NXCPCodes.VID_MAC_ADDR, data.getMacAddress()); msg.setFieldInt32(NXCPCodes.VID_DEVICE_CLASS, data.getDeviceClass()); msg.setField(NXCPCodes.VID_VENDOR, data.getVendor()); msg.setFieldInt32(NXCPCodes.VID_COMM_PROTOCOL, data.getCommProtocol()); msg.setField(NXCPCodes.VID_XML_CONFIG, data.getXmlConfig()); msg.setField(NXCPCodes.VID_XML_REG_CONFIG, data.getXmlRegConfig()); msg.setField(NXCPCodes.VID_SERIAL_NUMBER, data.getSerialNumber()); msg.setField(NXCPCodes.VID_DEVICE_ADDRESS, data.getDeviceAddress()); msg.setField(NXCPCodes.VID_META_TYPE, data.getMetaType()); msg.setField(NXCPCodes.VID_DESCRIPTION, data.getDescription()); msg.setFieldInt32(NXCPCodes.VID_SENSOR_PROXY, (int)data.getSensorProxy()); break; case AbstractObject.OBJECT_SUBNET: msg.setField(NXCPCodes.VID_IP_ADDRESS, data.getIpAddress()); break; case AbstractObject.OBJECT_BUSINESSSERVICEPROTOTYPE: msg.setFieldInt16(NXCPCodes.VID_INSTD_METHOD, data.getInstanceDiscoveryMethod()); break; } if (userData != null) createCustomObject(data, userData, msg); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsInt64(NXCPCodes.VID_OBJECT_ID); } /** * Create new NetXMS object. Equivalent of calling createObject(data, null). * * @param data Object creation data * @return ID of new object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long createObject(final NXCObjectCreationData data) throws IOException, NXCException { return createObject(data, null); } /** * Create new NetXMS object in synchronous mode. * * @param data Object creation data * @return newly created AbstractObject * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public AbstractObject createObjectSync(final NXCObjectCreationData data) throws IOException, NXCException { long id = createObject(data, null); FutureObject object = findFutureObjectById(id); synchronized (object) { while (!object.hasObject()) { try { object.wait(); } catch(InterruptedException e) { } } } return object.getObject(); } /** * Create new NetXMS object and run callback once it's created. * * @param data Object creation data * @param callback callback to run on object creation * @return ID of new object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long createObjectAsync(final NXCObjectCreationData data, ObjectCreationListener callback) throws IOException, NXCException { long id = createObject(data, null); findObjectAsync(id, callback); return id; } /** * Delete object * * @param objectId ID of an object which should be deleted * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteObject(final long objectId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_OBJECT); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); sendMessage(msg); waitForRCC(msg.getMessageId()); // If server reports success, delete object from cache and generate // appropriate notification without waiting for actual server update synchronized(objectList) { AbstractObject object = objectList.get(objectId); if (object != null) { objectList.remove(objectId); objectListGUID.remove(object.getGuid()); if (object instanceof Zone) zoneList.remove(((Zone)object).getUIN()); removeOrphanedObjects(object); } } sendNotification(new SessionNotification(SessionNotification.OBJECT_DELETED, objectId)); } /** * Remove orphaned objects (with last parent left) * * @param parent */ private void removeOrphanedObjects(AbstractObject parent) { Iterator it = parent.getChildren(); while(it.hasNext()) { AbstractObject object = objectList.get(it.next()); if ((object != null) && (object.getParentCount() == 1)) { objectList.remove(object.getObjectId()); objectListGUID.remove(object.getGuid()); if (object instanceof Zone) zoneList.remove(((Zone)object).getUIN()); removeOrphanedObjects(object); } } } /** * Hook method to populate NXCP message with custom object's data on object modification. * Default implementation does nothing. * * @param data object modification data passed to modifyObject * @param userData user-defined data passed to modifyObject * @param msg NXCP message to be sent to server */ protected void modifyCustomObject(NXCObjectModificationData data, Object userData, NXCPMessage msg) { } /** * Modify object (generic interface, in most cases wrapper functions should * be used instead). * * @param data Object modification data * @param userData user-defined data for custom object modification * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void modifyObject(final NXCObjectModificationData data, final Object userData) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_MODIFY_OBJECT); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)data.getObjectId()); // Object name if (data.getName() != null) { msg.setField(NXCPCodes.VID_OBJECT_NAME, data.getName()); } // Object alias if (data.getAlias() != null) { msg.setField(NXCPCodes.VID_ALIAS, data.getAlias()); } // Object name on network map if (data.getNameOnMap() != null) { msg.setField(NXCPCodes.VID_NAME_ON_MAP, data.getNameOnMap()); } // Primary IP if (data.getPrimaryIpAddress() != null) { msg.setField(NXCPCodes.VID_IP_ADDRESS, data.getPrimaryIpAddress()); } // Access control list if (data.getACL() != null) { if (data.isInheritAccessRights() == null) throw new IllegalArgumentException("Access control list should be set together with inherited access rights flag"); final Collection acl = data.getACL(); msg.setFieldInt32(NXCPCodes.VID_ACL_SIZE, acl.size()); msg.setFieldInt16(NXCPCodes.VID_INHERIT_RIGHTS, data.isInheritAccessRights() ? 1 : 0); long id1 = NXCPCodes.VID_ACL_USER_BASE; long id2 = NXCPCodes.VID_ACL_RIGHTS_BASE; for(AccessListElement e : acl) { msg.setFieldInt32(id1++, (int)e.getUserId()); msg.setFieldInt32(id2++, e.getAccessRights()); } } if (data.getCustomAttributes() != null) { Map attrList = data.getCustomAttributes(); Iterator it = attrList.keySet().iterator(); long id = NXCPCodes.VID_CUSTOM_ATTRIBUTES_BASE; int count = 0; while(it.hasNext()) { String key = it.next(); CustomAttribute attr = attrList.get(key); if (attr.getSourceObject() != 0 && !attr.isRedefined()) continue; msg.setField(id++, key); msg.setField(id++, attr.getValue()); msg.setFieldInt32(id++, (int)attr.getFlags()); count++; } msg.setFieldInt32(NXCPCodes.VID_NUM_CUSTOM_ATTRIBUTES, count); } if (data.getAutoBindFilter() != null) { msg.setField(NXCPCodes.VID_AUTOBIND_FILTER, data.getAutoBindFilter()); } if (data.getAutoBindFilter2() != null) { msg.setField(NXCPCodes.VID_AUTOBIND_FILTER_2, data.getAutoBindFilter2()); } if (data.getAutoBindFlags() != null) { msg.setFieldInt32(NXCPCodes.VID_AUTOBIND_FLAGS, data.getAutoBindFlags()); } if (data.getFilter() != null) { msg.setField(NXCPCodes.VID_FILTER, data.getFilter()); } if (data.getDescription() != null) { msg.setField(NXCPCodes.VID_DESCRIPTION, data.getDescription()); } if (data.getVersion() != null) { msg.setFieldInt32(NXCPCodes.VID_VERSION, data.getVersion()); } if (data.getAgentPort() != null) { msg.setFieldInt16(NXCPCodes.VID_AGENT_PORT, data.getAgentPort()); } if (data.getAgentProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_AGENT_PROXY, data.getAgentProxy().intValue()); } if (data.getAgentSecret() != null) { msg.setField(NXCPCodes.VID_SHARED_SECRET, data.getAgentSecret()); } if (data.getTrustedObjects() != null) { msg.setField(NXCPCodes.VID_TRUSTED_OBJECTS, data.getTrustedObjects()); } if (data.getSnmpVersion() != null) { msg.setFieldInt16(NXCPCodes.VID_SNMP_VERSION, data.getSnmpVersion().getValue()); } if (data.getSnmpAuthName() != null || data.getSnmpAuthPassword() != null || data.getSnmpPrivPassword() != null || data.getSnmpAuthMethod() != null || data.getSnmpPrivMethod() != null) { if (data.getSnmpAuthName() == null || data.getSnmpAuthPassword() == null || data.getSnmpPrivPassword() == null || data.getSnmpAuthMethod() == null || data.getSnmpPrivMethod() == null) throw new IllegalArgumentException("All SNMP fields should be set: auth name, auth password, priv password, auth method, priv method"); msg.setField(NXCPCodes.VID_SNMP_AUTH_OBJECT, data.getSnmpAuthName()); msg.setField(NXCPCodes.VID_SNMP_AUTH_PASSWORD, data.getSnmpAuthPassword()); msg.setField(NXCPCodes.VID_SNMP_PRIV_PASSWORD, data.getSnmpPrivPassword()); int methods = data.getSnmpAuthMethod() | (data.getSnmpPrivMethod() << 8); msg.setFieldInt16(NXCPCodes.VID_SNMP_USM_METHODS, methods); } if (data.getSnmpProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_SNMP_PROXY, data.getSnmpProxy().intValue()); } if (data.getSnmpPort() != null) { msg.setFieldInt16(NXCPCodes.VID_SNMP_PORT, data.getSnmpPort()); } if (data.getMqttProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_MQTT_PROXY, data.getMqttProxy().intValue()); } if (data.getIcmpProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_ICMP_PROXY, data.getIcmpProxy().intValue()); } if (data.getGeolocation() != null) { final GeoLocation gl = data.getGeolocation(); msg.setFieldInt16(NXCPCodes.VID_GEOLOCATION_TYPE, gl.getType()); msg.setField(NXCPCodes.VID_LATITUDE, gl.getLatitude()); msg.setField(NXCPCodes.VID_LONGITUDE, gl.getLongitude()); msg.setFieldInt16(NXCPCodes.VID_ACCURACY, gl.getAccuracy()); if (gl.getTimestamp() != null) { msg.setFieldInt64(NXCPCodes.VID_GEOLOCATION_TIMESTAMP, gl.getTimestamp().getTime() / 1000); } } if (data.getMapLayout() != null) { msg.setFieldInt16(NXCPCodes.VID_LAYOUT, data.getMapLayout().getValue()); } if (data.getMapBackground() != null || data.getMapBackgroundLocation() != null || data.getMapBackgroundZoom() != null || data.getMapBackgroundColor() != null) { if (data.getMapBackground() == null || data.getMapBackgroundLocation() == null || data.getMapBackgroundZoom() == null || data.getMapBackgroundColor() == null) throw new IllegalArgumentException("All map background attributes should be set (image ID, geolocation, zoom, and color)"); msg.setField(NXCPCodes.VID_BACKGROUND, data.getMapBackground()); msg.setField(NXCPCodes.VID_BACKGROUND_LATITUDE, data.getMapBackgroundLocation().getLatitude()); msg.setField(NXCPCodes.VID_BACKGROUND_LONGITUDE, data.getMapBackgroundLocation().getLongitude()); msg.setFieldInt16(NXCPCodes.VID_BACKGROUND_ZOOM, data.getMapBackgroundZoom()); msg.setFieldInt32(NXCPCodes.VID_BACKGROUND_COLOR, data.getMapBackgroundColor()); } if (data.getMapImage() != null) { msg.setField(NXCPCodes.VID_IMAGE, data.getMapImage()); } if (data.getMapElements() != null || data.getMapLinks() != null) { if (data.getMapElements() == null || data.getMapLinks() == null) throw new IllegalArgumentException("Both map elements and map links should be set"); msg.setFieldInt32(NXCPCodes.VID_NUM_ELEMENTS, data.getMapElements().size()); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(NetworkMapElement e : data.getMapElements()) { e.fillMessage(msg, fieldId); fieldId += 100; } msg.setFieldInt32(NXCPCodes.VID_NUM_LINKS, data.getMapLinks().size()); fieldId = NXCPCodes.VID_LINK_LIST_BASE; for(NetworkMapLink l : data.getMapLinks()) { l.fillMessage(msg, fieldId); fieldId += 20; } } if (data.getColumnCount() != null) { msg.setFieldInt16(NXCPCodes.VID_NUM_COLUMNS, data.getColumnCount()); } if (data.getDashboardElements() != null) { msg.setFieldInt32(NXCPCodes.VID_NUM_ELEMENTS, data.getDashboardElements().size()); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(DashboardElement e : data.getDashboardElements()) { e.fillMessage(msg, fieldId); fieldId += 10; } } if (data.getUrls() != null) { msg.setFieldInt32(NXCPCodes.VID_NUM_URLS, data.getUrls().size()); long fieldId = NXCPCodes.VID_URL_LIST_BASE; for(ObjectUrl u : data.getUrls()) { u.fillMessage(msg, fieldId); fieldId += 10; } } if (data.getScript() != null) { msg.setField(NXCPCodes.VID_SCRIPT, data.getScript()); } if (data.getActivationEvent() != null) { msg.setFieldInt32(NXCPCodes.VID_ACTIVATION_EVENT, data.getActivationEvent()); } if (data.getDeactivationEvent() != null) { msg.setFieldInt32(NXCPCodes.VID_DEACTIVATION_EVENT, data.getDeactivationEvent()); } if (data.getSourceObject() != null) { msg.setFieldInt32(NXCPCodes.VID_SOURCE_OBJECT, data.getSourceObject().intValue()); } if (data.getActiveStatus() != null) { msg.setFieldInt16(NXCPCodes.VID_ACTIVE_STATUS, data.getActiveStatus()); } if (data.getInactiveStatus() != null) { msg.setFieldInt16(NXCPCodes.VID_INACTIVE_STATUS, data.getInactiveStatus()); } if (data.getDciList() != null) { List dciList = data.getDciList(); msg.setFieldInt32(NXCPCodes.VID_NUM_ITEMS, dciList.size()); long varId = NXCPCodes.VID_DCI_LIST_BASE; for(ConditionDciInfo dci : dciList) { msg.setFieldInt32(varId++, (int)dci.getDciId()); msg.setFieldInt32(varId++, (int)dci.getNodeId()); msg.setFieldInt16(varId++, dci.getFunction()); msg.setFieldInt16(varId++, dci.getPolls()); varId += 6; } } if (data.getDrillDownObjectId() != null) { msg.setFieldInt32(NXCPCodes.VID_DRILL_DOWN_OBJECT_ID, data.getDrillDownObjectId().intValue()); } if (data.getServiceType() != null) { msg.setFieldInt16(NXCPCodes.VID_SERVICE_TYPE, data.getServiceType()); } if (data.getIpAddress() != null) { msg.setField(NXCPCodes.VID_IP_ADDRESS, data.getIpAddress()); } if (data.getIpProtocol() != null) { msg.setFieldInt16(NXCPCodes.VID_IP_PROTO, data.getIpProtocol()); } if (data.getIpPort() != null) { msg.setFieldInt16(NXCPCodes.VID_IP_PORT, data.getIpPort()); } if (data.getPollerNode() != null) { msg.setFieldInt32(NXCPCodes.VID_POLLER_NODE_ID, data.getPollerNode().intValue()); } if (data.getRequiredPolls() != null) { msg.setFieldInt16(NXCPCodes.VID_REQUIRED_POLLS, data.getRequiredPolls()); } if (data.getRequest() != null) { msg.setField(NXCPCodes.VID_SERVICE_REQUEST, data.getRequest()); } if (data.getResponse() != null) { msg.setField(NXCPCodes.VID_SERVICE_RESPONSE, data.getResponse()); } if (data.getObjectFlags() != null || data.getObjectFlagsMask() != null) { msg.setFieldInt32(NXCPCodes.VID_FLAGS, data.getObjectFlags()); if (data.getObjectFlagsMask() != null) msg.setFieldInt32(NXCPCodes.VID_FLAGS_MASK, data.getObjectFlagsMask()); } if (data.getIfXTablePolicy() != null) { msg.setFieldInt16(NXCPCodes.VID_USE_IFXTABLE, data.getIfXTablePolicy()); } if (data.getReportDefinition() != null) { msg.setField(NXCPCodes.VID_REPORT_DEFINITION, data.getReportDefinition()); } if (data.getResourceList() != null) { msg.setFieldInt32(NXCPCodes.VID_NUM_RESOURCES, data.getResourceList().size()); long varId = NXCPCodes.VID_RESOURCE_LIST_BASE; for(ClusterResource r : data.getResourceList()) { msg.setFieldInt32(varId++, (int)r.getId()); msg.setField(varId++, r.getName()); msg.setField(varId++, r.getVirtualAddress()); varId += 7; } } if (data.getNetworkList() != null) { int count = data.getNetworkList().size(); msg.setFieldInt32(NXCPCodes.VID_NUM_SYNC_SUBNETS, count); long varId = NXCPCodes.VID_SYNC_SUBNETS_BASE; for(InetAddressEx n : data.getNetworkList()) { msg.setField(varId++, n); } } if (data.getPrimaryName() != null) { msg.setField(NXCPCodes.VID_PRIMARY_NAME, data.getPrimaryName()); } if (data.getStatusCalculationMethod() != null || data.getStatusPropagationMethod() != null || data.getFixedPropagatedStatus() != null || data.getStatusShift() != null || data.getStatusTransformation() != null || data.getStatusSingleThreshold() != null || data.getStatusThresholds() != null) { msg.setFieldInt16(NXCPCodes.VID_STATUS_CALCULATION_ALG, data.getStatusCalculationMethod()); msg.setFieldInt16(NXCPCodes.VID_STATUS_PROPAGATION_ALG, data.getStatusPropagationMethod()); msg.setFieldInt16(NXCPCodes.VID_FIXED_STATUS, data.getFixedPropagatedStatus().getValue()); msg.setFieldInt16(NXCPCodes.VID_STATUS_SHIFT, data.getStatusShift()); ObjectStatus[] transformation = data.getStatusTransformation(); msg.setFieldInt16(NXCPCodes.VID_STATUS_TRANSLATION_1, transformation[0].getValue()); msg.setFieldInt16(NXCPCodes.VID_STATUS_TRANSLATION_2, transformation[1].getValue()); msg.setFieldInt16(NXCPCodes.VID_STATUS_TRANSLATION_3, transformation[2].getValue()); msg.setFieldInt16(NXCPCodes.VID_STATUS_TRANSLATION_4, transformation[3].getValue()); msg.setFieldInt16(NXCPCodes.VID_STATUS_SINGLE_THRESHOLD, data.getStatusSingleThreshold()); int[] thresholds = data.getStatusThresholds(); msg.setFieldInt16(NXCPCodes.VID_STATUS_THRESHOLD_1, thresholds[0]); msg.setFieldInt16(NXCPCodes.VID_STATUS_THRESHOLD_2, thresholds[1]); msg.setFieldInt16(NXCPCodes.VID_STATUS_THRESHOLD_3, thresholds[2]); msg.setFieldInt16(NXCPCodes.VID_STATUS_THRESHOLD_4, thresholds[3]); } if (data.getExpectedState() != null) { msg.setFieldInt16(NXCPCodes.VID_EXPECTED_STATE, data.getExpectedState()); } if (data.getLinkColor() != null) { msg.setFieldInt32(NXCPCodes.VID_LINK_COLOR, data.getLinkColor()); } if (data.getConnectionRouting() != null) { msg.setFieldInt16(NXCPCodes.VID_LINK_ROUTING, data.getConnectionRouting()); } if (data.getDiscoveryRadius() != null) { msg.setFieldInt32(NXCPCodes.VID_DISCOVERY_RADIUS, data.getDiscoveryRadius()); } if (data.getHeight() != null) { msg.setFieldInt16(NXCPCodes.VID_HEIGHT, data.getHeight()); } if (data.isRackNumberingTopBottom() != null) { msg.setField(NXCPCodes.VID_TOP_BOTTOM, data.isRackNumberingTopBottom()); } if (data.getPeerGatewayId() != null) { msg.setFieldInt32(NXCPCodes.VID_PEER_GATEWAY, data.getPeerGatewayId().intValue()); } if (data.getLocalNetworks() != null || data.getRemoteNetworks() != null) { if (data.getLocalNetworks() == null || data.getRemoteNetworks() == null) throw new IllegalArgumentException("Both local and remote networks should be set together"); long fieldId = NXCPCodes.VID_VPN_NETWORK_BASE; msg.setFieldInt32(NXCPCodes.VID_NUM_LOCAL_NETS, data.getLocalNetworks().size()); for(InetAddressEx a : data.getLocalNetworks()) { msg.setField(fieldId++, a); } msg.setFieldInt32(NXCPCodes.VID_NUM_REMOTE_NETS, data.getRemoteNetworks().size()); for(InetAddressEx a : data.getRemoteNetworks()) { msg.setField(fieldId++, a); } } if (data.getPostalAddress() != null) { data.getPostalAddress().fillMessage(msg); } if (data.getAgentCacheMode() != null) { msg.setFieldInt16(NXCPCodes.VID_AGENT_CACHE_MODE, data.getAgentCacheMode().getValue()); } if (data.getAgentCompressionMode() != null) { msg.setFieldInt16(NXCPCodes.VID_AGENT_COMPRESSION_MODE, data.getAgentCompressionMode().getValue()); } if (data.getMapObjectDisplayMode() != null) { msg.setFieldInt16(NXCPCodes.VID_DISPLAY_MODE, data.getMapObjectDisplayMode().getValue()); } if (data.getFrontRackImage() != null || data.getRearRackImage() != null || data.getRackPosition() != null || data.getRackHeight() != null || data.getRackOrientation() != null) { if (data.getFrontRackImage() == null || data.getRearRackImage() == null || data.getRackPosition() == null || data.getRackHeight() == null || data.getRackOrientation() == null) throw new IllegalArgumentException("All rack placement attributes should be set (front image, rear image, position, height, and orientation)"); msg.setFieldInt32(NXCPCodes.VID_PHYSICAL_CONTAINER_ID, data.getPhysicalContainerObjectId()!= null ? data.getPhysicalContainerObjectId().intValue() : 0); msg.setField(NXCPCodes.VID_RACK_IMAGE_FRONT, data.getFrontRackImage()); msg.setField(NXCPCodes.VID_RACK_IMAGE_REAR, data.getRearRackImage()); msg.setFieldInt16(NXCPCodes.VID_RACK_POSITION, data.getRackPosition()); msg.setFieldInt16(NXCPCodes.VID_RACK_HEIGHT, data.getRackHeight()); msg.setFieldInt16(NXCPCodes.VID_RACK_ORIENTATION, data.getRackOrientation().getValue()); } if (data.getPhysicalContainerObjectId() != null || data.getChassisPlacement() != null) { if (data.getPhysicalContainerObjectId() == null || data.getChassisPlacement() == null) throw new IllegalArgumentException("Both physical container object and chassis placement should be set"); msg.setFieldInt32(NXCPCodes.VID_PHYSICAL_CONTAINER_ID, data.getPhysicalContainerObjectId().intValue()); msg.setField(NXCPCodes.VID_CHASSIS_PLACEMENT_CONFIG, data.getChassisPlacement()); } if (data.getDashboards() != null) { msg.setField(NXCPCodes.VID_DASHBOARDS, data.getDashboards()); } if (data.getControllerId() != null) { msg.setFieldInt32(NXCPCodes.VID_CONTROLLER_ID, data.getControllerId().intValue()); } if (data.getSshProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_SSH_PROXY, data.getSshProxy().intValue()); } if (data.getSshKeyId() != null) { msg.setFieldInt32(NXCPCodes.VID_SSH_KEY_ID, data.getSshKeyId()); } if (data.getSshLogin() != null) { msg.setField(NXCPCodes.VID_SSH_LOGIN, data.getSshLogin()); } if (data.getSshPassword() != null) { msg.setField(NXCPCodes.VID_SSH_PASSWORD, data.getSshPassword()); } if (data.getSshPort() != null) { msg.setFieldInt16(NXCPCodes.VID_SSH_PORT, data.getSshPort()); } if (data.getZoneProxies() != null) { msg.setField(NXCPCodes.VID_ZONE_PROXY_LIST, data.getZoneProxies()); } if (data.getSeedObjectIds() != null) { msg.setField(NXCPCodes.VID_SEED_OBJECTS, data.getSeedObjectIds()); } if (data.getMacAddress() != null) { msg.setField(NXCPCodes.VID_MAC_ADDR, data.getMacAddress()); } if (data.getDeviceClass() != null) { msg.setFieldInt32(NXCPCodes.VID_DEVICE_CLASS, data.getDeviceClass()); } if (data.getVendor() != null) { msg.setField(NXCPCodes.VID_VENDOR, data.getVendor()); } if (data.getSerialNumber() != null) { msg.setField(NXCPCodes.VID_SERIAL_NUMBER, data.getSerialNumber()); } if (data.getDeviceAddress() != null) { msg.setField(NXCPCodes.VID_DEVICE_ADDRESS, data.getDeviceAddress()); } if (data.getMetaType() != null) { msg.setField(NXCPCodes.VID_META_TYPE, data.getMetaType()); } if (data.getSensorProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_SENSOR_PROXY, data.getSensorProxy().intValue()); } if (data.getXmlConfig() != null) { msg.setField(NXCPCodes.VID_XML_CONFIG, data.getXmlConfig()); } if (data.getPassiveElements() != null) { List elements = data.getPassiveElements(); msg.setFieldInt32(NXCPCodes.VID_NUM_ELEMENTS, elements.size()); long base = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < elements.size(); i++) { elements.get(i).fillMessage(msg, base); base += 10; } } if (data.getResponsibleUsers() != null) { msg.setFieldInt32(NXCPCodes.VID_RESPONSIBLE_USERS_COUNT, data.getResponsibleUsers().size()); long fieldId = NXCPCodes.VID_RESPONSIBLE_USERS_BASE; for(ResponsibleUser r : data.getResponsibleUsers()) { r.fillMessage(msg, fieldId); fieldId += 10; } } if (data.getIcmpStatCollectionMode() != null) { msg.setFieldInt16(NXCPCodes.VID_ICMP_COLLECTION_MODE, data.getIcmpStatCollectionMode().getValue()); } if (data.getIcmpTargets() != null) { msg.setFieldInt32(NXCPCodes.VID_ICMP_TARGET_COUNT, data.getIcmpTargets().size()); long fieldId = NXCPCodes.VID_ICMP_TARGET_LIST_BASE; for(InetAddress a : data.getIcmpTargets()) msg.setField(fieldId++, a); } if (data.getEtherNetIPPort() != null) { msg.setFieldInt16(NXCPCodes.VID_ETHERNET_IP_PORT, data.getEtherNetIPPort()); } if (data.getEtherNetIPProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_ETHERNET_IP_PROXY, data.getEtherNetIPProxy().intValue()); } if (data.getModbusTcpPort() != null) { msg.setFieldInt16(NXCPCodes.VID_MODBUS_TCP_PORT, data.getModbusTcpPort()); } if (data.getModbusUnitId() != null) { msg.setFieldInt16(NXCPCodes.VID_MODBUS_UNIT_ID, data.getModbusUnitId()); } if (data.getModbusProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_MODBUS_PROXY, data.getModbusProxy().intValue()); } if (data.getCertificateMappingData() != null || data.getCertificateMappingMethod() != null) { if (data.getCertificateMappingData() == null || data.getCertificateMappingMethod() == null) throw new IllegalArgumentException("Both certificate mapping method and certificate mapping data should be set"); msg.setFieldInt16(NXCPCodes.VID_CERT_MAPPING_METHOD, data.getCertificateMappingMethod().getValue()); msg.setField(NXCPCodes.VID_CERT_MAPPING_DATA, data.getCertificateMappingData()); } if (data.getCategoryId() != null) { msg.setFieldInt32(NXCPCodes.VID_CATEGORY_ID, data.getCategoryId()); } if (data.getGeoLocationControlMode() != null) { msg.setFieldInt16(NXCPCodes.VID_GEOLOCATION_CTRL_MODE, data.getGeoLocationControlMode().getValue()); } if (data.getGeoAreas() != null) { msg.setField(NXCPCodes.VID_GEO_AREAS, data.getGeoAreas()); } if (data.getInstanceDiscoveryMethod() != null) { msg.setFieldInt32(NXCPCodes.VID_INSTD_METHOD, data.getInstanceDiscoveryMethod()); } if (data.getInstanceDiscoveryData() != null) { msg.setField(NXCPCodes.VID_INSTD_DATA, data.getInstanceDiscoveryData()); } if (data.getInstanceDiscoveryFilter() != null) { msg.setField(NXCPCodes.VID_INSTD_FILTER, data.getInstanceDiscoveryFilter()); } if (data.getObjectStatusThreshold() != null) { msg.setFieldInt32(NXCPCodes.VID_OBJECT_STATUS_THRESHOLD, data.getObjectStatusThreshold()); } if (data.getDciStatusThreshold() != null) { msg.setFieldInt32(NXCPCodes.VID_DCI_STATUS_THRESHOLD, data.getDciStatusThreshold()); } if (data.getSourceNode() != null) { msg.setFieldInt32(NXCPCodes.VID_NODE_ID, data.getSourceNode().intValue()); } if (data.getWebServiceProxy() != null) { msg.setFieldInt32(NXCPCodes.VID_WEB_SERVICE_PROXY, data.getWebServiceProxy().intValue()); } if (data.getSyslogCodepage() != null) { msg.setField(NXCPCodes.VID_SYSLOG_CODEPAGE, data.getSyslogCodepage()); } if (data.getSNMPCodepage() != null) { msg.setField(NXCPCodes.VID_SNMP_CODEPAGE, data.getSNMPCodepage()); } if (data.getDisplayPriority() != null) { msg.setFieldInt32(NXCPCodes.VID_DISPLAY_PRIORITY, data.getDisplayPriority()); } modifyCustomObject(data, userData, msg); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Modify object (generic interface, in most cases wrapper functions should * be used instead). Equivalent of calling modifyObject(data, null). * * @param data Object modification data * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void modifyObject(final NXCObjectModificationData data) throws IOException, NXCException { modifyObject(data, null); } /** * Change object's name (wrapper for modifyObject()) * * @param objectId ID of object to be changed * @param name New object's name * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setObjectName(final long objectId, final String name) throws IOException, NXCException { NXCObjectModificationData data = new NXCObjectModificationData(objectId); data.setName(name); modifyObject(data); } /** * Change object's custom attributes (wrapper for modifyObject()) * * @param objectId The object ID * @param attrList The attribute list * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setObjectCustomAttributes(final long objectId, final Map attrList) throws IOException, NXCException { NXCObjectModificationData data = new NXCObjectModificationData(objectId); data.setCustomAttributes(attrList); modifyObject(data); } /** * Change object's ACL (wrapper for modifyObject()) * * @param objectId The object id * @param acl The AccessListElements * @param inheritAccessRights true if access rights should be inherited * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setObjectACL(long objectId, Collection acl, boolean inheritAccessRights) throws IOException, NXCException { NXCObjectModificationData data = new NXCObjectModificationData(objectId); data.setACL(acl); data.setInheritAccessRights(inheritAccessRights); modifyObject(data); } /** * Move object to different zone. Only nodes and clusters can be moved * between zones. * * @param objectId Node or cluster object ID * @param zoneUIN The zone UIN (unique identification number) * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void changeObjectZone(long objectId, int zoneUIN) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_CHANGE_ZONE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setFieldInt32(NXCPCodes.VID_ZONE_UIN, zoneUIN); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Change object's comments. * * @param objectId Object's ID * @param comments New comments * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void updateObjectComments(long objectId, String comments) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_OBJECT_COMMENTS); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setField(NXCPCodes.VID_COMMENTS, comments); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Update list of responsible users for given object. * * @param objectId Object's ID * @param users New list of responsible users * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void updateResponsibleUsers(long objectId, List users) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_RESPONSIBLE_USERS); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setFieldInt32(NXCPCodes.VID_RESPONSIBLE_USERS_COUNT, users.size()); long fieldId = NXCPCodes.VID_RESPONSIBLE_USERS_BASE; for(ResponsibleUser r : users) { r.fillMessage(msg, fieldId); fieldId += 10; } sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Set object's managed status. * * @param objectId object's identifier * @param isManaged object's managed status * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void setObjectManaged(final long objectId, final boolean isManaged) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_OBJECT_MGMT_STATUS); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setFieldInt16(NXCPCodes.VID_MGMT_STATUS, isManaged ? 1 : 0); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get effective rights of currently logged in user to given object. * * @param objectId The object ID * @return The effective rights * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public int getEffectiveRights(final long objectId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_EFFECTIVE_RIGHTS); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); sendMessage(msg); return waitForRCC(msg.getMessageId()).getFieldAsInt32(NXCPCodes.VID_EFFECTIVE_RIGHTS); } /** * Common internal implementation for bindObject, unbindObject, and * removeTemplate * * @param parentId parent object's identifier * @param childId Child object's identifier * @param bind true if operation is "bind" * @param removeDci true if DCIs created from template should be removed during * unbind * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ private void changeObjectBinding(long parentId, long childId, boolean bind, boolean removeDci) throws IOException, NXCException { NXCPMessage msg = newMessage(bind ? NXCPCodes.CMD_BIND_OBJECT : NXCPCodes.CMD_UNBIND_OBJECT); msg.setFieldInt32(NXCPCodes.VID_PARENT_ID, (int)parentId); msg.setFieldInt32(NXCPCodes.VID_CHILD_ID, (int)childId); msg.setFieldInt16(NXCPCodes.VID_REMOVE_DCI, removeDci ? 1 : 0); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Bind object. * * @param parentId parent object's identifier * @param childId Child object's identifier * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void bindObject(final long parentId, final long childId) throws IOException, NXCException { changeObjectBinding(parentId, childId, true, false); } /** * Unbind object. * * @param parentId parent object's identifier * @param childId Child object's identifier * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void unbindObject(final long parentId, final long childId) throws IOException, NXCException { changeObjectBinding(parentId, childId, false, false); } /** * Remove data collection template from node. * * @param templateId template object identifier * @param nodeId node object identifier * @param removeDci true if DCIs created from this template should be removed * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void removeTemplate(final long templateId, final long nodeId, final boolean removeDci) throws IOException, NXCException { changeObjectBinding(templateId, nodeId, false, removeDci); } /** * Apply data collection template to node. * * @param templateId template object ID * @param nodeId node object ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void applyTemplate(long templateId, long nodeId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_APPLY_TEMPLATE); msg.setFieldInt32(NXCPCodes.VID_SOURCE_OBJECT_ID, (int)templateId); msg.setFieldInt32(NXCPCodes.VID_DESTINATION_OBJECT_ID, (int)nodeId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Add node to cluster. * * @param clusterId cluster object ID * @param nodeId node object ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void addClusterNode(final long clusterId, final long nodeId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_ADD_CLUSTER_NODE); msg.setFieldInt32(NXCPCodes.VID_PARENT_ID, (int)clusterId); msg.setFieldInt32(NXCPCodes.VID_CHILD_ID, (int)nodeId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Remove node from cluster. * * @param clusterId cluster object ID * @param nodeId node object ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void removeClusterNode(final long clusterId, final long nodeId) throws IOException, NXCException { changeObjectBinding(clusterId, nodeId, false, true); } /** * Generic implementation for ad-hoc topology map requests. * * @param nodeId The node ID * @param command command to send to server * @param pageIdSuffix map page ID suffix * @return network map page representing requested topology * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ private NetworkMapPage queryAdHocTopologyMap(long nodeId, int command, String pageIdSuffix) throws IOException, NXCException { NXCPMessage msg = newMessage(command); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_OBJECTS); long[] idList = response.getFieldAsUInt32Array(NXCPCodes.VID_OBJECT_LIST); if (idList.length != count) throw new NXCException(RCC.INTERNAL_ERROR); NetworkMapPage page = new NetworkMapPage(msg.getMessageId() + pageIdSuffix); for(int i = 0; i < count; i++) page.addElement(new NetworkMapObject(page.createElementId(), idList[i])); count = response.getFieldAsInt32(NXCPCodes.VID_NUM_LINKS); long varId = NXCPCodes.VID_OBJECT_LINKS_BASE; for(int i = 0; i < count; i++, varId += 3) { NetworkMapObject obj1 = page.findObjectElement(response.getFieldAsInt64(varId++)); NetworkMapObject obj2 = page.findObjectElement(response.getFieldAsInt64(varId++)); int type = response.getFieldAsInt32(varId++); String port1 = response.getFieldAsString(varId++); String port2 = response.getFieldAsString(varId++); String name = response.getFieldAsString(varId++); int flags = response.getFieldAsInt32(varId++); if ((obj1 != null) && (obj2 != null)) { page.addLink(new NetworkMapLink(page.createLinkId(), name, type, obj1.getId(), obj2.getId(), port1, port2, flags)); } } return page; } /** * Query layer 2 topology for node * * @param nodeId The node ID * @return network map page representing layer 2 topology * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public NetworkMapPage queryLayer2Topology(final long nodeId) throws IOException, NXCException { return queryAdHocTopologyMap(nodeId, NXCPCodes.CMD_QUERY_L2_TOPOLOGY, ".L2Topology"); } /** * Query OSPF topology for node * * @param nodeId The node ID * @return network map page representing OSPF topology * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public NetworkMapPage queryOSPFTopology(final long nodeId) throws IOException, NXCException { return queryAdHocTopologyMap(nodeId, NXCPCodes.CMD_QUERY_OSPF_TOPOLOGY, ".OSPFTopology"); } /** * Query internal connection topology for node * * @param nodeId The node ID * @return network map page representing internal communication topology * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public NetworkMapPage queryInternalConnectionTopology(final long nodeId) throws IOException, NXCException { return queryAdHocTopologyMap(nodeId, NXCPCodes.CMD_QUERY_INTERNAL_TOPOLOGY, ".InternalConnectionTopology"); } /** * Execute action on remote agent * * @param nodeId Node object ID * @param alarmId Alarm ID (used for macro expansion) * @param action Action with all arguments, that will be expanded and splitted on server side * @param inputValues Input values provided by user for expansion * @param maskedFields List if input fields whose content should be masked (can be null) * @return Expanded action name * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String executeActionWithExpansion(long nodeId, long alarmId, String action, final Map inputValues, final List maskedFields) throws IOException, NXCException { return executeActionWithExpansion(nodeId, alarmId, action, false, inputValues, maskedFields, null, null); } /** * Execute action on remote agent * * @param nodeId Node object ID * @param alarmId Alarm ID (used for macro expansion) * @param action Action with all arguments, that will be expanded and splitted on server side * @param inputValues Input values provided by user for expansion * @param maskedFields List if input fields whose content should be masked (can be null) * @param receiveOutput true if action's output has to be read * @param listener listener for action's output or null * @param writer writer for action's output or null * @return Expanded action name * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String executeActionWithExpansion(long nodeId, long alarmId, String action, boolean receiveOutput, final Map inputValues, final List maskedFields, final TextOutputListener listener, final Writer writer) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_EXECUTE_ACTION); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setField(NXCPCodes.VID_EXPAND_STRING, true); msg.setField(NXCPCodes.VID_ACTION_NAME, action); msg.setField(NXCPCodes.VID_RECEIVE_OUTPUT, receiveOutput); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); if (inputValues != null) { msg.setFieldInt32(NXCPCodes.VID_INPUT_FIELD_COUNT, inputValues.size()); long varId = NXCPCodes.VID_INPUT_FIELD_BASE; for(Entry e : inputValues.entrySet()) { msg.setField(varId++, e.getKey()); msg.setField(varId++, e.getValue()); } } else { msg.setFieldInt16(NXCPCodes.VID_INPUT_FIELD_COUNT, 0); } if ((maskedFields != null) && !maskedFields.isEmpty()) { msg.setFieldsFromStringCollection(maskedFields, NXCPCodes.VID_MASKED_FIELD_LIST_BASE, NXCPCodes.VID_NUM_MASKED_FIELDS); } MessageHandler handler = receiveOutput ? new MessageHandler() { @Override public boolean processMessage(NXCPMessage m) { String text = m.getFieldAsString(NXCPCodes.VID_MESSAGE); if (text != null) { if (listener != null) listener.messageReceived(text); if (writer != null) { try { writer.write(text); } catch(IOException e) { } } } if (m.isEndOfSequence()) setComplete(); return true; } } : null; if (receiveOutput) addMessageSubscription(NXCPCodes.CMD_COMMAND_OUTPUT, msg.getMessageId(), handler); sendMessage(msg); NXCPMessage result = waitForRCC(msg.getMessageId()); if (receiveOutput) { handler.waitForCompletion(); if (handler.isExpired()) throw new NXCException(RCC.TIMEOUT); } return result.getFieldAsString(NXCPCodes.VID_ACTION_NAME); } /** * Execute action on remote agent * * @param nodeId Node object ID * @param action Action name * @param args Action arguments * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeAction(long nodeId, String action, String[] args) throws IOException, NXCException { executeAction(nodeId, action, args, false, null, null); } /** * Execute action on remote agent * * @param nodeId Node object ID * @param action Action name * @param args Action arguments * @param receiveOutput true if action's output has to be read * @param listener listener for action's output or null * @param writer writer for action's output or null * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeAction(long nodeId, String action, String[] args, boolean receiveOutput, final TextOutputListener listener, final Writer writer) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_EXECUTE_ACTION); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setField(NXCPCodes.VID_ACTION_NAME, action); msg.setField(NXCPCodes.VID_RECEIVE_OUTPUT, receiveOutput); if (args != null) { msg.setFieldInt16(NXCPCodes.VID_NUM_ARGS, args.length); long fieldId = NXCPCodes.VID_ACTION_ARG_BASE; for(String a : args) msg.setField(fieldId++, a); } else { msg.setFieldInt16(NXCPCodes.VID_NUM_ARGS, 0); } MessageHandler handler = receiveOutput ? new MessageHandler() { @Override public boolean processMessage(NXCPMessage m) { String text = m.getFieldAsString(NXCPCodes.VID_MESSAGE); if (text != null) { if (listener != null) listener.messageReceived(text); if (writer != null) { try { writer.write(text); } catch(IOException e) { } } } if (m.isEndOfSequence()) setComplete(); return true; } } : null; if (receiveOutput) addMessageSubscription(NXCPCodes.CMD_COMMAND_OUTPUT, msg.getMessageId(), handler); sendMessage(msg); waitForRCC(msg.getMessageId()); if (receiveOutput) { handler.waitForCompletion(); if (handler.isExpired()) throw new NXCException(RCC.TIMEOUT); } } /** * Execute SSH command on remote agent * * @param nodeId Node object ID * @param alarmId Alarm ID (0 if not executed in alarm context) * @param command Command to execute * @param inputFields Input fields provided by user or null * @param maskedFields List of input field names for which values should be masked (can be null) * @param receiveOutput true if command's output has to be read * @param listener listener for command's output or null * @param writer writer for command's output or null * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeSshCommand(long nodeId, long alarmId, String command, Map inputFields, List maskedFields, boolean receiveOutput, final TextOutputListener listener, final Writer writer) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_SSH_COMMAND); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); msg.setField(NXCPCodes.VID_COMMAND, command); msg.setField(NXCPCodes.VID_RECEIVE_OUTPUT, receiveOutput); if (inputFields != null) { msg.setFieldInt16(NXCPCodes.VID_NUM_FIELDS, inputFields.size()); long fieldId = NXCPCodes.VID_FIELD_LIST_BASE; for(Entry e : inputFields.entrySet()) { msg.setField(fieldId++, e.getKey()); msg.setField(fieldId++, e.getValue()); } } if ((maskedFields != null) && !maskedFields.isEmpty()) { msg.setFieldsFromStringCollection(maskedFields, NXCPCodes.VID_MASKED_FIELD_LIST_BASE, NXCPCodes.VID_NUM_MASKED_FIELDS); } MessageHandler handler = receiveOutput ? new MessageHandler() { @Override public boolean processMessage(NXCPMessage m) { String text = m.getFieldAsString(NXCPCodes.VID_MESSAGE); if (text != null) { if (listener != null) listener.messageReceived(text); if (writer != null) { try { writer.write(text); } catch(IOException e) { } } } if (m.isEndOfSequence()) setComplete(); return true; } } : null; if (receiveOutput) addMessageSubscription(NXCPCodes.CMD_COMMAND_OUTPUT, msg.getMessageId(), handler); sendMessage(msg); waitForRCC(msg.getMessageId()); if (receiveOutput) { handler.waitForCompletion(); if (handler.isExpired()) throw new NXCException(RCC.TIMEOUT); } } /** * Wakeup node by sending wake-on-LAN magic packet. Either node ID or * interface ID may be given. If node ID is given, system will send wakeup * packets to all active interfaces with IP address. * * @param objectId node or interface ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void wakeupNode(final long objectId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_WAKEUP_NODE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get node's physical components (obtained from ENTITY-MIB). * * @param nodeId node object identifier * @return root component * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public PhysicalComponent getNodePhysicalComponents(long nodeId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_NODE_COMPONENTS); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return new PhysicalComponent(response, NXCPCodes.VID_COMPONENT_LIST_BASE, null); } /** * Get list of available Windows performance objects. Returns empty list if node * does is not a Windows node or does not have WinPerf subagent installed. * * @param nodeId node object ID * @return list of available Windows performance objects * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getNodeWinPerfObjects(long nodeId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_WINPERF_OBJECTS); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return WinPerfObject.createListFromMessage(response); } /** * Get list of software packages installed on node. * * @param nodeId node object identifier * @return root component * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getNodeSoftwarePackages(long nodeId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_NODE_SOFTWARE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); List packages = new ArrayList(count); long varId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < count; i++) { packages.add(new SoftwarePackage(response, varId)); varId += 10; } return packages; } /** * Get list of hardware components as reported by agent. * * @param nodeId node object identifier * @return list of hardware components * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getNodeHardwareComponents(long nodeId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_NODE_HARDWARE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); List components = new ArrayList(count); long baseId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < count; i++) { components.add(new HardwareComponent(response, baseId)); baseId += 64; } return components; } /** * Get list of user sessions on given node as reported by agent. * * @param nodeId node object identifier * @return list of user sessions * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getUserSessions(long nodeId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_USER_SESSIONS); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_SESSIONS); List sessions = new ArrayList(count); long baseId = NXCPCodes.VID_SESSION_DATA_BASE; for(int i = 0; i < count; i++) { sessions.add(new UserSession(response, baseId)); baseId += 64; } return sessions; } /** * Get list of dependent nodes for given node. Node is considered dependent if it use given node * as any type of proxy or as data collection source for at least one DCI. * * @param nodeId node object ID * @return list of dependent node descriptors * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getDependentNodes(long nodeId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_DEPENDENT_NODES); msg.setFieldInt32(NXCPCodes.VID_NODE_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); List nodes = new ArrayList(count); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < count; i++, fieldId += 10) nodes.add(new DependentNode(msg, fieldId)); return nodes; } /** * Get list of server jobs * * @return list of server jobs * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public ServerJob[] getServerJobList() throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_JOB_LIST); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_JOB_COUNT); ServerJob[] jobList = new ServerJob[count]; long baseVarId = NXCPCodes.VID_JOB_LIST_BASE; for(int i = 0; i < count; i++, baseVarId += 10) { jobList[i] = new ServerJob(response, baseVarId); } return jobList; } /** * Cancel server job * * @param jobId Job ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void cancelServerJob(long jobId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_CANCEL_JOB); msg.setFieldInt32(NXCPCodes.VID_JOB_ID, (int)jobId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Put server job on hold * * @param jobId Job ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void holdServerJob(long jobId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_HOLD_JOB); msg.setFieldInt32(NXCPCodes.VID_JOB_ID, (int)jobId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Put server on hold job to pending state * * @param jobId Job ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void unholdServerJob(long jobId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UNHOLD_JOB); msg.setFieldInt32(NXCPCodes.VID_JOB_ID, (int)jobId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get state of background task. * * @param taskId Task ID * @return state of background task * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public BackgroundTaskState getBackgroundTaskState(long taskId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_BACKGROUND_TASK_STATE); msg.setFieldInt64(NXCPCodes.VID_JOB_ID, taskId); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); return BackgroundTaskState.getByValue(response.getFieldAsInt32(NXCPCodes.VID_STATE)); } /** * Deploy policy on agent * * @param policyId Policy object ID * @param nodeId Node object ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deployAgentPolicy(final long policyId, final long nodeId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DEPLOY_AGENT_POLICY); msg.setFieldInt32(NXCPCodes.VID_POLICY_ID, (int)policyId); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Uninstall policy from agent * * @param policyId Policy object ID * @param nodeId Node object ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void uninstallAgentPolicy(final long policyId, final long nodeId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_UNINSTALL_AGENT_POLICY); msg.setFieldInt32(NXCPCodes.VID_POLICY_ID, (int)policyId); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Internal implementation for open/get event processing policy. * * @param readOnly true to get read-only copy of the policy * @return Event processing policy * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ private EventProcessingPolicy getEventProcessingPolicyInternal(boolean readOnly) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_OPEN_EPP); msg.setFieldInt16(NXCPCodes.VID_READ_ONLY, readOnly ? 1 : 0); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); int numRules = response.getFieldAsInt32(NXCPCodes.VID_NUM_RULES); final EventProcessingPolicy policy = new EventProcessingPolicy(numRules); for(int i = 0; i < numRules; i++) { response = waitForMessage(NXCPCodes.CMD_EPP_RECORD, msg.getMessageId()); policy.addRule(new EventProcessingPolicyRule(response, i + 1)); } return policy; } /** * Get read-only copy of event processing policy. * * @return Event processing policy * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public EventProcessingPolicy getEventProcessingPolicy() throws IOException, NXCException { return getEventProcessingPolicyInternal(true); } /** * Open event processing policy for editing. This call will lock event * processing policy on server until closeEventProcessingPolicy called or * session terminated. * * @return Event processing policy * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public EventProcessingPolicy openEventProcessingPolicy() throws IOException, NXCException { return getEventProcessingPolicyInternal(false); } /** * Save event processing policy. If policy was not previously open by current * session exception will be thrown. * * @param epp Modified event processing policy * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void saveEventProcessingPolicy(EventProcessingPolicy epp) throws IOException, NXCException { final List rules = epp.getRules(); NXCPMessage msg = newMessage(NXCPCodes.CMD_SAVE_EPP); msg.setFieldInt32(NXCPCodes.VID_NUM_RULES, rules.size()); sendMessage(msg); final long msgId = msg.getMessageId(); waitForRCC(msgId); int id = 1; for(EventProcessingPolicyRule rule : rules) { msg = new NXCPMessage(NXCPCodes.CMD_EPP_RECORD); msg.setMessageId(msgId); msg.setFieldInt32(NXCPCodes.VID_RULE_ID, id++); rule.fillMessage(msg); sendMessage(msg); } // Wait for final confirmation if there was some rules if (rules.size() > 0) waitForRCC(msgId); } /** * Close event processing policy. This call will unlock event processing * policy on server. If policy was not previously open by current session * exception will be thrown. * * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void closeEventProcessingPolicy() throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_CLOSE_EPP); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Open data collection configuration for given node. You must call * DataCollectionConfiguration.close() to close data collection configuration * when it is no longer needed. * * @param nodeId Node object identifier * @return Data collection configuration object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DataCollectionConfiguration openDataCollectionConfiguration(long nodeId) throws IOException, NXCException { return openDataCollectionConfiguration(nodeId, null); } /** * Open data collection configuration for given node. You must call * DataCollectionConfiguration.close() to close data collection configuration * when it is no longer needed. * * @param nodeId Node object identifier * @param changeListener callback that will be called when DCO object is changed by server notification * @return Data collection configuration object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public DataCollectionConfiguration openDataCollectionConfiguration(long nodeId, RemoteChangeListener changeListener) throws IOException, NXCException { final DataCollectionConfiguration cfg = new DataCollectionConfiguration(this, nodeId); cfg.open(changeListener); return cfg; } /** * Modify data collection object without opening data collection configuration. * * @param dcObject dcObject collection object * @return Identifier assigned to newly created object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long modifyDataCollectionObject(DataCollectionObject dcObject) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_MODIFY_NODE_DCI); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)dcObject.getNodeId()); dcObject.fillMessage(msg); sendMessage(msg); return waitForRCC(msg.getMessageId()).getFieldAsInt64(NXCPCodes.VID_DCI_ID); } /** * Clear data collection configuration on agent. Will wipe out all configuration and collected data. * * @param nodeId node object ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void clearAgentDataCollectionConfiguration(final long nodeId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_CLEAN_AGENT_DCI_CONF); msg.setFieldInt32(NXCPCodes.VID_NODE_ID, (int)nodeId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Force re-synchronization of data collection configuration with agent. * * @param nodeId node object ID * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void resyncAgentDataCollectionConfiguration(final long nodeId) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_RESYNC_AGENT_DCI_CONF); msg.setFieldInt32(NXCPCodes.VID_NODE_ID, (int)nodeId); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Test DCI transformation script. * * @param nodeId ID of the node object to test script on * @param script script source code * @param inputValue input value for the script * @param dcObject optional data collection object data (for $dci variable in script) * @return test execution results * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public TransformationTestResult testTransformationScript(long nodeId, String script, String inputValue, DataCollectionObject dcObject) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_TEST_DCI_TRANSFORMATION); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setField(NXCPCodes.VID_SCRIPT, script); msg.setField(NXCPCodes.VID_VALUE, inputValue); if (dcObject != null) { dcObject.fillMessage(msg); } sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); TransformationTestResult r = new TransformationTestResult(); r.success = response.getFieldAsBoolean(NXCPCodes.VID_EXECUTION_STATUS); r.result = response.getFieldAsString(NXCPCodes.VID_EXECUTION_RESULT); return r; } /** * Message handler for script execution updates */ private static class ScriptExecutionUpdateHandler extends MessageHandler { private TextOutputListener listener; private int errorCode = 0; private String errorMessage = null; ScriptExecutionUpdateHandler(TextOutputListener listener) { this.listener = listener; } /** * @see org.netxms.client.MessageHandler#processMessage(org.netxms.base.NXCPMessage) */ @Override public boolean processMessage(NXCPMessage m) { int rcc = m.getFieldAsInt32(NXCPCodes.VID_RCC); if (rcc != RCC.SUCCESS) { errorCode = rcc; errorMessage = m.getFieldAsString(NXCPCodes.VID_ERROR_TEXT); if (errorMessage == null) errorMessage = "Unspecified sript execution error (RCC=" + rcc + ")"; if (listener != null) { listener.messageReceived(errorMessage + "\n\n"); listener.onFailure(null); } } else { String text = m.getFieldAsString(NXCPCodes.VID_MESSAGE); if ((text != null) && (listener != null)) { listener.messageReceived(text); } } if (m.isEndOfSequence()) { if (listener != null) listener.onSuccess(); setComplete(); } return true; } /** * Check if error was reported * * @return true if error was reported */ public boolean isFailure() { return errorMessage != null; } /** * Get error code. * * @return error code */ public int getErrorCode() { return errorCode; } /** * Get execution error message. * * @return execution error message */ public String getErrorMessage() { return errorMessage; } } /** * Process server script execution. * * @param msg prepared request message * @param listener script output listener or null if caller not interested in script output * @param resultAsMap if true, expect script execution results to be sent as map * @return execution result as map if resultAsMap is set to true, and null otherwise * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ private Map processScriptExecution(NXCPMessage msg, TextOutputListener listener, boolean resultAsMap) throws IOException, NXCException { msg.setField(NXCPCodes.VID_RESULT_AS_MAP, resultAsMap); ScriptExecutionUpdateHandler handler = new ScriptExecutionUpdateHandler(listener); handler.setMessageWaitTimeout(commandTimeout); addMessageSubscription(NXCPCodes.CMD_EXECUTE_SCRIPT_UPDATE, msg.getMessageId(), handler); sendMessage(msg); waitForRCC(msg.getMessageId()); handler.waitForCompletion(); if (handler.isExpired()) throw new NXCException(RCC.TIMEOUT); if (handler.isFailure()) throw new NXCException(handler.getErrorCode(), handler.getErrorMessage()); if (!resultAsMap) return null; NXCPMessage response = waitForMessage(NXCPCodes.CMD_SCRIPT_EXECUTION_RESULT, msg.getMessageId()); return response.getStringMapFromFields(NXCPCodes.VID_ELEMENT_LIST_BASE, NXCPCodes.VID_NUM_ELEMENTS); } /** * Execute library script on object. Script name interpreted as command line with server-side macro substitution. Map inputValues * can be used to pass data for %() macros. * * @param nodeId node ID to execute script on * @param script script name and parameters * @param inputFields input values map for %() macro substitution (can be null) * @param maskedFields List of input field names for which values should be masked (can be null) * @param listener script output listener * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeLibraryScript(long nodeId, String script, Map inputFields, List maskedFields, final TextOutputListener listener) throws IOException, NXCException { executeLibraryScript(nodeId, 0, script, inputFields, maskedFields, listener); } /** * Execute library script on object. Script name interpreted as command line with server-side macro substitution. Map inputValues * can be used to pass data for %() macros. * * @param objectId ID of the object to execute script on * @param alarmId alarm ID to use for expansion * @param script script name and parameters * @param inputFields input values map for %() macro substitution (can be null) * @param maskedFields List of input field names for which values should be masked (can be null) * @param listener script output listener * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeLibraryScript(long objectId, long alarmId, String script, Map inputFields, List maskedFields, final TextOutputListener listener) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_EXECUTE_LIBRARY_SCRIPT); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setField(NXCPCodes.VID_SCRIPT, script); msg.setFieldInt32(NXCPCodes.VID_ALARM_ID, (int)alarmId); msg.setField(NXCPCodes.VID_RECEIVE_OUTPUT, listener != null); if (inputFields != null) { msg.setFieldInt16(NXCPCodes.VID_NUM_FIELDS, inputFields.size()); long fieldId = NXCPCodes.VID_FIELD_LIST_BASE; for(Entry e : inputFields.entrySet()) { msg.setField(fieldId++, e.getKey()); msg.setField(fieldId++, e.getValue()); } } if ((maskedFields != null) && !maskedFields.isEmpty()) { msg.setFieldsFromStringCollection(maskedFields, NXCPCodes.VID_MASKED_FIELD_LIST_BASE, NXCPCodes.VID_NUM_MASKED_FIELDS); } processScriptExecution(msg, listener, false); } /** * Execute script. * * @param objectId ID of the object to execute script on * @param script script source code * @param listener script output listener * @param parameters script parameter list (can be null) * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeScript(long objectId, String script, String parameters, final TextOutputListener listener) throws IOException, NXCException { executeScript(objectId, script, parameters, listener, false); } /** * Execute script. * * @param objectId ID of the object to execute script on * @param script script source code * @param listener script output listener * @param parameters script parameter list (can be null) * @param developmentMode true if script should be run in development mode * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeScript(long objectId, String script, String parameters, final TextOutputListener listener, boolean developmentMode) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_EXECUTE_SCRIPT); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setField(NXCPCodes.VID_SCRIPT, script); msg.setField(NXCPCodes.VID_DEVELOPMENT_MODE, developmentMode); if (parameters != null) { msg.setField(NXCPCodes.VID_PARAMETER, parameters); } processScriptExecution(msg, listener, false); } /** * Execute script. * * @param objectId ID of the object to execute script on * @param script script source code * @param parameterList script parameter list (can be null) * @param listener script output listener * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeScript(long objectId, String script, List parameterList, final TextOutputListener listener) throws IOException, NXCException { executeScript(objectId, script, parameterList, listener, false); } /** * Execute script. * * @param objectId ID of the object to execute script on * @param script script source code * @param parameterList script parameter list (can be null) * @param listener script output listener * @param developmentMode true if script should be run in development mode * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void executeScript(long objectId, String script, List parameterList, final TextOutputListener listener, boolean developmentMode) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_EXECUTE_SCRIPT); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setField(NXCPCodes.VID_SCRIPT, script); msg.setField(NXCPCodes.VID_DEVELOPMENT_MODE, developmentMode); if (parameterList != null) { msg.setFieldInt16(NXCPCodes.VID_NUM_FIELDS, parameterList.size()); long fieldId = NXCPCodes.VID_FIELD_LIST_BASE; for(String param : parameterList) { msg.setField(fieldId++, param); } } processScriptExecution(msg, listener, false); } /** * Execute script and get return value as map. Content of returned map depends on actual data type of script return value: *

    *
  • For hash map matching map will be returned; *
  • For array all elements will be returned as values and keys will be element positions starting as 1; *
  • For all other types map will consist of single element with key "1" and script return value as value. *
* * @param nodeId ID of the node object to test script on * @param script script source code * @param parameterList script parameter list can be null * @param listener script output listener * @return script return value as a map * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map queryScript(long nodeId, String script, List parameterList, final TextOutputListener listener) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_EXECUTE_SCRIPT); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setField(NXCPCodes.VID_SCRIPT, script); if (parameterList != null) { msg.setFieldInt16(NXCPCodes.VID_NUM_FIELDS, parameterList.size()); long fieldId = NXCPCodes.VID_FIELD_LIST_BASE; for(String param : parameterList) { msg.setField(fieldId++, param); } } return processScriptExecution(msg, listener, true); } /** * Compile NXSL script on server. Field *success* in compilation result object will indicate compilation status. If compilation * fails, field *errorMessage* will contain compilation error message. * * @param source script source * @param serialize flag to indicate if compiled script should be serialized and sent back to client * @return script compilation result object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public ScriptCompilationResult compileScript(String source, boolean serialize) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_COMPILE_SCRIPT); msg.setField(NXCPCodes.VID_SCRIPT, source); msg.setField(NXCPCodes.VID_SERIALIZE, serialize); sendMessage(msg); return new ScriptCompilationResult(waitForRCC(msg.getMessageId())); } /** * Open server log by name. * * @param logName Log name * @return Log object * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Log openServerLog(final String logName) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_OPEN_SERVER_LOG); msg.setField(NXCPCodes.VID_LOG_NAME, logName); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); Log log = new Log(this, response, logName); return log; } /** * Get alarm categories from server * * @return List of configured alarm categories * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getAlarmCategories() throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_ALARM_CATEGORIES); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); ArrayList list = new ArrayList(); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); for(int i = 0; i < count; i++) { list.add(new AlarmCategory(response, fieldId)); fieldId += 10; } return list; } /** * Add or update alarm category in DB * * @param object alarm category * @return The ID of the category * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long modifyAlarmCategory(AlarmCategory object) throws IOException, NXCException { if (object.getName().isEmpty()) return 0; NXCPMessage msg = newMessage(NXCPCodes.CMD_MODIFY_ALARM_CATEGORY); object.fillMessage(msg); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsInt32(NXCPCodes.VID_CATEGORY_ID); } /** * Delete alarm category in DB * * @param id of alarm category * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteAlarmCategory(long id) throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_ALARM_CATEGORY); msg.setFieldInt32(NXCPCodes.VID_CATEGORY_ID, (int)id); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Synchronize alarm category configuration. After call to this method * session object will maintain internal list of configured alarm categories * * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncAlarmCategories() throws IOException, NXCException { List categories = getAlarmCategories(); synchronized(alarmCategories) { alarmCategories.clear(); for(AlarmCategory c : categories) { alarmCategories.put(c.getId(), c); } alarmCategoriesSynchronized = true; } } /** * Check if alarm categories are synchronized. * * @return true if if alarm categories are synchronized */ public boolean isAlarmCategoriesSynchronized() { return alarmCategoriesSynchronized; } /** * Find alarm category by id in alarm category database internally * maintained by session object. You must call * NXCSession.syncAlarmCategories() first to make local copy of event template * database. * * @param id alarm category id * @return Event template object or null if not found */ public AlarmCategory findAlarmCategoryById(long id) { synchronized(alarmCategories) { return alarmCategories.get(id); } } /** * Find alarm category by name in alarm category database internally * maintained by session object. You must call * NXCSession.syncAlarmCategories() first to make local copy of event template * database. * * @param name alarm category name * @return alarm category with given name or null if not found */ public AlarmCategory findAlarmCategoryByName(String name) { synchronized(alarmCategories) { for(Map.Entry c : alarmCategories.entrySet()) { if (((AlarmCategory)c.getValue()).getName().equals(name)) return (AlarmCategory)c.getValue(); } return null; } } /** * Find multiple alarm categories by category id`s in alarm category database * internally maintained by session object. You must call * NXCSession.syncAlarmCategories() first to make local copy of alarm category * database. * * @param ids List of alarm category id`s * @return List of found alarm categories */ public List findMultipleAlarmCategories(List ids) { List list = new ArrayList(); synchronized(alarmCategories) { for(Long id : ids) { AlarmCategory e = alarmCategories.get(id); if (e != null) list.add(e); } } return list; } /** * Check if event configuratrion objects are synchronized. * * @return true if event configuratrion objects are synchronized */ public boolean isEventObjectsSynchronized() { return eventTemplatesSynchronized; } /** * Synchronize event templates configuration. After call to this method * session object will maintain internal list of configured event templates. * * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void syncEventTemplates() throws IOException, NXCException { List templates = getEventTemplates(); synchronized(eventTemplates) { eventTemplates.clear(); for(EventTemplate t : templates) { eventTemplates.put(t.getCode(), t); } eventTemplatesSynchronized = true; } } /** * Re-synchronize event templates in background */ private void resyncEventTemplates() { new Thread(new Runnable() { @Override public void run() { try { syncEventTemplates(); } catch(Exception e) { logger.error("Exception in worker thread", e); } } }).start(); } /** * Get cached list event templates * * @return List of event templates cached by client library */ public EventTemplate[] getCachedEventTemplates() { EventTemplate[] events = null; synchronized(eventTemplates) { events = eventTemplates.values().toArray(new EventTemplate[eventTemplates.size()]); } return events; } /** * Find event template by name in event template database internally * maintained by session object. You must call * NXCSession.syncEventObjects() first to make local copy of event template * database. * * @param name Event name * @return Event template object or null if not found */ public EventTemplate findEventTemplateByName(String name) { EventTemplate result = null; synchronized(eventTemplates) { for(EventTemplate t : eventTemplates.values()) { if (t.getName().equalsIgnoreCase(name)) { result = t; break; } } } return result; } /** * Get event name from event code * * @param code event code * @return event name or event code as string if event not found */ public String getEventName(long code) { synchronized(eventTemplates) { EventTemplate e = eventTemplates.get(code); return (e != null) ? e.getName() : ("[" + Long.toString(code) + "]"); } } /** * Find event template by code in event template database internally * maintained by session object. You must call * NXCSession.syncEventObjects() first to make local copy of event template * database. * * @param code Event code * @return Event template object or null if not found */ public EventTemplate findEventTemplateByCode(long code) { synchronized(eventTemplates) { return eventTemplates.get(code); } } /** * Find multiple event templates by event codes in event template database internally maintained by session object. You must call * NXCSession.syncEventObjects() first to make local copy of event template database. * * @param codes set of event codes * @return List of found event templates */ public List findMultipleEventTemplates(Collection codes) { List list = new ArrayList(); synchronized(eventTemplates) { for(long code : codes) { EventTemplate t = eventTemplates.get(code); if (t != null) list.add(t); } } return list; } /** * Find multiple event templates by event codes in event template database * internally maintained by session object. You must call * NXCSession.syncEventObjects() first to make local copy of event template * database. * * @param codes List of event codes * @return List of found event templates */ public List findMultipleEventTemplates(final long[] codes) { List list = new ArrayList(); synchronized(eventTemplates) { for(long code : codes) { EventTemplate t = eventTemplates.get(code); if (t != null) list.add(t); } } return list; } /** * Get event objects from server * * @return List of configured event objects * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getEventTemplates() throws IOException, NXCException { NXCPMessage msg = newMessage(NXCPCodes.CMD_LOAD_EVENT_DB); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_EVENTS); long base = NXCPCodes.VID_ELEMENT_LIST_BASE; List objects = new ArrayList(count); for(int i = 0; i < count; i++) { objects.add(new EventTemplate(response, base)); base += 10; } return objects; } /** * Generate code for new event template. * * @return Code for new event template * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long generateEventCode() throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GENERATE_EVENT_CODE); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsInt64(NXCPCodes.VID_EVENT_CODE); } /** * Delete event template. * * @param eventCode Event code * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void deleteEventTemplate(long eventCode) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_DELETE_EVENT_TEMPLATE); msg.setFieldInt32(NXCPCodes.VID_EVENT_CODE, (int)eventCode); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Modify event template. * * @param tmpl Event template * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void modifyEventObject(EventTemplate tmpl) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_SET_EVENT_INFO); tmpl.fillMessage(msg); sendMessage(msg); tmpl.setCode(waitForRCC(msg.getMessageId()).getFieldAsInt32(NXCPCodes.VID_EVENT_CODE)); } /** * Send event to server. Event can be identified either by event code or event name. If event name is given, event code will be * ignored. *

* Node: sending events by name supported by server version 1.1.8 and higher. * * @param eventCode event code. Ignored if event name is not null. * @param eventName event name. Must be set to null if event identified by code. * @param objectId Object ID to send event on behalf of. If set to 0, server will determine object ID by client IP address. * @param parameters event's parameters * @param userTag event's user tag * @param originTimestamp origin timestamp or null * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void sendEvent(long eventCode, String eventName, long objectId, String[] parameters, String userTag, Date originTimestamp) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_TRAP); msg.setFieldInt32(NXCPCodes.VID_EVENT_CODE, (int)eventCode); if (eventName != null) msg.setField(NXCPCodes.VID_EVENT_NAME, eventName); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); msg.setField(NXCPCodes.VID_USER_TAG, (userTag != null) ? userTag : ""); if (originTimestamp != null) msg.setField(NXCPCodes.VID_ORIGIN_TIMESTAMP, originTimestamp); msg.setFieldInt16(NXCPCodes.VID_NUM_ARGS, parameters.length); long varId = NXCPCodes.VID_EVENT_ARG_BASE; for(int i = 0; i < parameters.length; i++) { msg.setField(varId++, parameters[i]); } sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Convenience wrapper for sendEvent interface. * * @param eventCode event code * @param parameters event's parameters * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void sendEvent(long eventCode, String[] parameters) throws IOException, NXCException { sendEvent(eventCode, null, 0, parameters, null, null); } /** * Convenience wrapper for sendEvent interface. * * @param eventName event name * @param parameters event's parameters * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void sendEvent(String eventName, String[] parameters) throws IOException, NXCException { sendEvent(0, eventName, 0, parameters, null, null); } /** * Get list of well-known SNMP communities configured on server. * * @return map of SNMP community strings * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map> getSnmpCommunities() throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_COMMUNITY_LIST); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_STRINGS); long stringBase = NXCPCodes.VID_COMMUNITY_STRING_LIST_BASE; long zoneBase = NXCPCodes.VID_COMMUNITY_STRING_ZONE_LIST_BASE; Map> map = new HashMap>(count); List communities = new ArrayList(); int currentZoneUIN = response.getFieldAsInt32(zoneBase); for(int i = 0; i < count; i++) { int zoneUIN = response.getFieldAsInt32(zoneBase++); if (currentZoneUIN != zoneUIN) { map.put(currentZoneUIN, communities); communities = new ArrayList(); currentZoneUIN = zoneUIN; } communities.add(response.getFieldAsString(stringBase++)); } if (count > 0) map.put(currentZoneUIN, communities); return map; } /** * Get list of well-known SNMP communities configured on server. * * @param zoneUIN Zone UIN (unique identification number) * @return list of SNMP community strings * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getSnmpCommunities(int zoneUIN) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_COMMUNITY_LIST); msg.setFieldInt32(NXCPCodes.VID_ZONE_UIN, zoneUIN); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_STRINGS); long stringBase = NXCPCodes.VID_COMMUNITY_STRING_LIST_BASE; List stringList = new ArrayList(); for(int i = 0; i < count; i++) { stringList.add(response.getFieldAsString(stringBase++)); } return stringList; } /** * Update list of well-known SNMP community strings on server. Existing list will be replaced by provided one. * * @param zoneUIN Zone UIN (unique identification number) * @param communityStrings New list of SNMP community strings * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void updateSnmpCommunities(int zoneUIN, List communityStrings) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_COMMUNITY_LIST); msg.setFieldInt32(NXCPCodes.VID_ZONE_UIN, zoneUIN); long stringBase = NXCPCodes.VID_COMMUNITY_STRING_LIST_BASE; for(String s : communityStrings) { msg.setField(stringBase++, s); } msg.setFieldInt32(NXCPCodes.VID_NUM_STRINGS, communityStrings.size()); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get list of well-known SNMP USM (user security model) credentials configured on server. * * @return Map of SNMP USM credentials * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map> getSnmpUsmCredentials() throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_USM_CREDENTIALS); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_RECORDS); Map> map = new HashMap>(count); List credentials = new ArrayList(); long fieldId = NXCPCodes.VID_USM_CRED_LIST_BASE; int zoneId = 0; for(int i = 0; i < count; i++, fieldId += 10) { SnmpUsmCredential cred = new SnmpUsmCredential(response, fieldId); if ((i != 0) && (zoneId != cred.getZoneId())) { map.put(zoneId, credentials); credentials = new ArrayList(); } credentials.add(cred); zoneId = cred.getZoneId(); } if (count > 0) map.put(zoneId, credentials); return map; } /** * Get list of well-known SNMP USM (user security model) credentials configured on server. * * @param zoneUIN Zone UIN (unique identification number) * @return List of configured SNMP USM credentials * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getSnmpUsmCredentials(int zoneUIN) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_USM_CREDENTIALS); msg.setFieldInt32(NXCPCodes.VID_ZONE_UIN, zoneUIN); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_RECORDS); List list = new ArrayList(count); long varId = NXCPCodes.VID_USM_CRED_LIST_BASE; for(int i = 0; i < count; i++, varId += 10) { list.add(new SnmpUsmCredential(response, varId)); } return list; } /** * Update list of well-known SNMP USM credentials on server. Existing list will be replaced by provided one. * * @param zoneUIN Zone UIN (unique identification number) * @param usmCredentials List of SNMP credentials * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void updateSnmpUsmCredentials(int zoneUIN, List usmCredentials) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_USM_CREDENTIALS); msg.setFieldInt32(NXCPCodes.VID_ZONE_UIN, zoneUIN); long varId = NXCPCodes.VID_USM_CRED_LIST_BASE; for(SnmpUsmCredential element : usmCredentials) { element.fillMessage(msg, varId); varId += 10; } msg.setFieldInt32(NXCPCodes.VID_NUM_RECORDS, usmCredentials.size()); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get SSH credentials for all zones. * * @return list of SSH credentials for all zones * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public Map> getSshCredentials() throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_SSH_CREDENTIALS); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); Map> credentials = new HashMap>(count); if (count > 0) { List zoneCredentials = new ArrayList(); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; int currentZoneUIN = response.getFieldAsInt32(fieldId); for(int i = 0; i < count; i++, fieldId += 10) { int zoneUIN = response.getFieldAsInt32(fieldId); if (zoneUIN != currentZoneUIN) { credentials.put(currentZoneUIN, zoneCredentials); zoneCredentials = new ArrayList(); } zoneCredentials.add(new SSHCredentials(response, fieldId + 1)); } credentials.put(currentZoneUIN, zoneCredentials); } return credentials; } /** * Get SSH credentials for specific zone. * * @param zoneUIN zone UIN * @return list of SSH credentials for specific zone * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getSshCredentials(int zoneUIN) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_SSH_CREDENTIALS); msg.setFieldInt32(NXCPCodes.VID_ZONE_UIN, zoneUIN); sendMessage(msg); NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_ELEMENTS); List credentials = new ArrayList(count); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(int i = 0; i < count; i++, fieldId += 10) credentials.add(new SSHCredentials(response, fieldId)); return credentials; } /** * Update list of well-known SSH credentials on the server. Existing list will be replaced by the provided one. * * @param zoneUIN Zone UIN (unique identification number) * @param sshCredentials List of SSH credentials * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void updateSshCredentials(int zoneUIN, List sshCredentials) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_SSH_CREDENTIALS); msg.setFieldInt32(NXCPCodes.VID_ZONE_UIN, zoneUIN); long fieldId = NXCPCodes.VID_ELEMENT_LIST_BASE; for(SSHCredentials element : sshCredentials) { element.fillMessage(msg, fieldId); fieldId += 10; } msg.setFieldInt32(NXCPCodes.VID_NUM_ELEMENTS, sshCredentials.size()); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get agent's master configuration file. * * @param nodeId Node ID * @return Master configuration file of agent running on given node * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public String readAgentConfigurationFile(long nodeId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_READ_AGENT_CONFIG_FILE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); return response.getFieldAsString(NXCPCodes.VID_CONFIG_FILE); } /** * Update agent's master configuration file. * * @param nodeId Node ID * @param config New configuration file content * @param apply Apply flag - if set to true, agent will restart automatically to * apply changes * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public void writeAgentConfigurationFile(long nodeId, String config, boolean apply) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_WRITE_AGENT_CONFIG_FILE); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setField(NXCPCodes.VID_CONFIG_FILE, config); msg.setFieldInt16(NXCPCodes.VID_APPLY_FLAG, apply ? 1 : 0); sendMessage(msg); waitForRCC(msg.getMessageId()); } /** * Get list of parameters supported by entity defined by origin on given node. * * @param nodeId Node ID * @param origin data origin (agent, driver, etc.) * @return List of parameters supported by agent * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getSupportedParameters(long nodeId, DataOrigin origin) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_PARAMETER_LIST); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt16(NXCPCodes.VID_FLAGS, 0x01); // Indicates request for parameters list msg.setFieldInt16(NXCPCodes.VID_DCI_SOURCE_TYPE, origin.getValue()); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_PARAMETERS); List list = new ArrayList(count); long baseId = NXCPCodes.VID_PARAM_LIST_BASE; for(int i = 0; i < count; i++) { list.add(new AgentParameter(response, baseId)); baseId += 3; } return list; } /** * Get list of parameters supported by agent running on given node. * * @param nodeId Node ID * @return List of parameters supported by agent * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getSupportedParameters(long nodeId) throws IOException, NXCException { return getSupportedParameters(nodeId, DataOrigin.AGENT); } /** * Get list of tables supported by agent running on given node. * * @param nodeId Node ID * @return List of tables supported by agent * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List getSupportedTables(long nodeId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_PARAMETER_LIST); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)nodeId); msg.setFieldInt16(NXCPCodes.VID_FLAGS, 0x02); // Indicates request for table list msg.setFieldInt16(NXCPCodes.VID_DCI_SOURCE_TYPE, DataOrigin.AGENT.getValue()); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_TABLES); List list = new ArrayList(count); long baseId = NXCPCodes.VID_TABLE_LIST_BASE; for(int i = 0; i < count; i++) { list.add(new AgentTable(response, baseId)); baseId += response.getFieldAsInt64(baseId); } return list; } /** * Get all events used in data collection by given node, cluster, or template object. * * @param objectId node, cluster, or template object ID * @return list of used event codes * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public long[] getRelatedEvents(long objectId) throws IOException, NXCException { final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_RELATED_EVENTS_LIST); msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int)objectId); sendMessage(msg); final NXCPMessage response = waitForRCC(msg.getMessageId()); if (response.getFieldAsInt32(NXCPCodes.VID_NUM_EVENTS) == 0) return new long[0]; return response.getFieldAsUInt32Array(NXCPCodes.VID_EVENT_LIST); } /** * Get names of all scripts used in data collection by given node, cluster, or template object. * * @param objectId node, cluster, or template object ID * @return list of used library scripts * @throws IOException if socket I/O error occurs * @throws NXCException if NetXMS server returns an error or operation was timed out */ public List