/**
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* All rights reserved. This program and the accompanying materials are made available under
* the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*/
package gov.redhawk.ide.debug.impl;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.omg.CORBA.COMM_FAILURE;
import org.omg.CORBA.IntHolder;
import org.omg.CORBA.Object;
import CF.DataType;
import CF.InvalidIdentifier;
import CF.InvalidObjectReference;
import CF.LogEvent;
import CF.PropertiesHolder;
import CF.UnknownIdentifier;
import CF.UnknownProperties;
import CF.LifeCyclePackage.InitializeError;
import CF.LifeCyclePackage.ReleaseError;
import CF.PropertyEmitterPackage.AlreadyInitialized;
import CF.PropertySetPackage.InvalidConfiguration;
import CF.PropertySetPackage.PartialConfiguration;
import CF.ResourcePackage.StartError;
import CF.ResourcePackage.StopError;
import CF.TestableObjectPackage.UnknownTest;
import gov.redhawk.ide.debug.ScaDebugPlugin;
import gov.redhawk.model.sca.ScaAbstractProperty;
import gov.redhawk.model.sca.ScaComponent;
import gov.redhawk.model.sca.ScaPackage;
import gov.redhawk.model.sca.ScaUsesPort;
import gov.redhawk.model.sca.commands.ScaModelCommand;
import gov.redhawk.sca.util.SilentJob;
import gov.redhawk.sca.util.SubMonitor;
import mil.jpeojtrs.sca.spd.SoftPkg;
/**
* Used for components of domain waveforms when the waveform is opened with the sandbox. Most operations are proxied
* to the {@link ScaComponent} so that the two objects stay in sync.
* @since 9.0
*/
public class ProxyScaComponentImpl extends LocalScaComponentImpl {
private ScaComponent target;
private Adapter targetListener = new EContentAdapter() {
@Override
public void notifyChanged(Notification msg) {
super.notifyChanged(msg);
if (msg.getNotifier() instanceof ScaAbstractProperty< ? >) {
// Ignore the "ignore remote set" attribute (which gets changed a lot)
if (msg.getFeatureID(ScaAbstractProperty.class) != ScaPackage.SCA_ABSTRACT_PROPERTY__IGNORE_REMOTE_SET) {
// If we get here, most likely it's the object's value that changed. Find the root object for the
// property (necessary for structs and struct sequences). TODO: We could update the value for just
// the part of the property that changed.
ScaAbstractProperty< ? > targetProp = (ScaAbstractProperty< ? >) msg.getNotifier();
while (targetProp.eContainer() instanceof ScaAbstractProperty< ? >) {
targetProp = (ScaAbstractProperty< ? >) targetProp.eContainer();
if (targetProp == null) {
return;
}
}
// Update our property value to match the target's property value
ScaAbstractProperty< ? > prop = getProperty(targetProp.getId());
if (prop != null) {
prop.fromAny(targetProp.toAny());
}
}
} else if (msg.getNotifier() instanceof ScaComponent) {
if (msg.getEventType() == Notification.SET) {
switch (msg.getFeatureID(ScaComponent.class)) {
case ScaPackage.SCA_COMPONENT__DISPOSED:
if (msg.getNewBooleanValue()) {
ProxyScaComponentImpl.this.target.eAdapters().remove(this);
EcoreUtil.delete(ProxyScaComponentImpl.this);
}
break;
case ScaPackage.SCA_COMPONENT__IDENTIFIER:
setIdentifier(msg.getNewStringValue());
break;
case ScaPackage.SCA_COMPONENT__PROFILE:
setProfile(msg.getNewStringValue());
break;
case ScaPackage.SCA_COMPONENT__PROFILE_OBJ:
setProfileObj((SoftPkg) msg.getNewValue());
break;
case ScaPackage.SCA_COMPONENT__STARTED:
setStarted((Boolean) msg.getNewValue());
break;
default:
break;
}
}
} else if (msg.getNotifier() instanceof ScaUsesPort) {
if (msg.getFeatureID(ScaUsesPort.class) == ScaPackage.SCA_USES_PORT__CONNECTIONS) {
// Find our matching port object
String portName = ((ScaUsesPort) msg.getNotifier()).getName();
if (portName == null) {
return;
}
final ScaUsesPort usesPort = (ScaUsesPort) getScaPort(portName);
if (usesPort == null) {
return;
}
// Update our port
new SilentJob(execParam) {
@Override
protected IStatus runSilent(IProgressMonitor monitor) {
usesPort.fetchConnections(monitor);
return Status.OK_STATUS;
}
}.schedule();
}
}
}
protected void addAdapter(Notifier notifier) {
// Watch the component, its uses ports, and its properties
if (notifier instanceof ScaAbstractProperty || notifier instanceof ScaUsesPort || notifier instanceof ScaComponent) {
super.addAdapter(notifier);
}
}
};
/**
* This method <b>must</b> be called in a transaction so it can add itself as an adapter to the target.
* @param target The {@link ScaComponent} in the domain's model to proxy.
*/
public ProxyScaComponentImpl(ScaComponent target) {
this.target = target;
// Listen for changes
ProxyScaComponentImpl.this.target.eAdapters().add(targetListener);
}
//////////////////////////////
// Forward the certain fetch operations to the target first. Use what the target has cached when we fetch for
// ourself.
//////////////////////////////
@Override
public String identifier() {
// Use cached value from target
return target.getIdentifier();
}
@Override
public String fetchIdentifier(IProgressMonitor monitor) {
// Cause target to fetch, then update ourself using that
SubMonitor progress = SubMonitor.convert(monitor, 2);
target.fetchIdentifier(progress.newChild(1));
return super.fetchIdentifier(progress.newChild(1));
}
@Override
public boolean started() {
// Use cached value from target
Boolean retVal = target.getStarted();
return (retVal == null) ? false : retVal;
}
@Override
public Boolean fetchStarted(IProgressMonitor monitor) {
// Cause target to fetch, then update ourself using that
SubMonitor progress = SubMonitor.convert(monitor, 2);
target.fetchStarted(progress.newChild(1));
return super.fetchStarted(progress.newChild(1));
}
@Override
public String softwareProfile() {
// Use cached value from target
String newProfile = target.getProfile();
if (newProfile == null) {
throw new COMM_FAILURE();
}
return newProfile;
}
@Override
public String fetchProfile(IProgressMonitor monitor) {
// Cause target to fetch, then update ourself using that
SubMonitor progress = SubMonitor.convert(monitor, 2);
target.fetchProfile(progress.newChild(1));
return super.fetchProfile(progress.newChild(1));
}
@Override
public void query(final PropertiesHolder configProperties) throws UnknownProperties {
// Use the target's existing cached property values.
try {
ScaModelCommand.runExclusive(target, new RunnableWithResult.Impl<Object>() {
@Override
public void run() {
if (configProperties.value.length == 0) {
List<DataType> dtProps = new ArrayList<>();
for (ScaAbstractProperty< ? > prop : target.getProperties()) {
dtProps.add(new DataType(prop.getId(), prop.toAny()));
}
configProperties.value = dtProps.toArray(new DataType[0]);
} else {
List<DataType> unknownProps = new ArrayList<>();
for (DataType dt : configProperties.value) {
ScaAbstractProperty< ? > prop = target.getProperty(dt.id);
if (prop == null) {
unknownProps.add(dt);
} else {
dt.value = prop.toAny();
}
}
if (unknownProps.size() > 0) {
UnknownProperties exception = new UnknownProperties(unknownProps.toArray(new DataType[0]));
setStatus(new Status(IStatus.ERROR, ScaDebugPlugin.ID, "Invalid properties", exception));
} else {
setStatus(new Status(IStatus.OK, ScaDebugPlugin.ID, ""));
}
}
}
});
} catch (InterruptedException e) {
// PASS
}
}
@Override
public EList<ScaAbstractProperty< ? >> fetchProperties(IProgressMonitor monitor) {
// Cause target to fetch, then update ourself using that
SubMonitor progress = SubMonitor.convert(monitor, 2);
target.fetchProperties(progress.newChild(1));
return super.fetchProperties(progress.newChild(1));
}
@Override
public SoftPkg fetchProfileObject(IProgressMonitor monitor) {
// Cause target to fetch, then update ourself
SubMonitor progress = SubMonitor.convert(monitor, 2);
target.fetchProfileObject(progress.newChild(1));
return super.fetchProfileObject(progress.newChild(1));
}
//////////////////////////////
// Certain actions can be forwarded to the target. We'll get notified by the target of changes.
//////////////////////////////
@Override
public boolean _is_a(String repId) {
return target._is_a(repId);
}
@Override
public void initializeProperties(DataType[] initialProperties) throws AlreadyInitialized, InvalidConfiguration, PartialConfiguration {
target.initializeProperties(initialProperties);
}
@Override
public String registerPropertyListener(Object obj, String[] propIds, float interval) throws UnknownProperties, InvalidObjectReference {
return target.registerPropertyListener(obj, propIds, interval);
}
@Override
public void unregisterPropertyListener(String id) throws InvalidIdentifier {
target.unregisterPropertyListener(id);
}
@Override
public void configure(DataType[] configProperties) throws InvalidConfiguration, PartialConfiguration {
target.configure(configProperties);
}
@Override
public void start() throws StartError {
target.start();
}
@Override
public void stop() throws StopError {
target.stop();
}
@Override
public void initialize() throws InitializeError {
target.initialize();
}
@Override
public void releaseObject() throws ReleaseError {
target.releaseObject();
}
@Override
public void runTest(int testid, PropertiesHolder testValues) throws UnknownTest, UnknownProperties {
target.runTest(testid, testValues);
}
@Override
public LogEvent[] retrieve_records(IntHolder howMany, int startingRecord) {
return target.retrieve_records(howMany, startingRecord);
}
@Override
public LogEvent[] retrieve_records_by_date(IntHolder howMany, long toTimeStamp) {
return target.retrieve_records_by_date(howMany, toTimeStamp);
}
@Override
public LogEvent[] retrieve_records_from_date(IntHolder howMany, long fromTimeStamp) {
return target.retrieve_records_from_date(howMany, fromTimeStamp);
}
@Override
public int log_level() {
return target.log_level();
}
@Override
public void log_level(int newLogLevel) {
target.log_level(newLogLevel);
}
@Override
public void setLogLevel(String loggerId, int newLevel) throws UnknownIdentifier {
target.setLogLevel(loggerId, newLevel);
}
@Override
public String getLogConfig() {
return target.getLogConfig();
}
@Override
public void setLogConfig(String configContents) {
target.setLogConfig(configContents);
}
@Override
public void setLogConfigURL(String configUrl) {
target.setLogConfigURL(configUrl);
}
}