| /******************************************************************************* |
| * Copyright (c) 2007, 2016 Wind River Systems and others. |
| * 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 |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.cdt.dsf.debug.ui.viewmodel.variable; |
| |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| |
| import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; |
| import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; |
| import org.eclipse.cdt.dsf.concurrent.Query; |
| import org.eclipse.cdt.dsf.concurrent.ThreadSafe; |
| import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor; |
| import org.eclipse.cdt.dsf.debug.service.IExpressions; |
| import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext; |
| import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; |
| import org.eclipse.cdt.dsf.service.DsfSession; |
| import org.eclipse.cdt.dsf.service.IDsfService; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.util.tracker.ServiceTracker; |
| |
| @ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor") |
| public class SyncVariableDataAccess { |
| |
| /** |
| * The session that this data access operates in. |
| */ |
| private final DsfSession fSession; |
| |
| /** |
| * Need to use the OSGi service tracker here (instead of DsfServiceTracker), |
| * because we're accessing it in non-dispatch thread. DsfServiceTracker is |
| * not thread-safe. |
| */ |
| @ThreadSafe |
| private ServiceTracker fServiceTracker; |
| |
| |
| public SyncVariableDataAccess(DsfSession session) { |
| fSession = session; |
| } |
| |
| @ThreadSafe |
| private synchronized IExpressions getService() { |
| |
| if (fServiceTracker == null) { |
| try { |
| fServiceTracker = new ServiceTracker( |
| DsfUIPlugin.getBundleContext(), |
| DsfUIPlugin.getBundleContext().createFilter(getServiceFilter()), null); |
| fServiceTracker.open(); |
| } catch (InvalidSyntaxException e) { |
| return null; |
| } |
| } |
| return (IExpressions) fServiceTracker.getService(); |
| } |
| |
| private String getServiceFilter() { |
| StringBuilder filter = new StringBuilder(); |
| filter.append("(&"); //$NON-NLS-1$ |
| filter.append("(OBJECTCLASS="); //$NON-NLS-1$ |
| filter.append(IExpressions.class.getName()); |
| filter.append(')'); |
| filter.append('('); |
| filter.append(IDsfService.PROP_SESSION_ID); |
| filter.append('='); |
| filter.append(fSession.getId()); |
| filter.append(')'); |
| filter.append(')'); |
| return filter.toString(); |
| } |
| |
| @ThreadSafe |
| public synchronized void dispose() { |
| if (fServiceTracker != null) { |
| fServiceTracker.close(); |
| } |
| } |
| |
| public IExpressionDMContext getVariableDMC(Object element) { |
| if (element instanceof IAdaptable) { |
| return ((IAdaptable) element).getAdapter(IExpressionDMContext.class); |
| } |
| return null; |
| } |
| |
| |
| public class GetVariableValueQuery extends Query<IExpressionDMData> { |
| |
| private IExpressionDMContext fDmc; |
| |
| public GetVariableValueQuery(IExpressionDMContext dmc) { |
| super(); |
| fDmc = dmc; |
| } |
| |
| @Override |
| protected void execute(final DataRequestMonitor<IExpressionDMData> rm) { |
| /* |
| * Guard against the session being disposed. If session is disposed |
| * it could mean that the executor is shut-down, which in turn could |
| * mean that we can't complete the RequestMonitor argument. in that |
| * case, cancel to notify waiting thread. |
| */ |
| final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); |
| if (session == null) { |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Debug session already shut down.", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| IExpressions service = getService(); |
| if (service == null) { |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service not available", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| service.getExpressionData(fDmc, new DataRequestMonitor<IExpressionDMData>(session.getExecutor(), rm) { |
| @Override |
| protected void handleSuccess() { |
| /* |
| * All good set return value. |
| */ |
| rm.setData(getData()); |
| rm.done(); |
| } |
| }); |
| } |
| } |
| |
| public IExpressionDMContext getExpressionDMC(Object element) { |
| if (element instanceof IAdaptable) { |
| return ((IAdaptable) element).getAdapter(IExpressionDMContext.class); |
| } |
| return null; |
| } |
| |
| public IExpressionDMData readVariable(Object element) { |
| /* |
| * Get the DMC and the session. If element is not an expression DMC, or |
| * session is stale, then bail out. |
| */ |
| IExpressionDMContext dmc = getExpressionDMC(element); |
| if (dmc == null) return null; |
| DsfSession session = DsfSession.getSession(dmc.getSessionId()); |
| if (session == null) return null; |
| |
| /* |
| * Create the query to request the value from service. Note: no need to |
| * guard against RejectedExecutionException, because |
| * DsfSession.getSession() above would only return an active session. |
| */ |
| GetVariableValueQuery query = new GetVariableValueQuery(dmc); |
| session.getExecutor().execute(query); |
| |
| /* |
| * This class is about synchronous access to the variable, so wait until |
| * the query has completed on the DSF session thread and return the |
| * result. |
| */ |
| try { |
| return query.get(); |
| } catch (InterruptedException e) { |
| assert false; |
| return null; |
| } catch (ExecutionException e) { |
| return null; |
| } |
| } |
| |
| public class SetVariableValueQuery extends Query<Object> { |
| |
| private IExpressionDMContext fDmc; |
| private String fValue; |
| private String fFormatId; |
| |
| public SetVariableValueQuery(IExpressionDMContext dmc, String value, String formatId) { |
| super(); |
| fDmc = dmc; |
| fValue = value; |
| fFormatId = formatId; |
| } |
| |
| @Override |
| protected void execute(final DataRequestMonitor<Object> rm) { |
| /* |
| * We're in another dispatch, so we must guard against executor |
| * shutdown again. |
| */ |
| final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); |
| if (session == null) { |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Debug session already shut down.", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| /* |
| * Guard against a disposed service |
| */ |
| IExpressions service = getService(); |
| if (service == null) { |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| /* |
| * Write the expression value using a string/format style. |
| */ |
| service.writeExpression( |
| fDmc, |
| fValue, |
| fFormatId, |
| new DataRequestMonitor<IExpressionDMData>(session.getExecutor(), rm) { |
| @Override |
| protected void handleSuccess() { |
| /* |
| * All good set return value. |
| */ |
| rm.setData(new Object()); |
| rm.done(); |
| } |
| } |
| ); |
| } |
| } |
| |
| public void writeVariable(Object element, String value, String formatId) { |
| |
| /* |
| * Get the DMC and the session. If element is not an register DMC, or |
| * session is stale, then bail out. |
| */ |
| IExpressionDMContext dmc = getExpressionDMC(element); |
| if (dmc == null) return; |
| DsfSession session = DsfSession.getSession(dmc.getSessionId()); |
| if (session == null) return; |
| |
| /* |
| * Create the query to write the value to the service. Note: no need to |
| * guard against RejectedExecutionException, because |
| * DsfSession.getSession() above would only return an active session. |
| */ |
| SetVariableValueQuery query = new SetVariableValueQuery(dmc, value, formatId); |
| session.getExecutor().execute(query); |
| |
| /* |
| * This class is about synchronous access to the variable, so wait until |
| * the query has completed on the DSF session thread. |
| */ |
| try { |
| /* |
| * Return value is irrelevant, any error would come through with an |
| * exception. |
| */ |
| query.get(3000, TimeUnit.MILLISECONDS); |
| } catch (InterruptedException e) { |
| assert false; |
| } catch (ExecutionException e) { |
| /* |
| * View must be shutting down, no need to show error dialog. |
| */ |
| } catch (TimeoutException e) { |
| assert false; |
| } |
| } |
| |
| public IFormattedDataDMContext getFormattedDMC(Object element) { |
| if (element instanceof IAdaptable) { |
| return ((IAdaptable) element).getAdapter(IFormattedDataDMContext.class); |
| } |
| return null; |
| } |
| |
| public class GetSupportFormatsValueQuery extends Query<Object> { |
| |
| IFormattedDataDMContext fDmc; |
| |
| public GetSupportFormatsValueQuery(IFormattedDataDMContext dmc) { |
| super(); |
| fDmc = dmc; |
| } |
| |
| @Override |
| protected void execute(final DataRequestMonitor<Object> rm) { |
| /* |
| * We're in another dispatch, so we must guard against executor |
| * shutdown again. |
| */ |
| final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); |
| if (session == null) { |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Debug session already shut down.", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| /* |
| * Guard against a disposed service |
| */ |
| IExpressions service = getService(); |
| if (service == null) { |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| /* |
| * Get the available formats from the service. |
| */ |
| service.getAvailableFormats( |
| fDmc, |
| new DataRequestMonitor<String[]>(session.getExecutor(), rm) { |
| @Override |
| protected void handleSuccess() { |
| /* |
| * All good set return value. |
| */ |
| rm.setData(getData()); |
| rm.done(); |
| } |
| } |
| ); |
| } |
| } |
| |
| public String[] getSupportedFormats(Object element) { |
| |
| /* |
| * Get the DMC and the session. If element is not an register DMC, or |
| * session is stale, then bail out. |
| */ |
| IFormattedDataDMContext dmc = getFormattedDMC(element); |
| if (dmc == null) return null; |
| DsfSession session = DsfSession.getSession(dmc.getSessionId()); |
| if (session == null) return null; |
| |
| /* |
| * Create the query to write the value to the service. Note: no need to |
| * guard against RejectedExecutionException, because |
| * DsfSession.getSession() above would only return an active session. |
| */ |
| GetSupportFormatsValueQuery query = new GetSupportFormatsValueQuery(dmc); |
| session.getExecutor().execute(query); |
| |
| /* |
| * Now we have the data, go and get it. Since the call is completed now |
| * the ".get()" will not suspend it will immediately return with the |
| * data. |
| */ |
| try { |
| return (String[]) query.get(); |
| } catch (InterruptedException e) { |
| assert false; |
| return null; |
| } catch (ExecutionException e) { |
| return null; |
| } |
| } |
| |
| public class GetFormattedValueValueQuery extends Query<Object> { |
| |
| private IFormattedDataDMContext fDmc; |
| private String fFormatId; |
| private boolean fEditable; |
| |
| public GetFormattedValueValueQuery(IFormattedDataDMContext dmc, String formatId) { |
| this(dmc, formatId, false); |
| } |
| |
| public GetFormattedValueValueQuery(IFormattedDataDMContext dmc, String formatId, boolean editable) { |
| super(); |
| fDmc = dmc; |
| fFormatId = formatId; |
| fEditable = editable; |
| } |
| |
| @Override |
| protected void execute(final DataRequestMonitor<Object> rm) { |
| /* |
| * We're in another dispatch, so we must guard against executor |
| * shutdown again. |
| */ |
| final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); |
| if (session == null) { |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Debug session already shut down.", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| /* |
| * Guard against a disposed service |
| */ |
| IExpressions service = getService(); |
| if (service == null) { |
| rm .setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| /* |
| * Convert to the proper formatting DMC then go get the formatted value. |
| */ |
| |
| FormattedValueDMContext formDmc = service.getFormattedValueContext(fDmc, fFormatId); |
| |
| service.getFormattedExpressionValue(formDmc, new DataRequestMonitor<FormattedValueDMData>(session.getExecutor(), rm) { |
| @Override |
| protected void handleSuccess() { |
| rm.setData(fEditable ? getData().getEditableValue() : getData().getFormattedValue()); |
| rm.done(); |
| } |
| }); |
| } |
| } |
| |
| public String getFormattedValue(Object element, String formatId) { |
| return getValue(element, formatId, false); |
| } |
| |
| public String getEditableValue(Object element, String formatId) { |
| return getValue(element, formatId, true); |
| } |
| |
| private String getValue(Object element, String formatId, boolean editable) { |
| |
| /* |
| * Get the DMC and the session. If element is not an register DMC, or |
| * session is stale, then bail out. |
| */ |
| IFormattedDataDMContext dmc = getFormattedDMC(element); |
| if (dmc == null) return null; |
| DsfSession session = DsfSession.getSession(dmc.getSessionId()); |
| if (session == null) return null; |
| |
| /* |
| * Create the query to write the value to the service. Note: no need to |
| * guard against RejectedExecutionException, because |
| * DsfSession.getSession() above would only return an active session. |
| */ |
| GetFormattedValueValueQuery query = new GetFormattedValueValueQuery(dmc, formatId, editable); |
| session.getExecutor().execute(query); |
| |
| /* |
| * Now we have the data, go and get it. Since the call is completed now |
| * the ".get()" will not suspend it will immediately return with the |
| * data. |
| */ |
| try { |
| return (String) query.get(); |
| } catch (InterruptedException e) { |
| assert false; |
| return null; |
| } catch (ExecutionException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * @since 1.1 |
| */ |
| public class CanWriteExpressionQuery extends Query<Boolean> { |
| |
| private IExpressionDMContext fDmc; |
| |
| public CanWriteExpressionQuery(IExpressionDMContext dmc) { |
| super(); |
| fDmc = dmc; |
| } |
| |
| @Override |
| protected void execute(final DataRequestMonitor<Boolean> rm) { |
| /* |
| * We're in another dispatch, so we must guard against executor |
| * shutdown again. |
| */ |
| final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); |
| if (session == null) { |
| rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Debug session already shut down.", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| /* |
| * Guard against a disposed service |
| */ |
| IExpressions service = getService(); |
| if (service == null) { |
| rm .setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$ |
| rm.done(); |
| return; |
| } |
| |
| service.canWriteExpression(fDmc, new DataRequestMonitor<Boolean>(session.getExecutor(), rm) { |
| @Override |
| protected void handleSuccess() { |
| /* |
| * All good set return value. |
| */ |
| rm.setData(getData()); |
| rm.done(); |
| } |
| }); |
| } |
| } |
| |
| public boolean canWriteExpression(Object element) { |
| /* |
| * Get the DMC and the session. If element is not an expression DMC, or |
| * session is stale, then bail out. |
| */ |
| IExpressionDMContext dmc = getExpressionDMC(element); |
| if (dmc == null) return false; |
| DsfSession session = DsfSession.getSession(dmc.getSessionId()); |
| if (session == null) return false; |
| |
| /* |
| * Create the query to make the request to the service. Note: no need to |
| * guard against RejectedExecutionException, because |
| * DsfSession.getSession() above would only return an active session. |
| */ |
| CanWriteExpressionQuery query = new CanWriteExpressionQuery(dmc); |
| session.getExecutor().execute(query); |
| |
| /* |
| * Now we have the data, go and get it. Since the call is completed now |
| * the ".get()" will not suspend it will immediately return with the |
| * data. |
| */ |
| try { |
| return query.get(); |
| } catch (InterruptedException e) { |
| assert false; |
| return false; |
| } catch (ExecutionException e) { |
| return false; |
| } |
| } |
| |
| |
| } |