Skip to content

Commit

Permalink
[core] Add the SRE utility class and the SREBootstrap.
Browse files Browse the repository at this point in the history
These classes enables to launch a SARL run-time environment (SRE)
programmatically, without having a explicit dependency to the SRE
implementation library.

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Sep 12, 2017
1 parent f98c7d5 commit 0275037
Show file tree
Hide file tree
Showing 4 changed files with 381 additions and 0 deletions.
206 changes: 206 additions & 0 deletions main/apiplugins/io.sarl.core/src/io/sarl/core/bootstrap.sarl
@@ -0,0 +1,206 @@
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 the original authors or authors.
*
* 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 io.sarl.core

import java.lang.ref.SoftReference
import java.util.ServiceLoader
import java.util.UUID
import io.sarl.lang.core.Agent

/**
* Represents an access point to the SARL run-time environment (SRE).
* This access point may be used for accessing the underlying SRE independently of its implementation.
*
* <p>Depending on the implementation of the SRE, an instance of this SRE access point could be injected.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.6
*/
interface SREBootstrap {

/**
* Launch the SRE and the first agent in the kernel.
*
* <p>The function {@link #getBootAgentIdentifier()} permits to retrieve the identifier of the launched agent.
*
* @param agentCls - type of the first agent to launch.
* @param params - parameters to pass to the agent as its initialization parameters.
* @return the identifier of the created agent.
* @throws Exception - if it is impossible to start the platform.
* @see #getBootAgentIdentifier()
*/
def startAgent(agentCls : Class<? extends Agent>, params : Object*) : UUID throws Exception

/**
* Launch the SRE and the first agent in the kernel.
*
* <p>The function {@link #getBootAgentIdentifier()} permits to retrieve the identifier of the launched agent.
*
* @param nbAgents - the number of agents to be launched.
* @param agentCls - type of the first agent to launch.
* @param params - parameters to pass to the agent as its initialization parameters.
* @return the identifiers of the created agents.
* @throws Exception - if it is impossible to start the platform.
* @see #getBootAgentIdentifier()
*/
def startAgent(nbAgents : int, agentCls : Class<? extends Agent>, params : Object*) : Iterable<UUID> throws Exception

/**
* Replies the identifier of the boot agent from the system's properties. The boot agent is launched with
* {@link #startAgent(int, Class, Object...)}.
*
* @return the identifier of the boot agent, or <code>null</code> if it is unknown.
* @see #startAgent(int, Class, Object...)
*/
def getBootAgentIdentifier : UUID

/** Replies if the bootstrap could be used.
*
* <p>If the bootstrap cannot be used, it cannot launch agent.
*
* @return {@code true} if the bootstrap could be used. {@code false} if it cannot be used.
*/
def isActive : boolean { true }
}

/**
* Represents an access point to the SARL run-time environment (SRE).
* This access point may be used for accessing the underlying SRE independently of its implementation.
*
* <p>Depending on the implementation of the SRE, an instance of this SRE access point could be injected.
*
* <p>For declaring a SRE bootstrap, the library that contains the contributing SRE must declared
* a specific service implementation of {@link SREBootstrap}. The declaration of this service must be
* done by creating a file into the folder {@code META-INF/services/io.sarl.lang.core.SREBootstrap}.
* This file contains a single line that is the fully qualified name of the {@link SREBootstrap}'s implementation.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.6
* @see ServiceLoader
*/
final class SRE {

static var currentSRE : SREBootstrap

static var loader : SoftReference<ServiceLoader<SREBootstrap>>

private new {
}

/** Reset the service loader for the SRE bootstrap.
*/
static def resetServiceLoader() : void {
synchronized (typeof(SRE)) {
loader = null
}
}

/** Replies all the installed SRE into the classpath.
*
* @param onlyInstalledInJRE indicates if the services will be considered only into the libraries that are
* installed into the JRE. If {@code true}, only the libraries into the JRE will be considered and
* the application libraries will be ignored. If {@code false}, the application libraries will be
* considered as well.
* @return the installed SRE.
*/
static def getServiceLoader(onlyInstalledInJRE : boolean = false) : ServiceLoader<SREBootstrap> {
synchronized (typeof(SRE)) {
var sl = if (loader === null) null else loader.get
if (sl === null) {
if (onlyInstalledInJRE) {
sl = ServiceLoader::loadInstalled(typeof(SREBootstrap))
} else {
sl = ServiceLoader::load(typeof(SREBootstrap))
}
loader = new SoftReference(sl)
}
return sl
}
}

/** Change the current SRE.
*
* @param sre the current SRE.
*/
static def setBootstrap(sre : SREBootstrap) {
synchronized (typeof(SRE)) {
currentSRE = sre
}
}

/** Find and reply the current SRE.
*
* @return the current SRE, never {@code null}.
* @throws IllegalStateException if a SRE cannot be found.
*/
static def getBootstrap : SREBootstrap {
synchronized (typeof(SRE)) {
if (currentSRE === null) {
val iterator = getServiceLoader.iterator
if (iterator.hasNext) {
currentSRE = iterator.next
} else {
currentSRE = new VoidSREBootstrap
}
}
return currentSRE
}
}

/**
* Private API: not documented.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.6
*/
private static class VoidSREBootstrap implements SREBootstrap {

package new {
}

override startAgent(agentCls : Class<? extends Agent>, params : Object*) : UUID {
throw new UnsupportedOperationException
}

override startAgent(nbAgents : int, agentCls : Class<? extends Agent>, params : Object*) : Iterable<UUID> {
throw new UnsupportedOperationException
}

override getBootAgentIdentifier : UUID {
throw new UnsupportedOperationException
}

override isActive : boolean {
false
}

}

}
@@ -0,0 +1,51 @@
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 the original authors or authors.
*
* 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 io.sarl.core.tests;

