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.
package il.ac.bgu.cs.bp.bpjs.execution.jsproxy;
import il.ac.bgu.cs.bp.bpjs.model.BProgram;
import il.ac.bgu.cs.bp.bpjs.model.BThreadSyncSnapshot;
import il.ac.bgu.cs.bp.bpjs.model.BEvent;
import il.ac.bgu.cs.bp.bpjs.model.eventsets.EventSet;
import il.ac.bgu.cs.bp.bpjs.model.eventsets.EventSets;
import il.ac.bgu.cs.bp.bpjs.model.eventsets.JsEventSet;
import il.ac.bgu.cs.bp.bpjs.exceptions.BPjsRuntimeException;
import il.ac.bgu.cs.bp.bpjs.execution.tasks.FailedAssertionException;
import il.ac.bgu.cs.bp.bpjs.model.SyncStatement;
import il.ac.bgu.cs.bp.bpjs.model.ForkStatement;
import il.ac.bgu.cs.bp.bpjs.model.eventsets.ComposableEventSet;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import java.util.stream.Stream;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContinuationPending;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeObject;
/**
* An object representing the {@link BProgram} context for Javascript code.
* Methods in this object allow Javascript code to register new BThreads,
* create events,write messages to the log etc.
*
* Methods in the class are available to Javascript code via the {@code bp}
* object, like so:
*
*
* bp.log.info("I'm a log message!");
* var myEvent = bp.Event("My Event");
* bp.registerBThread(...);
*
*
* @author michael
*/
public class BProgramJsProxy extends SyncStatementBuilder
implements java.io.Serializable {
private static final ThreadLocal CURRENT_BTHREAD = new ThreadLocal<>();
public static void setCurrentBThread( BThreadSyncSnapshot bss ) {
CURRENT_BTHREAD.set(bss);
}
public static void clearCurrentBThread(){
CURRENT_BTHREAD.remove();
}
private final BProgram program;
private final AtomicInteger autoAddCounter = new AtomicInteger(0);
public final BpLog log = new BpLog();
public final EventSet all = EventSets.all;
public final EventSet none = EventSets.none;
/**
* Facility for creating random numbers. BPjs code should not use Javascript's
* random facility, as it won't play well with model checking.
*/
public RandomProxy random = new RandomProxy();
public BProgramJsProxy(BProgram program) {
this.program = program;
}
/**
* Event constructor, called from Javascript, hence the funny
* capitalization.
*
* @param name name of the event
* @return an event with the passed name.
*/
public BEvent Event(String name) {
return new BEvent(name);
}
/**
* Event constructor, called from Javascript, hence the funny
* capitalization.
*
* @param name name of the event
* @param jsData Additional data for the object.
* @return an event with the passed name.
*/
public BEvent Event(String name, Object jsData) {
return new BEvent(name, jsData );
}
public JsEventSet EventSet(String name, Object predicateObj) {
if ( predicateObj instanceof Function ) {
return new JsEventSet(name, (Function) predicateObj);
} else {
throw new BPjsRuntimeException("An event set predicate has to be a function.");
}
}
public EventSet allExcept( EventSet es ) {
return EventSets.allExcept(es);
}
/**
* Called from JS to add BThreads running func as their runnable code.
*
* @param name Name of the registered BThread (useful for debugging).
* @param func Script entry point of the BThread.
*
* @see #registerBThread(org.mozilla.javascript.Function)
*/
public void registerBThread(String name, Function func) {
program.registerBThread(new BThreadSyncSnapshot(name, func));
}
/**
* Registers a BThread and gives it a unique name. Use when you don't care
* about the added BThread's name.
*
* @param func the BThread to add.
*
* @see #registerBThread(java.lang.String, org.mozilla.javascript.Function)
*/
public void registerBThread(Function func) {
registerBThread("autoadded-" + autoAddCounter.incrementAndGet(), func);
}
/**
* If {@code value} is {@code false}, puts the entire program in an invalid
* state. This, in turn, would terminate it when it's being run, or discover
* a specification violation when it's being verified.
*
* note: I'd rather call it {@code assert} too, but that's a Java keyword, which complicates stuff.
*
* @param value The value of the assertion. When {@code false}, the program is declared in invalid state.
* @param message Textual information about what caused the violation.
* @throws FailedAssertionException if {@code value} is false.
*/
public void ASSERT( boolean value, String message ) throws FailedAssertionException {
if ( ! value ) {
throw new FailedAssertionException( message );
}
}
public void fork() throws ContinuationPending {
ContinuationPending capturedContinuation = Context.getCurrentContext().captureContinuation();
capturedContinuation.setApplicationState(new ForkStatement(capturedContinuation.getContinuation()));
throw capturedContinuation;
}
public void setInterruptHandler( Object aPossibleHandler ) {
CURRENT_BTHREAD.get().setInterruptHandler(
(aPossibleHandler instanceof Function) ? (Function) aPossibleHandler: null );
}
////////////////////////
// sync ("bsync") related code
@Override
public void sync( NativeObject jsRWB, Object data ) {
synchronizationPoint(jsRWB, null, data);
}
@Override
public SyncStatementBuilder hot(boolean isHot) {
SyncStatementBuilderImpl sub = new SyncStatementBuilderImpl(this);
sub.setHotness(isHot);
return sub;
}
/**
* Where the actual Behavioral Programming synchronization point is done.
*
* @param jsRWB The JavaScript object {@code {request:... waitFor:...}}
* @param hot {@code True} if this should be a "hot" synchronization point.
* @param data Optional extra data the synchronizing b-thread may want to add.
*/
@Override
void synchronizationPoint( NativeObject jsRWB, Boolean hot, Object data ) {
Map jRWB = (Map)Context.jsToJava(jsRWB, Map.class);
SyncStatement stmt = SyncStatement.make();
if ( hot != null ) {
stmt = stmt.hot(hot);
}
Object req = jRWB.get("request");
if ( req != null ) {
if ( req instanceof BEvent ) {
stmt = stmt.request((BEvent)req);
} else if ( req instanceof NativeArray ) {
NativeArray arr = (NativeArray) req;
stmt = stmt.request(
Arrays.asList( arr.getIndexIds() ).stream()
.map( i -> (BEvent)arr.get(i) )
.collect( toList() ));
}
}
EventSet waitForSet = convertToEventSet(jRWB.get("waitFor"));
EventSet blockSet = convertToEventSet(jRWB.get("block"));
EventSet interruptSet = convertToEventSet(jRWB.get("interrupt"));
stmt = stmt.waitFor( waitForSet )
.block( blockSet )
.interrupt( interruptSet )
.data( data );
boolean hasCollision = stmt.getRequest().stream().anyMatch(blockSet::contains);
if (hasCollision) {
System.err.println("Warning: B-thread is blocking an event it is also requesting, this may lead to a deadlock.");
}
captureBThreadState(stmt);
}
private EventSet convertToEventSet( Object jsObject ) {
if ( jsObject == null ) return EventSets.none;
// This covers event sets AND events.
if ( jsObject instanceof EventSet ) {
return (EventSet)jsObject;
} else if ( jsObject instanceof NativeArray ) {
NativeArray arr = (NativeArray) jsObject;
if ( Stream.of(arr.getIds()).anyMatch( id -> arr.get(id)==null) ) {
throw new RuntimeException("EventSet Array contains null sets.");
}
return ComposableEventSet.anyOf(
Arrays.asList(arr.getIndexIds()).stream()
.map( i ->(EventSet)arr.get(i) )
.collect( toSet() ) );
} else {
final String errorMessage = "Cannot convert " + jsObject + " of class " + jsObject.getClass() + " to an event set";
Logger.getLogger(BThreadSyncSnapshot.class.getName()).log(Level.SEVERE, errorMessage);
throw new IllegalArgumentException( errorMessage);
}
}
private void captureBThreadState(SyncStatement stmt) throws ContinuationPending {
ContinuationPending capturedContinuation = Context.getCurrentContext().captureContinuation();
capturedContinuation.setApplicationState(stmt);
throw capturedContinuation;
}
// /sync
/////////////////////////
/**
* Push a new event to the external event queue.
* @param evt The event to be pushed.
* @return the event being pushed.
*/
public BEvent enqueueExternalEvent( BEvent evt ) {
program.enqueueExternalEvent(evt);
return evt;
}
/**
* Sets whether the BProgram will wait for external events when there's
* no internal event to choose.
*
* @param newDaemonMode {@code true} for making {@code this} a daemon;
* {@code false} otherwise.
*/
public void setWaitForExternalEvents( boolean newDaemonMode ) {
program.setWaitForExternalEvents( newDaemonMode );
}
public boolean isWaitForExternalEvents() {
return program.isWaitForExternalEvents();
}
/**
* @return Returns the current time in milliseconds since 1/1/1970.
*/
public long getTime() {
return System.currentTimeMillis();
}
/**
* Gets the name of the Java thread executing this b-thread at the moment. Useful for
* debugging Java runtime issues.
*
* @return the name of the Java thread executing this b-thread at the moment.
*/
public String getJavaThreadName() {
return Thread.currentThread().getName();
}
@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + Objects.hashCode(this.program);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final BProgramJsProxy other = (BProgramJsProxy) obj;
return Objects.equals(this.program, other.program);
}
}