package aQute.remote.api;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.osgi.framework.dto.BundleDTO;
import org.osgi.framework.dto.FrameworkDTO;
import org.osgi.framework.wiring.dto.BundleRevisionDTO;
/**
* An agent runs on remote OSGi framework and provides the means to control this
* framework. This API can also be used to install a framework before an agent
* is started. Such a pre-agent is called an Envoy. An Envoy implements
* {@link #createFramework(String, Collection, Map)} and {@link #isEnvoy()} only
* but switches to the agent API once the framework is installed.
*/
public interface Agent {
/**
* The default port. The port can be overridden with the System/framework
* property {$value {@link #AGENT_SERVER_PORT_KEY}.
*/
int DEFAULT_PORT = 29998;
/**
* The property key to set the agent's port.
*/
String AGENT_SERVER_PORT_KEY = "aQute.agent.server.port";
/**
* The pattern for a server port specification: {@code [<interface>:]<port>}
* .
*/
Pattern PORT_P = Pattern.compile("(?:([^:]+):)?(\\d+)");
/**
* The port for attaching to a remote Gogo CommandSession
*/
int COMMAND_SESSION = -1;
/**
* The port for having no redircet of IO
*/
int NONE = 0;
/**
* The port for System.in, out, err redirecting.
*/
int CONSOLE = 1;
/**
* An Envoy is an agent that can install a framework (well, -runpath) and
* launch it with an Agent. An envoy can only handle this method and
* {@link #createFramework(String, Collection, Map)} so other methods should
* not be called. This rather awkward model is necessary so that we do not
* have to reconnect to the actual agent.
*
* @return true if this is a limited envoy, otherwise true for a true Agent.
*/
boolean isEnvoy();
/**
* Get the Bundles for the given ids. If no ids are given, all bundles are
* returned.
*/
List<BundleDTO> getBundles(long... bundleId) throws Exception;
/**
* Get the Bundle Revisions for the given ids. If no ids are given, the
* revisions for all bundles must be returned.
*/
List<BundleRevisionDTO> getBundleRevisons(long... bundleId) throws Exception;
/**
* Get the framework DTO
*/
FrameworkDTO getFramework() throws Exception;
/**
* Install a new bundle at the given bundle location. The SHA identifies the
* file and should be retrievable through {@link Supervisor#getFile(String)}
* .
*
* @param location the bundle location
* @param sha the sha of the bundle's JAR
* @return A Bundle DTO
*/
BundleDTO install(String location, String sha) throws Exception;
/**
* Install a new bundle at the given location using a url to get the stream.
* <p>
* <b>NOTICE:</b> this method makes assumptions about the target e.g. that
* it will be able to use out-of-band communication to read from the URL and
* have the necessary url handlers to open the URL stream.
* </p>
*
* @param location the bundle location
* @param url url of the bundle that can retrived using url.openStream()
* @return A bundle DTO
*/
BundleDTO installFromURL(String location, String url) throws Exception;
/**
* Start a number of bundles
*
* @param id the bundle ids
* @return any errors that occurred
*/
String start(long... id) throws Exception;
/**
* Stop a number of bundles
*
* @param id the bundle ids
* @return any errors that occurred
*/
String stop(long... id) throws Exception;
/**
* Uninstall a number of bundles
*
* @param id the bundle ids
* @return any errors that occurred
*/
String uninstall(long... id) throws Exception;
/**
* Update the bundles in the framework. Each agent compares this map against
* a map of installed bundles. The map maps a bundle location to SHA. Any
* differences are reflected in the installed bundles. That is, a change in
* the SHA will update, a new entry will install, and a removed entry will
* uninstall. This is the preferred way to keep the remote framework
* synchronized since it is idempotent.
*
* @param bundles the bundles to update
*/
String update(Map<String,String> bundles) throws Exception;
/**
* Updates a single bundle by id in the framework. The SHA identifies the
* file and should be retrievable through {@link Supervisor#getFile(String)}
*
* @param id the bundle id
* @param sha the sha of the bundle
* @return any errors that occurred
*/
String update(long id, String sha) throws Exception;
/**
* Updates a single bundle from a url
* <p>
* <b>NOTICE:</b> this method makes assumptions about the target e.g. that
* it will be able to use out-of-band communication to read from the URL and
* have the necessary url handlers to open the URL stream.
* </p>
*
* @param id bundle to update
* @param url location of bundle contents
* @return any errors that occurred
*/
String updateFromURL(long id, String url) throws Exception;
/**
* Redirect I/O from port. Port can be {@link #CONSOLE},
* {@link #COMMAND_SESSION}, {@link #NONE}, or a TCP Telnet port.
*
* @param port the port to redirect from
* @return if the redirection was changed
*/
boolean redirect(int port) throws Exception;
/**
* Send a text to the potentially redirected stdin stream so that remotely
* executing code will read it from an InputStream.
*
* @param s text that should be read as input
* @return true if this was redirected
*/
boolean stdin(String s) throws Exception;
/**
* Execute a remote command on Gogo (if present) and return the result.
*
* @param cmd the command to execute
* @return the result
*/
String shell(String cmd) throws Exception;
/**
* Get the remote's system's System properties
*
* @return the remote systems properties
*/
Map<String,String> getSystemProperties() throws Exception;
/**
* This method is only implemented in the Envoy (the pre-Agent). It is meant
* to install a -runpath before the framework runs. An Envoy can actally
* created multiple independent frameworks. If this framework already
* existed, and the given parameters are identical, that framework will be
* used for the aget that will take over. Otherwise the current framework is
* stopped and a new framework is started.
*
* @param name the name of the framework
* @param runpath the runpath the install
* @param properties the framework properties
* @return if this created a new framework
*/
boolean createFramework(String name, Collection<String> runpath, Map<String,Object> properties) throws Exception;
/**
* Abort the remote agent. The agent should send an event back and die. This
* is an async method.
*/
void abort() throws Exception;
/**
* Ping the remote agent to see if it is still alive.
*/
boolean ping();
}