Location Service
The Location Service handles component (i.e., Applications, Sequencers, Assemblies, HCDs, and Services) registration and discovery in the distributed TMT software system.
The CSW Location Service cluster must be running, and appropriate environment variables set to run apps. See CSW Location Server.
A component’s location information can be used by other components and services to connect to it and use it. An example of location information is:
- host address/port pairs
- URL/URIs paths
- connection protocols
Dependencies
To use the Location Service without using the framework, add this to your build.sbt
file:
- sbt
-
libraryDependencies += "com.github.tmtsoftware.csw" %% "csw-location-server" % "5.0.1"
Create Location Service
Note that before using this API, the csw-location-server application should be running at a known location in the network (or at multiple locations) and the necessary configuration, environment variables or system properties should be defined to point to the correct host and port number(s).
LocationServiceFactory
provides a make method to create an instance of the LocationService API. This call will look for configuration or environment variable settings.
- Scala
-
source
private val locationService = HttpLocationServiceFactory.makeLocalClient(typedSystem)
- Java
-
source
private final akka.actor.ActorSystem system = context().system(); private final ILocationService locationService = JHttpLocationServiceFactory.makeLocalClient(Adapter.toTyped(system));
Creating Components, Connections and Registrations
An Application, Sequencer, Assembly, HCD, or Service may need to be used by another component as part of normal observatory operations. It must register its location information with Location Service so that other components can find it. Location information is comprised of:
-
ComponentId : A component ID consisting of
- ComponentName : a name describing the component.
- ComponentType : such as Container, Sequencer, HCD, Assembly, Service.
-
ConnectionType : the means to reach components. These are categorized as
Akka
,HTTP
, orTcp
type connections.
The location information is stored in the Location Service as Registrations.
Some of the examples of the string representation of a connection are:
- TromboneAssembly-assembly-akka
- TromboneHcd-hcd-akka
- ConfigServer-service-http
- EventService-service-tcp
The register
API takes a Registration
parameter and returns a future registration result. If registration fails for some reason, the returned future will fail with an exception. (Registration will fail if the csw-location-server
application is not running or could not be found, or if the given component name was already registered.)
AkkaRegistrationFactory
can be used to instantiate AkkaRegistration
using AkkaConnection
, Actor Ref
and optional Metadata
. The following example shows registration of both an UnTyped ActorRef and a Typed ActorRef:
- Scala
-
source
// add some dummy registrations for illustrative purposes // dummy http connection val httpPort = 8080 val httpConnection: HttpConnection = HttpConnection( api.models.ComponentId(Prefix(Subsystem.CSW, "configuration"), ComponentType.Service) ) // When no network type is provided in httpRegistration, default is NetworkType.Private val httpRegistration: HttpRegistration = HttpRegistration(httpConnection, httpPort, "path123") private val httpRegResultF: Future[RegistrationResult] = locationService .register(httpRegistration) httpRegResultF .map(httpRegResult => { log.info(s"$httpRegResult successfully registered in location service") }) // When a service wants to register itself on Public network, it can provide NetworkType.Public in httpRegistration val httpRegistrationOnPublicNetwork: HttpRegistration = HttpRegistration(httpConnection, httpPort, "path123", NetworkType.Outside) private val httpRegResultOnPublicNetworkF: Future[RegistrationResult] = locationService.register(httpRegistrationOnPublicNetwork) httpRegResultOnPublicNetworkF .map(httpRegResultOnPublicNetwork => { log.info(s"$httpRegResultOnPublicNetwork successfully registered in location service") }) // ************************************************************************************************************ // import scaladsl adapter to implicitly convert UnTyped ActorRefs to Typed ActorRef[Nothing] import akka.actor.typed.scaladsl.adapter.* // dummy HCD connection val hcdConnection: AkkaConnection = AkkaConnection(api.models.ComponentId(Prefix(Subsystem.NFIRAOS, "hcd1"), ComponentType.HCD)) val hcdRegistration: AkkaRegistration = AkkaRegistrationFactory.make( hcdConnection, context .actorOf( Props(new Actor { override def receive: Receive = { case "print" => log.info("hello world") } }), name = "my-actor-1" ) .toTyped ) // Register UnTyped ActorRef with Location service. Import scaladsl adapter to implicitly convert // UnTyped ActorRefs to Typed ActorRef[Nothing] private val hcdRegResultF: Future[RegistrationResult] = locationService .register(hcdRegistration) hcdRegResultF .map(hcdRegResult => { log.info(s"$hcdRegResult successfully registered in location service") }) // ************************************************************************************************************ def behavior(): Behavior[String] = Behaviors.setup { _ => Behaviors.receiveMessage { _ => Behaviors.same } } val typedActorRef: ActorRef[String] = context.system.spawn(behavior(), "typed-actor-ref") val assemblyConnection: AkkaConnection = AkkaConnection( ComponentId(Prefix(Subsystem.NFIRAOS, "assembly1"), ComponentType.Assembly) ) // Register Typed ActorRef[String] with Location Service val assemblyRegistration: AkkaRegistration = AkkaRegistrationFactory.make(assemblyConnection, typedActorRef) private val assemblyRegResultF: Future[RegistrationResult] = locationService .register(assemblyRegistration) assemblyRegResultF .map(assemblyRegResult => { log.info(s"$assemblyRegResult successfully registered in location service") }) - Java
-
source
// dummy http connection HttpConnection httpConnection = new HttpConnection(new ComponentId(new Prefix(JSubsystem.CSW, "configuration"), JComponentType.Service)); // When no network type is provided in httpRegistration, default is JNetworkType.Private HttpRegistration httpRegistration = new HttpRegistration(httpConnection, 8080, "path123"); httpRegResult = locationService.register(httpRegistration).get(); // When a service wants to register itself on Public network, it can provide JNetworkType.Public in httpRegistration HttpRegistration httpRegistrationOnPublicNetwork = new HttpRegistration(httpConnection, 8080, "path123", JNetworkType.Outside); httpRegResultonPublicNetwork = locationService.register(httpRegistrationOnPublicNetwork).get(); // ************************************************************************************************************ // dummy HCD connection AkkaConnection hcdConnection = new AkkaConnection(new ComponentId(new Prefix(JSubsystem.NFIRAOS, "hcd1"), JComponentType.HCD)); ActorRef actorRefUntyped = getContext().actorOf(Props.create(AbstractActor.class, () -> new AbstractActor() { @Override public Receive createReceive() { return ReceiveBuilder.create().build(); } }), "my-actor-1" ); // Register UnTyped ActorRef with Location service. Use javadsl Adapter to convert UnTyped ActorRefs // to Typed ActorRef[Nothing] akka.actor.typed.ActorRef actorRef = Adapter.toTyped(actorRefUntyped); AkkaRegistration hcdRegistration = JAkkaRegistrationFactory.make(hcdConnection, actorRef); hcdRegResult = locationService.register(hcdRegistration).get(); // ************************************************************************************************************ Behavior<String> behavior = Behaviors.setup(ctx -> Behaviors.same()); akka.actor.typed.ActorRef<String> typedActorRef = Adapter.spawn(context(), behavior, "typed-actor-ref"); AkkaConnection assemblyConnection = new AkkaConnection(new ComponentId(new Prefix(JSubsystem.NFIRAOS, "assembly1"), JComponentType.Assembly)); // Register Typed ActorRef[String] with Location Service AkkaRegistration assemblyRegistration = JAkkaRegistrationFactory.make(assemblyConnection, typedActorRef); assemblyRegResult = locationService.register(assemblyRegistration).get();
Capability to add metadata while registering connection
Location service supports to add additional information while registering connection. This information is metadata for that registration. Metadata given at point of registration is reflected in location model. This metadata information can be used to store additional info e.g. agentId for any component running on that agent. Metadata field is optional while registration, if not provided location will be reflected with empty metadata
Following example shows adding metadata in HttpRegistration
. Similarly, metadata can be added in AkkaRegistration
as well as TcpRegistration
. Once location is registered Metadata
associated can be used for any computation.
- Scala
-
source
// add some dummy registrations for illustrative purposes // dummy http connection val httpPortForService = 8080 val httpConnectionForService: HttpConnection = HttpConnection( api.models.ComponentId(Prefix(Subsystem.CSW, "configuration"), ComponentType.Service) ) // When no network type is provided in httpRegistration, default is NetworkType.Private val httpRegistrationForService: HttpRegistration = HttpRegistration(httpConnectionForService, httpPortForService, "path123", Metadata(Map("key1" -> "value1"))) private val httpRegResultForServiceF: Future[RegistrationResult] = locationService .register(httpRegistrationForService) httpRegResultForServiceF .map(httpRegResultForService => { log.info(s"$httpRegResultForService successfully registered in location service") })
- Java
-
source
// dummy http connection HttpConnection httpConnectionForService = new HttpConnection(new ComponentId(new Prefix(JSubsystem.CSW, "configuration"), JComponentType.Service)); // When no network type is provided in httpRegistration, default is JNetworkType.Private HttpRegistration httpRegistrationForService = new HttpRegistration(httpConnectionForService, 8080, "path123", new Metadata(Map.of("key1", "value1"))); httpRegResult = locationService.register(httpRegistrationForService).get(); // usage of metadata Map metadataMap = httpRegResult.location().metadata().jValue();
The AkkaRegistration
api takes only Typed ActorRefs. Hence, to register an UnTyped ActorRef for an akka connection, it needs to be adapted to Typed ActorRef[Nothing]
, using adapters provided by Akka. The usage of the adapter is shown in the above snippet for both Scala and Java.
Also, note that for components, the registration will be taken care of via csw-framework
. Hence, component developers won’t register any connections during their development. So, the above demonstration of registering connections is for explanatory and testing purposes only.
Creating ActorRef for Registration
The ActorSystem used to start actors that will be registered in the Location Service must be created using an ActorSystemFactory
as follows:
- Scala
-
source
val typedSystem: typed.ActorSystem[SpawnProtocol.Command] = ActorSystemFactory.remote(SpawnProtocol(), "csw-examples-locationServiceClient")
- Java
-
source
ActorSystem<SpawnProtocol.Command> typedSystem = ActorSystemFactory.remote(SpawnProtocol.create(), "csw" + "-examples-locationServiceClient");
This is required to start a remote ActorSystem on the same network interface where the csw-cluster is running. All the ActorRefs created using this ActorSystem will be available for communication from other components that are part of the CSW Cluster.
Resolving Connections
The list
API returns a list of the currently registered connections from the Location Service.
A connection of interest can be looked up using the resolve
or find
methods:
resolve
gets the location for a connection from the local cache. If not found in the cache, it waits for the event to arrive within the specified time limit and returns None on failure.
find
returns the location for a connection from the local cache and returns None if not immediately found there.
- Scala
-
source
// find connection to LocationServiceExampleComponent in location service // [do this before starting LocationServiceExampleComponent. this should return Future[None]] val exampleConnection: AkkaConnection = LocationServiceExampleComponent.connection log.info( s"Attempting to find $exampleConnection", Map(Keys.OBS_ID -> "foo_obs_id", "exampleConnection" -> exampleConnection.name) ) locationService.find(exampleConnection).map { case Some(findResult) => log.info(s"Result of the find call: $findResult") val akkaLocation = findResult // If the component type is HCD or Assembly, use this to get the correct ActorRef val typedComponentRef: ActorRef[ComponentMessage] = akkaLocation.componentRef // If the component type is Container, use this to get the correct ActorRef val typedContainerRef: ActorRef[ContainerMessage] = akkaLocation.containerRef case None => // do something when nothing is found }
- Java
-
source
// find connection to LocationServiceExampleComponent in location service // [do this before starting LocationServiceExampleComponent. this should return Future[None]] log.info("Attempting to find " + exampleConnection, Map.of( JKeys.OBS_ID, "foo_obs_id", "exampleConnection", exampleConnection.name() )); Optional<AkkaLocation> findResult = locationService.find(exampleConnection).get(); if (findResult.isPresent()) { log.info("Find result: " + connectionInfo(findResult.orElseThrow().connection())); } else { log.info(() -> "Result of the find call : None"); }
The logging output from the above example when the given component is not registered should include:
[INFO] Attempting to find connection AkkaConnection(ComponentId(LocationServiceExampleComponent,Assembly))
[INFO] Result of the find call: None
An example of the resolve command is shown in the following:
- Scala
-
source
// resolve connection to LocationServiceExampleComponent // [start LocationServiceExampleComponent after this command but before timeout] log.info(s"Attempting to resolve $exampleConnection with a wait of $waitForResolveLimit ...") val resolveResultF: Future[Option[AkkaLocation]] = locationService.resolve(exampleConnection, waitForResolveLimit) val resolveResult: Option[AkkaLocation] = Await.result(resolveResultF, waitForResolveLimit + timeout) resolveResult match { case Some(result) => log.info(s"Resolve result: ${locationInfoToString(result)}") case None => log.info(s"Timeout waiting for location $exampleConnection to resolve.") }
- Java
-
source
// resolve connection to LocationServiceExampleComponent // [start LocationServiceExampleComponent after this command but before timeout] Duration waitForResolveLimit = Duration.ofSeconds(30); log.info(() -> "Attempting to resolve " + exampleConnection + " with a wait of " + waitForResolveLimit + ".." + ".", () -> Map.of( JKeys.OBS_ID, "foo_obs_id", "exampleConnection", exampleConnection.name() )); Optional<AkkaLocation> resolveResult = locationService.resolve(exampleConnection, waitForResolveLimit).get(); if (resolveResult.isPresent()) { log.info(() -> "Resolve result: " + connectionInfo(resolveResult.orElseThrow().connection())); } else { log.info(() -> "Timeout waiting for location " + exampleConnection + " to resolve."); }
The logging output from the above example should include:
[INFO] Attempting to resolve AkkaConnection(ComponentId(LocationServiceExampleComponent,Assembly)) with a wait of 30 seconds ...
If you then start the LocationServiceExampleComponentApp, the following message will be logged:
[INFO] Resolve result: LocationServiceExampleComponent-assembly-akka, component type=Assembly, connection type=AkkaType
If not, eventually the operation will timeout and the output should read:
[INFO] Timeout waiting for location AkkaConnection(ComponentId(LocationServiceExampleComponent,Assembly)) to resolve.
The resolve
and find
api returns the concrete Location
type i.e. Akkalocation
, HttpLocation
or TcpLocation
as demonstrated in this section. Once the Akka location is found or resolved, we need to ascribe the type to the ActorRef, since the explicit type annotation is removed from the program before it is executed at run-time (see type erasure). Use following AkkaLocation
API to get the correct Typed ActorRef:
- Scala
-
source
// If the component type is HCD or Assembly, use this to get the correct ActorRef val typedComponentRef: ActorRef[ComponentMessage] = akkaLocation.componentRef // If the component type is Container, use this to get the correct ActorRef val typedContainerRef: ActorRef[ContainerMessage] = akkaLocation.containerRef
- Java
-
source
// If the component type is HCD or Assembly, use this to get the correct ActorRef akka.actor.typed.ActorRef<ComponentMessage> typedComponentRef = AkkaLocationExt.RichAkkaLocation(akkaLocation).componentRef(typedSystem); // If the component type is Container, use this to get the correct ActorRef akka.actor.typed.ActorRef<ContainerMessage> typedContainerRef = AkkaLocationExt.RichAkkaLocation(akkaLocation).containerRef(typedSystem);
Filtering
The list
API and its variants offer means to inquire about available connections with the Location Service. The parameter-less list
returns all available connections
- Scala
-
source
// list connections in location service locationService.list.map(connectionList => { log.info("All Registered Connections:") connectionList.foreach(c => log.info(s"--- ${locationInfoToString(c)}")) })
- Java
-
source
// list connections in location service List<Location> connectionList = locationService.list().get(); log.info("All Registered Connections:"); for (Location loc : connectionList) { log.info("--- " + connectionInfo(loc.connection())); }
The log output from the above should contain:
[INFO] All Registered Connections:
[INFO] --- configuration-service-http, component type=Service, connection type=HttpType
[INFO] --- hcd1-hcd-akka, component type=HCD, connection type=AkkaType
[INFO] --- LocationServiceExampleComponent-assembly-akka, component type=Assembly, connection type=AkkaType
[INFO] --- redis-service-tcp, component type=Service, connection type=TcpType
[INFO] --- assembly1-assembly-akka, component type=Assembly, connection type=AkkaType
Other variants are filters using ConnectionType
, ComponentType
, and hostname
.
Filtering by component type is shown below:
- Scala
-
source
// filter connections based on component type locationService .list(ComponentType.Assembly) .map(componentList => { log.info("Registered Assemblies:") componentList.foreach(c => log.info(s"--- ${locationInfoToString(c)}")) })
- Java
-
source
// filter connections based on component type List<Location> componentList = locationService.list(JComponentType.Assembly).get(); log.info("Registered Assemblies:"); for (Location loc : componentList) { log.info("--- " + connectionInfo(loc.connection())); }
The log output from the above code should contain:
[INFO] Registered Assemblies:
[INFO] --- LocationServiceExampleComponent-assembly-akka, component type=Assembly, connection type=AkkaType
[INFO] --- assembly1-assembly-akka, component type=Assembly, connection type=AkkaType
Filtering by connection type is shown below:
- Scala
-
source
// filter connections based on connection type locationService .list(ConnectionType.AkkaType) .map(akkaList => { log.info("Registered Akka connections:") akkaList.foreach(c => log.info(s"--- ${locationInfoToString(c)}")) })
- Java
-
source
// filter connections based on connection type List<Location> akkaList = locationService.list(JConnectionType.AkkaType).get(); log.info("Registered Akka connections:"); for (Location loc : akkaList) { log.info("--- " + connectionInfo(loc.connection())); }
The log output should contain:
[INFO] Registered Akka connections:
[INFO] --- hcd1-hcd-akka, component type=HCD, connection type=AkkaType
[INFO] --- LocationServiceExampleComponent-assembly-akka, component type=Assembly, connection type=AkkaType
[INFO] --- assembly1-assembly-akka, component type=Assembly, connection type=AkkaType
Filtering akka connections by prefix is shown below:
- Scala
-
source
// filter akka locations based on prefix locationService .listByPrefix("NFIRAOS.ncc") .map(akkaLocations => { log.info("Registered akka locations for nfiraos.ncc") akkaLocations.foreach(c => log.info(s"--- ${locationInfoToString(c)}")) })
- Java
-
source
List<Location> locations = locationService.listByPrefix("NFIRAOS.ncc").get(); log.info("Registered akka locations for nfiraos.ncc"); for (Location loc : locations) { log.info("--- " + connectionInfo(loc.connection())); }
The log output should contain:
[INFO] Registered akka locations for nfiraos.ncc
[INFO] --- nfiraos.ncc.hcd1-hcd-akka, component type=HCD, connection type=AkkaType
[INFO] --- nfiraos.ncc.assembly1-assembly-akka, component type=Assembly, connection type=AkkaType
Tracking and Subscribing
The lifecycle of a connection of interest can be followed using either the track
API or the subscribe
API.
These methods take a Connection
instance as a parameter. A Connection
need not already be registered with Location Service. It’s okay to track connections that will be registered in future.
The track
API returns two values:
* A source that will emit a stream of TrackingEvents
for the connection.
* A KillSwitch to turn off the stream when no longer needed.
The Akka stream API provides many building blocks to process this stream, such as Flow and Sink. In the example below, Sink.actorRef
is used to forward any location messages received to the current actor (self).
A consumer can shut down the stream using the KillSwitch.
The subscribe
API allows the caller to track a connection and receive the TrackingEvent notifications via a callback.
The API expects following parameters:
* An existing connection or a connection to be registered in the future.
* A callback that implements Consumer
and receives the TrackEvent as a parameter.
Callbacks are not thread-safe on the JVM. If you are doing side effects/mutations inside the callback, you should ensure that it is done in a thread-safe way inside an actor. Here is an example of how it can be done.
This API returns a KillSwitch that can be used to turn off the event notifications and release the supplied callback, if required.
- Scala
-
source
def sinkBehavior: Behaviors.Receive[ExampleMessages] = Behaviors.receive[ExampleMessages] { (ctx, msg) => { val log: Logger = new LoggerFactory(Prefix("csw.my-component-name")).getLogger(ctx) msg match { case TrackingEventAdapter(LocationUpdated(loc)) => log.info(s"Location updated ${locationInfoToString(loc)}") case TrackingEventAdapter(LocationRemoved(conn)) => log.warn(s"Location removed $conn", Map("connection" -> conn.toString)) case AllDone(exampleConnection) => log.info(s"Tracking of $exampleConnection complete.") case CustomException(throwable) => log.error(throwable.getMessage, ex = throwable) } Behaviors.same } } // the following two methods are examples of two ways to track a connection. // both are implemented but only one is really needed. // Method1: track connection to LocationServiceExampleComponent // Calls track method for example connection and forwards location messages to this actor // log.info(s"Starting to track $exampleConnection") val sinfActorRef = typedSystem.spawn(LocationServiceExampleClient.sinkBehavior, "") locationService .track(exampleConnection) .map(TrackingEventAdapter) .to(ActorSink.actorRef[ExampleMessages](sinfActorRef, AllDone(exampleConnection), CustomException)) .run() // track returns a Killswitch, that can be used to turn off notifications arbitarily // in this case track a connection for 5 seconds, after that schedule switching off the stream val killswitch = locationService .track(httpConnection) .toMat(Sink.foreach(println))(Keep.left) .run() context.system.scheduler.scheduleOnce(5.seconds) { killswitch.cancel() } // Method2: subscribe to LocationServiceExampleComponent events log.info(s"Starting a subscription to $exampleConnection") locationService.subscribe( exampleConnection, trackingEvent => { // the following println is to distinguish subscription events from tracking events log.info("subscription event") self ! trackingEvent } )
- Java
-
source
// the following two methods are examples of two ways to track a connection. // both are implemented but only one is really needed. // track connection to LocationServiceExampleComponent // Calls track method for example connection and forwards location messages to this actor log.info("Starting to track " + exampleConnection); locationService.track(exampleConnection).toMat(Sink.actorRef(getSelf(), AllDone.class), Keep.both()).run(typedSystem); //track returns a Killswitch, that can be used to turn off notifications arbitarily //in this case track a connection for 5 seconds, after that schedule switching off the stream Pair pair = locationService.track(exampleConnection).toMat(Sink.ignore(), Keep.both()).run(typedSystem); context().system().scheduler().scheduleOnce( Duration.ofSeconds(5), () -> ((KillSwitch) pair.first()).shutdown(), context().system().dispatcher()); // subscribe to LocationServiceExampleComponent events log.info("Starting a subscription to " + exampleConnection); locationService.subscribe(exampleConnection, trackingEvent -> { log.info("subscription event"); getSelf().tell(trackingEvent, ActorRef.noSender()); });
The log output should contain the following:
[INFO] Starting to track AkkaConnection(ComponentId(LocationServiceExampleComponent,Assembly)) LocationUpdated(HttpLocation(HttpConnection(ComponentId(configuration,Service)),http://131.215.210.170:8080/path123))
[INFO] Starting a subscription to AkkaConnection(ComponentId(LocationServiceExampleComponent,Assembly))
[INFO] Subscribing to connection LocationServiceExampleComponent-assembly-akka
[INFO] Location updated LocationServiceExampleComponent-assembly-akka, component type=Assembly, connection type=AkkaType
[INFO] subscription event
[INFO] Location updated LocationServiceExampleComponent-assembly-akka, component type=Assembly, connection type=AkkaType
If you now stop the LocationServiceExampleComponentApp, it would log:
[INFO] subscription event
[INFO] Location removed AkkaConnection(ComponentId(LocationServiceExampleComponent,Assembly))
[INFO] Location removed AkkaConnection(ComponentId(LocationServiceExampleComponent,Assembly))
If you start the LocationServiceExampleComponentApp again, the log output should be:
[INFO] subscription event
[INFO] Location updated LocationServiceExampleComponent-assembly-akka, component type=Assembly, connection type=AkkaType
[INFO] Location updated LocationServiceExampleComponent-assembly-akka, component type=Assembly, connection type=AkkaType
Note: the line after the words “subscription event” in our example is generated by the subscription, and the other line is from tracking. These two events could come in any order.
Unregistering
One of the ways to unregister
a service is by calling unregister on registration result received from register
API.
- Scala
-
source
val unregisterF = async { await(httpRegResultF.map(_.unregister())) await(httpRegResultOnPublicNetworkF.map(_.unregister())) await(hcdRegResultF.map(_.unregister())) await(assemblyRegResultF.map(_.unregister())) }.flatten val eventualDone = async { await(unregisterF)
- Java
-
source
httpRegResult.unregister(); httpRegResultonPublicNetwork.unregister(); hcdRegResult.unregister(); assemblyRegResult.unregister();
Protected Routes
The following Location Server routes are Protected
. To use these routes, the user must be authenticated and authorized with location-admin
role.
- register
- unregister
- unregisterAll
Refer to csw-aas docs to know more about how to authenticate and authorize with AAS and get an access token.
Technical Description
See Location Service Technical Description.