/*_############################################################################
  _## 
  _##  SNMP4J - Session.java  
  _## 
  _##  Copyright (C) 2003-2026  Frank Fock (SNMP4J.org)
  _##  
  _##  Licensed under the Apache License, Version 2.0 (the "License");
  _##  you may not use this file except in compliance with the License.
  _##  You may obtain a copy of the License at
  _##  
  _##      http://www.apache.org/licenses/LICENSE-2.0
  _##  
  _##  Unless required by applicable law or agreed to in writing, software
  _##  distributed under the License is distributed on an "AS IS" BASIS,
  _##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  _##  See the License for the specific language governing permissions and
  _##  limitations under the License.
  _##  
  _##########################################################################*/
package org.snmp4j;

import org.snmp4j.event.*;
import org.snmp4j.smi.Address;

import java.io.Closeable;
import java.io.IOException;

/**
 * {@code Session} defines a common interface for all classes that
 * implement SNMP protocol operations based on SNMP4J.
 *
 * @author Frank Fock
 * @version 3.1.0
 */
public interface Session extends Closeable {

    /**
     * Closes the session and frees any allocated resources, i.e. sockets.
     * After a {@code Session} has been closed it must
     * be used.
     *
     * @throws IOException
     *         if the session could not free all resources.
     */
    public void close() throws IOException;

    /**
     * Sends a {@code PDU} to the given target and returns the received
     * response {@code PDU}.
     *
     * @param pdu
     *         the {@code PDU} to send.
     * @param target
     *         the {@code Target} instance that specifies how and where to send
     *         the PDU.
     * @param <A> the {@link Address} type of target and response (i.e., must be the same)
     *
     * @return the received response encapsulated in a {@code ResponseEvent}
     * instance. To obtain the received response {@code PDU} call
     * {@link ResponseEvent#getResponse()}. If the request timed out,
     * that method will return {@code null}. If the sent {@code pdu}
     * is an unconfirmed PDU (notification, response, or report), then
     * {@code null} will be returned.
     * @throws IOException
     *         if the message could not be sent.
     */
    public <A extends Address> ResponseEvent<A> send(PDU pdu, Target<A> target) throws IOException;

    /**
     * Asynchronously sends a {@code PDU} to the given target. The response
     * is then returned by calling the supplied {@code ResponseListener}
     * instance.
     *
     * @param pdu
     *         the PDU instance to send.
     * @param target
     *         the Target instance representing the target SNMP engine where to send
     *         the {@code pdu}.
     * @param userHandle
     *         an user defined handle that is returned when the request is returned
     *         via the {@code listener} object.
     * @param listener
     *         a {@code ResponseListener} instance that is called when
     *         {@code pdu} is a confirmed PDU and the request is either answered
     *         or timed out.
     * @param <A> the {@link Address} type of target and response (i.e., must be the same)
     *
     * @throws IOException
     *         if the message could not be sent.
     */
    <A extends Address> void send(PDU pdu, Target<A> target, Object userHandle, ResponseListener listener)
            throws IOException;

    /**
     * Sends a {@code PDU} to the given target and returns the received
     * response {@code PDU} encapsulated in a {@code ResponseEvent}
     * object that also includes:
     * <ul>
     * <li>the transport address of the response sending peer,
     * <li>the {@code Target} information of the target,
     * <li>the request {@code PDU},
     * <li>the response {@code PDU} (if any).
     * </ul>
     *
     * @param pdu
     *         the PDU instance to send.
     * @param target
     *         the Target instance representing the target SNMP engine where to send
     *         the {@code pdu}.
     * @param transport
     *         specifies the {@code TransportMapping} to be used when sending
     *         the PDU. If {@code transport} is {@code null}, the associated
     *         message dispatcher will try to determine the transport mapping by the
     *         {@code target}'s address.
     * @param <A> the target {@link Address} type.
     *
     * @return the received response encapsulated in a {@code ResponseEvent}
     * instance. To obtain the received response {@code PDU} call
     * {@link ResponseEvent#getResponse()}. If the request timed out,
     * that method will return {@code null}. If the sent {@code pdu}
     * is an unconfirmed PDU (notification, response, or report), then
     * {@code null} will be returned.
     * @throws IOException
     *         if the message could not be sent.
     */
    <A extends Address> ResponseEvent<A> send(PDU pdu, Target<A> target, TransportMapping<? super A> transport)
            throws IOException;

    /**
     * Asynchronously sends a {@code PDU} to the given target. The response
     * is then returned by calling the supplied {@code ResponseListener}
     * instance.
     *
     * @param pdu
     *         the PDU instance to send.
     * @param target
     *         the Target instance representing the target SNMP engine where to send
     *         the {@code pdu}.
     * @param transport
     *         specifies the {@code TransportMapping} to be used when sending
     *         the PDU. If {@code transport} is {@code null}, the associated
     *         message dispatcher will try to determine the transport mapping by the
     *         {@code target}'s address.
     * @param userHandle
     *         an user defined handle that is returned when the request is returned
     *         via the {@code listener} object.
     * @param listener
     *         a {@code ResponseListener} instance that is called when
     *         {@code pdu} is a confirmed PDU and the request is either answered
     *         or timed out.
     * @param <A> the target {@link Address} type.
     *
     * @throws IOException
     *         if the message could not be sent.
     */
    <A extends Address> void send(PDU pdu, Target<A> target, TransportMapping<? super A> transport, Object userHandle,
              ResponseListener listener) throws IOException;


    /**
     * Cancels an asynchronous request. Any asynchronous request must be canceled
     * when the supplied response listener is being called, even if the
     * {@code ResponseEvent} indicates an error.
     *
     * @param request
     *         a request PDU as sent via {@link #send(PDU pdu, Target target,
     *         Object userHandle, ResponseListener listener)} or any .
     * @param listener
     *         a ResponseListener instance.
     */
    void cancel(PDU request, ResponseListener listener);

    /**
     * Sets the local engine ID for the SNMP entity represented by this
     * {@code Snmp} instance. This is a convenience method that sets
     * the local engine ID in the associated {@code MPv3} and
     * {@code USM}.
     *
     * @param engineID
     *         a byte array containing the local engine ID. The length and content
     *         has to comply with the constraints defined in the SNMP-FRAMEWORK-MIB.
     * @param engineBoots
     *         the number of boots of this SNMP engine (zero-based).
     * @param engineTime
     *         the number of seconds since the value of engineBoots last changed.
     *
     * @since 3.0
     */
    public void setLocalEngine(byte[] engineID, int engineBoots, int engineTime);

    /**
     * Gets the local engine ID if the MPv3 is available, otherwise a runtime
     * exception is thrown.
     *
     * @return byte[]
     *          the local engine ID.
     * @since 3.0
     */
    byte[] getLocalEngineID();
}