import java.util.UUID;

import io.sarl.core.SREBootstrap;
import io.sarl.lang.core.Agent;

/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
public class SREBootstrapMock implements SREBootstrap {

@Override
public UUID startAgent(Class<? extends Agent> agentCls, Object... params) throws Exception {
throw new IllegalStateException();
}

@Override
public Iterable<UUID> startAgent(int nbAgents, Class<? extends Agent> agentCls, Object... params) throws Exception {
throw new IllegalStateException();
}

@Override
public UUID getBootAgentIdentifier() {
throw new IllegalStateException();
}

}
123 changes: 123 additions & 0 deletions tests/io.sarl.core.tests/src/test/java/io/sarl/core/tests/SRETest.java
@@ -0,0 +1,123 @@
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 the original authors or authors.
*
* 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 io.sarl.core.tests;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.UUID;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import io.sarl.core.SRE;
import io.sarl.core.SREBootstrap;
import io.sarl.lang.core.Agent;
import io.sarl.tests.api.AbstractSarlTest;

/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
@SuppressWarnings("all")
public class SRETest extends AbstractSarlTest {

@Before
public void setUp() {
SRE.resetServiceLoader();
SRE.setBootstrap(null);
}

@After
public void tearDown() {
SRE.resetServiceLoader();
SRE.setBootstrap(null);
}

private void installNoService() {
SRE.getServiceLoader(true);
}

private void installService() {
SRE.getServiceLoader(false);
}

@Test
public void getServiceLoader_noService() {
installNoService();
ServiceLoader<SREBootstrap> bootstraps = SRE.getServiceLoader();
assertContains(bootstraps);
}

@Test
public void getServiceLoader_mockedService() {
installService();
ServiceLoader<SREBootstrap> bootstraps = SRE.getServiceLoader();
Iterator<SREBootstrap> iterator = bootstraps.iterator();
SREBootstrap bs = iterator.next();
assertNotNull(bs);
assertInstanceOf(SREBootstrapMock.class, bs);
assertFalse(iterator.hasNext());
}

@Test
public void getBootstrap_noService() throws Exception {
installNoService();
SREBootstrap bs = SRE.getBootstrap();
assertNotNull(bs);
assertFalse(bs.isActive());
try {
bs.startAgent(MyAgent.class);
fail("Expecting exception");
} catch (IllegalStateException | UnsupportedOperationException ex) {
}
try {
bs.startAgent(1, MyAgent.class);
fail("Expecting exception");
} catch (IllegalStateException | UnsupportedOperationException ex) {
}
}

@Test
public void getBootstrap_mockedService() {
installService();
SREBootstrap bs = SRE.getBootstrap();
assertNotNull(bs);
assertTrue(bs.isActive());
assertInstanceOf(SREBootstrapMock.class, bs);
}

private static class MyAgent extends Agent {

public MyAgent(UUID parentID, UUID agentID) {
super(parentID, agentID);
}

}

}
@@ -0,0 +1 @@
io.sarl.core.tests.SREBootstrapMock

0 comments on commit 0275037

Please sign in to comment.