/******************************************************************************* * Copyright (c) 2006, 2010 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.examples.dsf.timers; import java.util.concurrent.ExecutionException; import java.util.concurrent.RejectedExecutionException; 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.service.DsfServices; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin; import org.eclipse.cdt.examples.dsf.timers.AlarmService.TriggerDMContext; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.swt.widgets.Shell; import org.osgi.framework.InvalidSyntaxException; import org.osgi.util.tracker.ServiceTracker; /** * Cell modifier used to edit the trigger value. */ @ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()") public class TriggerCellModifier implements ICellModifier { private final DsfSession fSession; // Need to use the OSGi service tracker (instead of DsfServiceTracker), // because it's being accessed on multiple threads. @ThreadSafe private ServiceTracker fServiceTracker; /** * Constructor for the modifier requires a valid session in order to * initialize the service tracker. * @param session DSF session this modifier will use. */ public TriggerCellModifier(DsfSession session) { fSession = session; } public boolean canModify(Object element, String property) { return TimersViewColumnPresentation.COL_VALUE.equals(property) && getAlarmDMC(element) != null; } public Object getValue(Object element, String property) { if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return ""; // Get the context and the session. If element is not an trigger // context or if the session is stale then bail out. TriggerDMContext triggerCtx = getAlarmDMC(element); if (triggerCtx == null) return ""; DsfSession session = DsfSession.getSession(triggerCtx.getSessionId()); if (session == null) return ""; // Create the query to request the value from service. GetValueQuery query = new GetValueQuery(triggerCtx); try { session.getExecutor().execute(query); } catch (RejectedExecutionException e) { return ""; } try { return query.get().toString(); } catch (InterruptedException e) { assert false; return ""; } catch (ExecutionException e) { return ""; } } public void modify(Object element, String property, Object value) { if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return; TriggerDMContext dmc = getAlarmDMC(element); if (dmc == null) return; DsfSession session = DsfSession.getSession(dmc.getSessionId()); if (session == null) return; // Shell is used in displaying error dialogs. Shell shell = getShell(); if (shell == null) return; Integer intValue = null; if (value instanceof String) { try { intValue = new Integer(((String)value).trim()); } catch (NumberFormatException e) { MessageDialog.openError(shell, "Invalid Value", "Please enter a positive integer"); return; } if (intValue.intValue() <= 0) { MessageDialog.openError(shell, "Invalid Value", "Please enter a positive integer"); return; } } // Create the query to write the value to the service. SetValueQuery query = new SetValueQuery(dmc, intValue); try { session.getExecutor().execute(query); } catch (RejectedExecutionException e) { // View must be shutting down, no need to show error dialog. } try { // Return value is irrelevant, any error would come through with an exception. query.get().toString(); } catch (InterruptedException e) { assert false; } catch (ExecutionException e) { // View must be shutting down, no need to show error dialog. } } /** * Need to dispose the cell modifier property because of the service * tracker. */ @ThreadSafe public synchronized void dispose() { if (fServiceTracker != null) { fServiceTracker.close(); } } private Shell getShell() { if (DsfExamplesPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow() != null) { return DsfExamplesPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); } return null; } private TriggerDMContext getAlarmDMC(Object element) { if (element instanceof IAdaptable) { return (TriggerDMContext)((IAdaptable)element).getAdapter(TriggerDMContext.class); } return null; } @ThreadSafe private synchronized AlarmService getService(TriggerDMContext dmc) { // Create and initialize the service tracker if needed. String serviceId = DsfServices.createServiceFilter( AlarmService.class, fSession.getId() ); if (fServiceTracker == null) { try { fServiceTracker = new ServiceTracker( DsfExamplesPlugin.getBundleContext(), DsfExamplesPlugin.getBundleContext().createFilter(serviceId), null); fServiceTracker.open(); } catch (InvalidSyntaxException e) { return null; } } // Get the service. return (AlarmService)fServiceTracker.getService(); } private class GetValueQuery extends Query<Integer> { final TriggerDMContext fDmc; private GetValueQuery(TriggerDMContext dmc) { super(); fDmc = dmc; } @Override protected void execute(final DataRequestMonitor<Integer> 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 execute the "done" 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, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Debug session already shut down.", null)); //$NON-NLS-1$ rm.done(); return; } AlarmService service = getService(fDmc); if (service == null) { rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service not available", null)); rm.done(); return; } int value = service.getTriggerValue(fDmc); if (value == -1) { rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Invalid context", null)); rm.done(); return; } rm.setData(value); rm.done(); } } private class SetValueQuery extends Query<Object> { TriggerDMContext fDmc; int fValue; SetValueQuery(TriggerDMContext dmc, int value) { super(); fDmc = dmc; fValue = value; } @Override protected void execute(final DataRequestMonitor<Object> rm) { // Guard against terminated session final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); if (session == null) { rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Debug session already shut down.", null)); //$NON-NLS-1$ rm.done(); return; } // Guard against a disposed service AlarmService service = getService(fDmc); if (service == null) { rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service not available", null)); rm.done(); return; } // Finally set the value and return. service.setTriggerValue(fDmc, fValue); // Return value is irrelevant. rm.setData(new Object()); rm.done(); } } }