/* * $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.janusproject.kernel.bic; import java.util.HashSet; import java.util.Set; import java.util.UUID; import com.google.inject.Inject; import io.janusproject.services.contextspace.ContextSpaceService; import io.sarl.core.InnerContextAccess; import io.sarl.lang.core.Address; import io.sarl.lang.core.Agent; import io.sarl.lang.core.AgentContext; import io.sarl.lang.core.Event; import io.sarl.lang.core.EventListener; import io.sarl.lang.core.Skill; import io.sarl.lang.core.Space; import io.sarl.lang.core.SpaceID; import io.sarl.lang.util.ClearableReference; import io.sarl.lang.util.SynchronizedSet; import io.sarl.util.Collections3; import io.sarl.util.OpenEventSpace; /** * Janus implementation of SARL's {@link InnerContextSkill} built-in capacity. * * @author $Author: srodriguez$ * @author $Author: ngaud$ * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public class InnerContextSkill extends BuiltinSkill implements InnerContextAccess { private static int installationOrder = -1; private final Address agentAddressInInnerDefaultSpace; private ClearableReference<Skill> skillBufferInternalEventBusCapacity; /** * Context inside the agent. */ private AgentContext innerContext; @Inject private ContextSpaceService contextService; /** * @param agent - owner of this skill. * @param agentAddressInInnerDefaultSpace - address of the owner of this skill in its default space. */ InnerContextSkill(Agent agent, Address agentAddressInInnerDefaultSpace) { super(agent); this.agentAddressInInnerDefaultSpace = agentAddressInInnerDefaultSpace; } /** Replies the InternalEventBusCapacity skill as fast as possible. * * @return the skill */ protected final InternalEventBusCapacity getInternalEventBusCapacitySkill() { if (this.skillBufferInternalEventBusCapacity == null || this.skillBufferInternalEventBusCapacity.get() == null) { this.skillBufferInternalEventBusCapacity = $getSkill(InternalEventBusCapacity.class); } return $castSkill(InternalEventBusCapacity.class, this.skillBufferInternalEventBusCapacity); } @Override public int getInstallationOrder() { if (installationOrder < 0) { installationOrder = installationOrder(this); } return installationOrder; } /** * Replies if the inner context was instanciated. To create the inner context, call {@link #getInnerContext()} * * @return <code>true</code> if an instance of inner context exists, otherwise <code>false</code>. */ public synchronized boolean hasInnerContext() { return this.innerContext != null; } /** * Force to reset the inner context. This function does not update the context repository. * * <p>Do not call this function, exception if you are sure that the setting of the inner context to <code>null</code> only does * not introduce problems. */ synchronized void resetInnerContext() { this.innerContext = null; } @Override protected String attributesToString() { return super.attributesToString() + ", addressInDefaultspace = " + this.agentAddressInInnerDefaultSpace; //$NON-NLS-1$ } @Override protected void uninstall(UninstallationStage stage) { if (stage == UninstallationStage.POST_DESTROY_EVENT) { final AgentContext context = this.innerContext; this.innerContext = null; if (context != null) { // Unregister the agent from the default space final EventListener listener = getInternalEventBusCapacitySkill().asEventListener(); ((OpenEventSpace) context.getDefaultSpace()).unregister(listener); // Destroy the context this.contextService.removeContext(context); } } } @Override public synchronized AgentContext getInnerContext() { if (this.innerContext == null) { // Create the inner context. this.innerContext = this.contextService.createContext( this.agentAddressInInnerDefaultSpace.getSpaceId().getContextID(), this.agentAddressInInnerDefaultSpace.getSpaceId().getID()); // Register the agent in the default space final EventListener listener = getInternalEventBusCapacitySkill().asEventListener(); final OpenEventSpace defSpace = (OpenEventSpace) this.innerContext.getDefaultSpace(); defSpace.register(listener); } return this.innerContext; } @Override public synchronized boolean hasMemberAgent() { if (this.innerContext != null) { final Set<UUID> participants = this.innerContext.getDefaultSpace().getParticipants(); assert participants != null; return (participants.size() > 1) || ((participants.size() == 1) && (!participants.contains(getOwner().getID()))); } return false; } @Override public synchronized int getMemberAgentCount() { if (this.innerContext != null) { final SynchronizedSet<UUID> participants = this.innerContext.getDefaultSpace().getParticipants(); assert participants != null; int count = participants.size(); if (participants.contains(getOwner().getID())) { --count; } return count; } return 0; } @Override public synchronized SynchronizedSet<UUID> getMemberAgents() { if (this.innerContext != null) { final SynchronizedSet<UUID> participants = this.innerContext.getDefaultSpace().getParticipants(); assert participants != null; final Set<UUID> members = new HashSet<>(); final UUID myId = getOwner().getID(); for (final UUID id : participants) { if (!id.equals(myId)) { members.add(id); } } return Collections3.synchronizedSet(members, members); } return Collections3.emptySynchronizedSet(); } @Override public boolean isInnerDefaultSpace(Space space) { return isInnerDefaultSpace(space.getSpaceID()); } @Override public boolean isInnerDefaultSpace(SpaceID spaceID) { final AgentContext context = this.innerContext; return context != null && spaceID.equals(context.getDefaultSpace().getSpaceID()); } @Override public boolean isInnerDefaultSpace(UUID spaceID) { final AgentContext context = this.innerContext; return context != null && spaceID.equals(context.getDefaultSpace().getSpaceID().getID()); } @Override public boolean isInInnerDefaultSpace(Event event) { if (event != null) { final Address adr = event.getSource(); if (adr != null) { return isInnerDefaultSpace(adr.getSpaceId()); } } return false; } }