io.janusproject.kernel.services.jdk.contextspace.Context Maven / Gradle / Ivy
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2018 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.janusproject.kernel.services.jdk.contextspace;
import java.text.MessageFormat;
import java.util.UUID;
import com.google.inject.Injector;
import io.janusproject.services.contextspace.SpaceRepositoryListener;
import io.janusproject.services.distributeddata.DistributedDataStructureService;
import io.janusproject.services.logging.LogService;
import io.janusproject.util.TwoStepConstruction;
import io.sarl.core.SpaceCreated;
import io.sarl.core.SpaceDestroyed;
import io.sarl.lang.core.Address;
import io.sarl.lang.core.AgentContext;
import io.sarl.lang.core.EventSpace;
import io.sarl.lang.core.Space;
import io.sarl.lang.core.SpaceID;
import io.sarl.lang.core.SpaceSpecification;
import io.sarl.lang.util.SynchronizedCollection;
import io.sarl.lang.util.SynchronizedIterable;
import io.sarl.util.Collections3;
import io.sarl.util.OpenEventSpace;
import io.sarl.util.OpenEventSpaceSpecification;
/**
* Implementation of an agent context in the Janus platform.
*
* This class is thread-safe.
*
* @author $Author: srodriguez$
* @author $Author: ngaud$
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
@TwoStepConstruction
public class Context implements AgentContext {
private final UUID id;
private final SpaceRepository spaceRepository;
private final UUID defaultSpaceID;
private OpenEventSpace defaultSpace;
/**
* Constructs a Context
.
*
*
CAUTION: Do not miss to call {@link #postConstruction()}.
*
* @param id identifier of the context.
* @param defaultSpaceID identifier of the default space in the context.
* @param factory factory to use for creating the space repository.
* @param startUpListener repository listener which is added just after the creation of the repository, but before the
* creation of the default space.
*/
public Context(UUID id, UUID defaultSpaceID, SpaceRepositoryFactory factory, SpaceRepositoryListener startUpListener) {
assert factory != null;
this.id = id;
this.defaultSpaceID = defaultSpaceID;
this.spaceRepository = factory.newInstance(this, id.toString() + "-spaces", //$NON-NLS-1$
startUpListener);
}
@Override
public String toString() {
return this.id.toString();
}
/**
* Create the default space in this context.
*
* @return the created space.
*/
public EventSpace postConstruction() {
this.spaceRepository.postConstruction();
this.defaultSpace = createSpace(OpenEventSpaceSpecification.class, this.defaultSpaceID);
if (this.defaultSpace == null) {
// The default space could have been created before thanks to Hazelcast,
// thus createSpace returns null because the space already exist,
// in this case we return the already existing default space stored in the SpaceRepository
this.defaultSpace = (OpenEventSpace) this.spaceRepository
.getSpace(new SpaceID(this.id, this.defaultSpaceID, OpenEventSpaceSpecification.class));
}
return this.defaultSpace;
}
/**
* Destroy any associated resources.
*/
public void destroy() {
this.spaceRepository.destroy();
}
@Override
public UUID getID() {
return this.id;
}
@Override
public OpenEventSpace getDefaultSpace() {
return this.defaultSpace;
}
@Override
public SynchronizedIterable getSpaces(Class extends SpaceSpecification> spec) {
final SynchronizedCollection col = this.spaceRepository.getSpaces(spec);
return Collections3.unmodifiableSynchronizedIterable(col, col.mutex());
}
@Override
public SynchronizedIterable extends io.sarl.lang.core.Space> getSpaces() {
final SynchronizedCollection extends io.sarl.lang.core.Space> col = this.spaceRepository.getSpaces();
return Collections3.unmodifiableSynchronizedIterable(col, col.mutex());
}
@Override
public S createSpace(Class extends SpaceSpecification> spec, UUID spaceUUID,
Object... creationParams) {
return this.spaceRepository.createSpace(new SpaceID(this.id, spaceUUID, spec), spec, creationParams);
}
@Override
public S getOrCreateSpaceWithSpec(Class extends SpaceSpecification> spec, UUID spaceUUID,
Object... creationParams) {
return this.spaceRepository.getOrCreateSpaceWithSpec(new SpaceID(this.id, spaceUUID, spec), spec, creationParams);
}
@Override
public S getOrCreateSpaceWithID(Class extends SpaceSpecification> spec, UUID spaceUUID,
Object... creationParams) {
return this.spaceRepository.getOrCreateSpaceWithID(new SpaceID(this.id, spaceUUID, spec), spec, creationParams);
}
@SuppressWarnings("unchecked")
@Override
public S getSpace(UUID spaceUUID) {
// Type safety: assume that any ClassCastException will be thrown in the caller context.
return (S) this.spaceRepository.getSpace(
// The space specification parameter
// could be null because it will
// not be used during the search.
new SpaceID(this.id, spaceUUID, null));
}
/**
* Listener on the events in the space repository.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
private static class SpaceListener implements SpaceRepositoryListener {
private final Context context;
private final SpaceRepositoryListener relay;
private final LogService logger;
/** Constructor.
* @param context the context that is owner this space listener.
* @param logger the logging service to use.
* @param relay the space repository listener to register at initialization time.
*/
SpaceListener(Context context, LogService logger, SpaceRepositoryListener relay) {
assert context != null;
assert logger != null;
assert relay != null;
this.context = context;
this.logger = logger;
this.relay = relay;
}
@Override
public void spaceCreated(Space space, boolean isLocalCreation) {
this.logger.getKernelLogger().info(MessageFormat.format(Messages.Context_0, space.getSpaceID()));
// Notify the relays (other services)
this.relay.spaceCreated(space, isLocalCreation);
// Send the event in the default space of the context.
if (isLocalCreation) {
final EventSpace defSpace = this.context.getDefaultSpace();
// defSpace may be null if the created space is the default space.
if (defSpace != null) {
defSpace.emit(
// No need to give an event source because it is explicitly set below.
null,
new SpaceCreated(new Address(defSpace.getSpaceID(), this.context.getID()), space.getSpaceID()));
}
}
}
@Override
public void spaceDestroyed(Space space, boolean isLocalDestruction) {
this.logger.getKernelLogger().info(MessageFormat.format(Messages.Context_1, space.getSpaceID()));
// Send the event in the default space of the context.
if (isLocalDestruction) {
final EventSpace defSpace = this.context.getDefaultSpace();
// defSpace may be null if the created space is the default space.
if (defSpace != null) {
defSpace.emit(
// No need to give an event source because it is explicitly set below.
null,
new SpaceDestroyed(new Address(defSpace.getSpaceID(), this.context.getID()), space.getSpaceID()));
}
}
// Notify the relays (other services)
this.relay.spaceDestroyed(space, isLocalDestruction);
}
}
/**
* Factory for the space repository in a context.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
public static class DefaultSpaceRepositoryFactory implements SpaceRepositoryFactory {
private final DistributedDataStructureService dataStructureService;
private final Injector injector;
private final LogService logger;
/** Constructor.
* @param injector instance of the injector to be used.
* @param distributedDataStructure service that permits to obtain distributed data structure.
* @param logger logging service.
*/
public DefaultSpaceRepositoryFactory(Injector injector, DistributedDataStructureService distributedDataStructure,
LogService logger) {
this.dataStructureService = distributedDataStructure;
this.injector = injector;
this.logger = logger;
}
/**
* {@inheritDoc}
*
*
In opposite to {@link #newInstanceWithPrivateSpaceListener(Context, String, SpaceRepositoryListener)}, this function
* wraps the listener into a private space listener proxy before giving this wrapper to the space repository.
*/
@Override
public final SpaceRepository newInstance(Context context, String distributedSpaceSetName,
SpaceRepositoryListener listener) {
return newInstanceWithPrivateSpaceListener(context, distributedSpaceSetName,
new SpaceListener(context, this.logger, listener));
}
/**
* Create an instance of the space repository.
*
*
In opposite to {@link #newInstance(Context, String, SpaceRepositoryListener)}, this function gives the listener to the
* space repository, without wrapping it into the private space listener proxy.
*
* @param context the context in which the space repository must be created.
* @param distributedSpaceSetName name of the distribued data structure used by the space repository.
* @param listener the listener on the space repository events to be register at initialization stage.
* @return the space repository
*/
protected SpaceRepository newInstanceWithPrivateSpaceListener(Context context, String distributedSpaceSetName,
SpaceRepositoryListener listener) {
return new SpaceRepository(distributedSpaceSetName, this.dataStructureService, this.injector, listener);
}
}
}