Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* This file is part of ObjectFabric (http://objectfabric.org).
*
* ObjectFabric is licensed under the Apache License, Version 2.0, the terms
* of which may be found at http://www.apache.org/licenses/LICENSE-2.0.html.
*
* Copyright ObjectFabric Inc.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.objectfabric;
import java.util.concurrent.atomic.AtomicReference;
/**
* Lets an application specify its own resource storage and data format.
*/
public abstract class CustomLocation extends Origin {
private final Origin _innerLocation;
private final AtomicReference _workspace = new AtomicReference();
/**
* This class must be backed by a regular OF location to keep track of versions
* ordering. This information is not strictly required, but loosing it might lead to
* ordering errors during synchronization. E.g. an old version stored in a client
* cache might become the new latest version instead of being discarded during
* synchronization. When conflicts will be exposed by OF's API, this will turn into
* false positives.
*
* @param backingLocation
* Backing OF location. Must not be registered in any Workspace or Server.
*/
public CustomLocation(Origin backingLocation) {
super(false);
_innerLocation = backingLocation;
}
/**
* A resource has been requested, set its value using data from the custom location.
* This method should not block as it might be called from an internal or IO thread.
* The resource value can instead be set asynchronously when data is ready.
*/
protected abstract void onGet(Resource resource);
/**
* A resource has changed, update the custom location using its new value, and call
* the acknowledgment runnable when done. Any change triggers this method, even if the
* resource is a graph or collection and only a subset changed.
*
* Warning: If value contains TObjects, its content must not be accessed once
* method has returned, or it might be invalid. All serialization must occur during
* method execution, even if acknowledgment is invoked later on.
*
* This method should not block as it might be called from an internal or IO thread.
* Invoking the runnable notifies OF data is safely stored. It lets workspace flushes
* complete, if any are pending.
*/
protected abstract void onChange(Resource resource, Runnable ack);
@Override
View newView(URI uri) {
if (uri.origin() == this)
return new CustomView(this);
if (Debug.ENABLED)
Debug.assertion(uri.origin() == _innerLocation);
return new Bridge(this);
}
@Override
void onView(URI uri, View view) {
if (uri.origin() == this) {
CustomView outerView = (CustomView) view;
outerView._innerURI = _innerLocation.getURI(uri.path());
outerView._innerURI.getOrCreate(_innerLocation);
outerView._bridge = (Bridge) outerView._innerURI.getOrCreate(this);
outerView._bridge._outerURI = uri;
}
}
static final class CustomView extends View {
URI _innerURI;
Bridge _bridge;
CustomResource _resource;
CustomView(CustomLocation outerLocation) {
super(outerLocation);
}
@Override
void getKnown(URI outerUri) {
_innerURI.getKnown(_bridge);
}
@Override
void onKnown(URI outerUri, long[] ticks) {
}
@Override
void getBlock(URI outerUri, long tick) {
}
@Override
void onBlock(URI outerUri, long tick, Buff[] buffs, long[] removals, boolean requested) {
transferBlock(_innerURI, _bridge, tick, buffs, removals, requested);
}
}
private static void transferBlock(URI uri, View view, long tick, Buff[] buffs, long[] removals, boolean requested) {
if (Debug.THREADS)
ThreadAssert.exchangeTake(buffs);
final Buff[] duplicates = new Buff[buffs.length];
for (int i = 0; i < buffs.length; i++) {
duplicates[i] = buffs[i].duplicate();
if (Debug.THREADS) {
ThreadAssert.exchangeGive(duplicates, duplicates[i]);
ThreadAssert.exchangeGive(buffs, buffs[i]);
}
}
uri.onBlock(view, tick, duplicates, removals, requested, null, false);
if (Debug.THREADS)
ThreadAssert.exchangeTake(duplicates);
for (int i = 0; i < duplicates.length; i++)
duplicates[i].recycle();
}
static final class Bridge extends View {
URI _outerURI;
CustomResource _innerResource;
Bridge(CustomLocation outerLocation) {
super(outerLocation);
}
@Override
void getKnown(URI innerURI) {
try {
CustomLocation location = (CustomLocation) location();
location.onGet(_innerResource);
} catch (Exception ex) {
Log.write(ex);
}
}
@Override
void onKnown(URI innerUri, long[] ticks) {
if (ticks != Tick.EMPTY) {
View view = _outerURI.getOrCreate(_innerResource._outerLocation);
_outerURI.onKnown(view, ticks);
} else {
Workspace workspace, created = null;
CustomLocation location = (CustomLocation) location();
// Delays creation of workspace so that Platform is set.
// TODO remove or simplify
for (;;) {
workspace = location._workspace.get();
if (workspace != null)
break;
if (created == null)
created = Platform.get().newCustomWorkspace(location);
if (location._workspace.compareAndSet(null, workspace = created)) {
workspace.startWatcher();
break;
}
}
_innerResource = (CustomResource) innerUri.getOrCreate(workspace);
_innerResource._outerURI = _outerURI;
innerUri.open(_innerResource);
}
}
@Override
void getBlock(URI innerUri, long tick) {
}
@Override
void onBlock(URI innerUri, long tick, Buff[] buffs, long[] removals, boolean requested) {
View view = _outerURI.getOrCreate((CustomLocation) location());
transferBlock(_outerURI, view, tick, buffs, removals, requested);
}
}
static final class CustomResource extends Resource {
final CustomLocation _outerLocation;
URI _outerURI;
CustomResource(Workspace workspace, URI innerUri, CustomLocation outerLocation) {
super(workspace, innerUri);
_outerLocation = outerLocation;
}
@Override
Exception onBlock(long tick, Buff[] buffs, long[] removals) {
tellKnown();
return super.onBlock(tick, buffs, removals);
}
// @Override
// boolean cancelAck(Object source) {
// return source == _view;
// }
@Override
void onLoad(Snapshot snapshot, final List acks) {
if (Debug.ENABLED)
Debug.assertion(workspace().transaction() == null);
Transaction transaction = workspace().getOrCreateTransaction();
int flags = TransactionBase.FLAG_IGNORE_READS | TransactionBase.FLAG_NO_WRITES | TransactionBase.FLAG_COMMITTED;
workspace().startImpl(transaction, flags, snapshot);
if (Debug.ENABLED)
transaction.checkInvariants();
try {
_outerLocation.onChange(this, new Runnable() {
@Override
public void run() {
Object key;
if (Debug.THREADS)
ThreadAssert.suspend(key = new Object());
View view = _outerURI.getOrCreate(_outerLocation);
for (int i = 0; i < acks.size(); i++)
_outerURI.onAck(view, acks.get(i).Tick);
if (Debug.THREADS)
ThreadAssert.resume(key);
}
});
} catch (Exception ex) {
Log.write(ex);
}
transaction.reset();
if (Debug.THREADS)
ThreadAssert.removePrivate(transaction);
workspace().recycle(transaction);
}
}
@Override
public String toString() {
return "custom://";
}
}