swim.runtime.lane.LaneModel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swim-runtime Show documentation
Show all versions of swim-runtime Show documentation
Uploads all artifacts belonging to configuration ':swim-runtime:archives'
// Copyright 2015-2019 SWIM.AI inc.
//
// 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 swim.runtime.lane;
import java.util.Collections;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import swim.api.agent.AgentContext;
import swim.api.auth.Identity;
import swim.api.data.DataFactory;
import swim.api.downlink.Downlink;
import swim.api.lane.Lane;
import swim.api.policy.Policy;
import swim.api.uplink.Uplink;
import swim.codec.Decoder;
import swim.collections.FingerTrieSeq;
import swim.concurrent.Schedule;
import swim.concurrent.Stage;
import swim.http.HttpBody;
import swim.http.HttpRequest;
import swim.http.HttpResponse;
import swim.http.HttpStatus;
import swim.math.Z2Form;
import swim.runtime.AbstractTierBinding;
import swim.runtime.HttpBinding;
import swim.runtime.LaneBinding;
import swim.runtime.LaneContext;
import swim.runtime.LinkBinding;
import swim.runtime.LinkContext;
import swim.runtime.PushRequest;
import swim.runtime.TierContext;
import swim.runtime.uplink.UplinkModem;
import swim.store.DataBinding;
import swim.store.ListDataBinding;
import swim.store.MapDataBinding;
import swim.store.SpatialDataBinding;
import swim.store.ValueDataBinding;
import swim.structure.Value;
import swim.uri.Uri;
import swim.warp.CommandMessage;
import swim.warp.Envelope;
public abstract class LaneModel extends AbstractTierBinding implements LaneBinding {
protected LaneContext laneContext;
volatile Object views; // View | LaneView[]
volatile FingerTrieSeq uplinks;
public LaneModel() {
this.uplinks = FingerTrieSeq.empty();
}
@Override
public TierContext tierContext() {
return this.laneContext;
}
@Override
public LaneContext laneContext() {
return this.laneContext;
}
@Override
public void setLaneContext(LaneContext laneContext) {
this.laneContext = laneContext;
}
@SuppressWarnings("unchecked")
@Override
public T unwrapLane(Class laneClass) {
if (laneClass.isAssignableFrom(getClass())) {
return (T) this;
} else {
final Object views = this.views;
if (views instanceof LaneView) {
return ((LaneView) views).unwrapLane(laneClass);
} else if (views instanceof LaneView[]) {
final LaneView[] viewArray = (LaneView[]) views;
for (int i = 0, n = viewArray.length; i < n; i += 1) {
final T lane = viewArray[i].unwrapLane(laneClass);
if (lane != null) {
return lane;
}
}
}
return null;
}
}
protected abstract U createUplink(LinkBinding link);
@Override
public final Uri meshUri() {
return this.laneContext.meshUri();
}
@Override
public final Value partKey() {
return this.laneContext.partKey();
}
@Override
public final Uri hostUri() {
return this.laneContext.hostUri();
}
@Override
public final Uri nodeUri() {
return this.laneContext.nodeUri();
}
@Override
public final Uri laneUri() {
return this.laneContext.laneUri();
}
@Override
public final Value agentKey() {
return this.laneContext.agentKey();
}
@Override
public Policy policy() {
return this.laneContext.policy();
}
@Override
public Schedule schedule() {
return this.laneContext.schedule();
}
@Override
public Stage stage() {
return this.laneContext.stage();
}
@Override
public DataFactory data() {
return this.laneContext.data();
}
@Override
public Lane getLaneView(AgentContext agentContext) {
final Object views = this.views;
LaneView view;
if (views instanceof LaneView) {
view = (LaneView) views;
if (agentContext == view.agentContext()) {
return view;
}
} else if (views instanceof LaneView[]) {
final LaneView[] viewArray = (LaneView[]) views;
for (int i = 0, n = viewArray.length; i < n; i += 1) {
view = viewArray[i];
if (agentContext == view.agentContext()) {
return view;
}
}
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public void openLaneView(Lane view) {
Object oldLaneViews;
Object newLaneViews;
do {
oldLaneViews = this.views;
if (oldLaneViews instanceof LaneView) {
newLaneViews = new LaneView[]{(LaneView) oldLaneViews, (LaneView) view};
} else if (oldLaneViews instanceof LaneView[]) {
final LaneView[] oldLaneViewArray = (LaneView[]) oldLaneViews;
final int n = oldLaneViewArray.length;
final LaneView[] newLaneViewArray = new LaneView[n + 1];
System.arraycopy(oldLaneViewArray, 0, newLaneViewArray, 0, n);
newLaneViewArray[n] = (LaneView) view;
newLaneViews = newLaneViewArray;
} else {
newLaneViews = (LaneView) view;
}
} while (!VIEWS.compareAndSet(this, oldLaneViews, newLaneViews));
didOpenLaneView((View) view);
}
@SuppressWarnings("unchecked")
@Override
public void closeLaneView(Lane view) {
Object oldLaneViews;
Object newLaneViews;
do {
oldLaneViews = this.views;
if (oldLaneViews instanceof LaneView) {
if (oldLaneViews == view) {
newLaneViews = null;
continue;
}
} else if (oldLaneViews instanceof LaneView[]) {
final LaneView[] oldLaneViewArray = (LaneView[]) oldLaneViews;
final int n = oldLaneViewArray.length;
if (n == 2) {
if (oldLaneViewArray[0] == view) {
newLaneViews = oldLaneViewArray[1];
continue;
} else if (oldLaneViewArray[1] == view) {
newLaneViews = oldLaneViewArray[0];
continue;
}
} else { // n > 2
final LaneView[] newLaneViewArray = new LaneView[n - 1];
int i = 0;
while (i < n) {
if (oldLaneViewArray[i] != view) {
if (i < n - 1) {
newLaneViewArray[i] = oldLaneViewArray[i];
}
i += 1;
} else {
break;
}
}
if (i < n) {
System.arraycopy(oldLaneViewArray, i + 1, newLaneViewArray, i, n - (i + 1));
newLaneViews = newLaneViewArray;
continue;
}
}
}
newLaneViews = oldLaneViews;
break;
} while (!VIEWS.compareAndSet(this, oldLaneViews, newLaneViews));
if (oldLaneViews != newLaneViews) {
didCloseLaneView((View) view);
}
if (newLaneViews == null) {
close();
}
}
@SuppressWarnings("unchecked")
@Override
public FingerTrieSeq getUplinks() {
return (FingerTrieSeq) (FingerTrieSeq>) this.uplinks;
}
@SuppressWarnings("unchecked")
@Override
public LinkBinding getUplink(Value linkKey) {
final FingerTrieSeq uplinks = (FingerTrieSeq) (FingerTrieSeq>) this.uplinks;
for (int i = 0, n = uplinks.size(); i < n; i += 1) {
final U uplink = uplinks.get(i);
if (linkKey.equals(uplink.linkKey())) {
return uplink.linkBinding();
}
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public void openUplink(LinkBinding link) {
FingerTrieSeq oldUplinks;
FingerTrieSeq newUplinks;
final U uplink = createUplink(link);
link.setLinkContext(uplink);
do {
oldUplinks = (FingerTrieSeq) (FingerTrieSeq>) this.uplinks;
newUplinks = oldUplinks.appended(uplink);
} while (!UPLINKS.compareAndSet(this, oldUplinks, newUplinks));
didUplink(uplink);
// TODO: onEnter
}
@SuppressWarnings("unchecked")
@Override
public void closeUplink(Value linkKey) {
FingerTrieSeq oldUplinks;
FingerTrieSeq newUplinks;
U linkContext;
do {
oldUplinks = (FingerTrieSeq) (FingerTrieSeq>) this.uplinks;
newUplinks = oldUplinks;
linkContext = null;
for (int i = 0, n = oldUplinks.size(); i < n; i += 1) {
final U uplink = oldUplinks.get(i);
if (linkKey.equals(uplink.linkKey())) {
linkContext = uplink;
newUplinks = oldUplinks.removed(i);
break;
}
}
} while (!UPLINKS.compareAndSet(this, oldUplinks, newUplinks));
if (linkContext != null) {
linkContext.linkBinding().didCloseUp();
// TODO: onLeave
}
}
@Override
public void httpUplink(HttpBinding http) {
final HttpLaneUplink httpContext = new HttpLaneUplink(this, http);
http.setHttpContext(httpContext);
}
@SuppressWarnings("unchecked")
protected void cueDown() {
FingerTrieSeq uplinks;
do {
uplinks = (FingerTrieSeq) (FingerTrieSeq>) this.uplinks;
for (int i = 0, n = uplinks.size(); i < n; i += 1) {
final U u = uplinks.get(i);
if (u.isConnected()) {
u.cueDown();
} else {
closeUplink(u.linkKey());
}
}
} while (uplinks != this.uplinks);
}
@SuppressWarnings("unchecked")
protected void sendDown(Value body) {
FingerTrieSeq uplinks;
do {
uplinks = (FingerTrieSeq) (FingerTrieSeq>) this.uplinks;
for (int i = 0, n = uplinks.size(); i < n; i += 1) {
final U u = uplinks.get(i);
if (u.isConnected()) {
u.sendDown(body);
} else {
closeUplink(u.linkKey());
}
}
} while (uplinks != this.uplinks);
}
@Override
public void pushUp(PushRequest pushRequest) {
final Envelope envelope = pushRequest.envelope();
if (envelope instanceof CommandMessage) {
onCommand((CommandMessage) envelope);
pushRequest.didDeliver();
} else {
pushRequest.didDecline();
}
}
@Override
public void pushUpCommand(CommandMessage message) {
onCommand(message);
}
protected void onCommand(CommandMessage message) {
new LaneRelayOnCommand(this, message).run();
}
protected abstract void didOpenLaneView(View view);
protected void didCloseLaneView(View view) {
// stub
}
protected void didUplink(U uplink) {
new LaneRelayDidUplink(this, uplink).run();
}
protected void didEnter(Identity identity) {
new LaneRelayDidEnter(this, identity).run();
}
protected void didLeave(Identity identity) {
new LaneRelayDidLeave(this, identity).run();
}
public Decoder
© 2015 - 2025 Weber Informatics LLC | Privacy Policy