/*******************************************************************************
* Copyright (c) 2012 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.tcf.debug.test.services;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.eclipse.tcf.debug.test.util.ICache;
import org.eclipse.tcf.debug.test.util.TokenCache;
import org.eclipse.tcf.debug.test.util.TransactionCache;
import org.eclipse.tcf.protocol.IChannel;
import org.eclipse.tcf.protocol.IToken;
import org.eclipse.tcf.services.ILineNumbers;
import org.eclipse.tcf.services.ILineNumbers.CodeArea;
import org.eclipse.tcf.services.IMemoryMap;
import org.eclipse.tcf.services.IMemoryMap.MemoryMapListener;
import org.eclipse.tcf.services.IRunControl.RunControlContext;
import org.eclipse.tcf.services.IRunControl.RunControlListener;
/**
*
*/
public class LineNumbersCM extends AbstractCacheManager {
private ResetMap fMemContextResetMap = new ResetMap();
private ILineNumbers fService;
private IMemoryMap fMemoryMap;
private RunControlCM fRunControlCM;
public LineNumbersCM(IChannel channel, ILineNumbers lineNumbers, IMemoryMap memMap, RunControlCM runControlCM) {
super(channel);
fService = lineNumbers;
fMemoryMap = memMap;
fMemoryMap.addListener(fMemoryMapListener);
fRunControlCM = runControlCM;
fRunControlCM.addListener(fRunControlListener);
}
@Override
public void dispose() {
fRunControlCM.removeListener(fRunControlListener);
fMemoryMap.removeListener(fMemoryMapListener);
super.dispose();
}
abstract private class MapToSourceKey<V> extends IdKey<V> {
private final Number fStartAdddress;
private final Number fEndAddress;
public MapToSourceKey(Class<V> cacheClass, String id, Number startAddress, Number endAddress) {
super(cacheClass, id);
fStartAdddress = startAddress;
fEndAddress = endAddress;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) && obj instanceof MapToSourceKey<?>) {
MapToSourceKey<?> other = (MapToSourceKey<?>)obj;
return fStartAdddress.equals(other.fStartAdddress) && fEndAddress.equals(other.fEndAddress);
}
return false;
}
@Override
public int hashCode() {
return super.hashCode() + fStartAdddress.hashCode() + fEndAddress.hashCode();
}
}
public ICache<CodeArea[]> mapToSource(final String context_id, final Number start_address, final Number end_address) {
class MyCache extends TransactionCache<ILineNumbers.CodeArea[]> {
@Override
protected CodeArea[] process() throws InvalidCacheException, ExecutionException {
RunControlContext rcContext = validate(fRunControlCM.getContext(context_id));
String mem_id = rcContext.getProcessID();
if (mem_id == null) {
// TODO: is this the correct fall-back. Should we save the parent ID for reset?
mem_id = context_id;
}
return validate( doMapToSource(mem_id, start_address, end_address) );
}
}
return mapCache(new MapToSourceKey<MyCache>(MyCache.class, context_id, start_address, end_address) {
@Override MyCache createCache() { return new MyCache(); }
});
}
private ICache<CodeArea[]> doMapToSource(final String mem_id, final Number start_address, final Number end_address) {
class MyCache extends TokenCache<CodeArea[]> implements ILineNumbers.DoneMapToSource {
MyCache() { super(fChannel); }
@Override
protected IToken retrieveToken() {
return fService.mapToSource(mem_id, start_address, end_address, this);
}
public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) {
fMemContextResetMap.addValid(mem_id, this);
set(token, areas, error);
}
};
return mapCache(new MapToSourceKey<MyCache>(MyCache.class, mem_id, start_address, end_address) {
@Override MyCache createCache() { return new MyCache(); }
});
}
abstract private class MapToMemoryKey<V> extends IdKey<V> {
private final String fFile;
private final int fLine;
private final int fColumn;
public MapToMemoryKey(Class<V> cacheClass, String id, String file, int line, int col) {
super(cacheClass, id);
fFile = file;
fLine = line;
fColumn = col;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj) && obj instanceof MapToMemoryKey<?>) {
MapToMemoryKey<?> other = (MapToMemoryKey<?>)obj;
return fFile.equals(other.fFile) && fLine == other.fLine && fColumn == other.fColumn;
}
return false;
}
@Override
public int hashCode() {
return super.hashCode() + fFile.hashCode()^fLine^(fColumn + 1);
}
}
public ICache<CodeArea[]> mapToMemory(final String context_id, final String file, final int line, final int column) {
class MyCache extends TransactionCache<ILineNumbers.CodeArea[]> {
private String fId = context_id;
protected CodeArea[] process() throws InvalidCacheException, ExecutionException {
RunControlContext rcContext = validate(fRunControlCM.getContext(fId));
String mem_id = rcContext.getProcessID();
if (mem_id == null) {
// TODO: is this the correct fall-back. Should we save the parent ID for reset?
mem_id = fId;
}
return validate( doMapToMemory(mem_id, file, line, column) );
}
}
return mapCache(new MapToMemoryKey<MyCache>(MyCache.class, context_id, file, line, column) {
@Override MyCache createCache() { return new MyCache(); }
});
}
private ICache<CodeArea[]> doMapToMemory(final String mem_id, final String file, final int line, final int column) {
class MyCache extends TokenCache<CodeArea[]> implements ILineNumbers.DoneMapToMemory {
MyCache() { super(fChannel); }
@Override
protected IToken retrieveToken() {
return fService.mapToMemory(mem_id, file, line, column, this);
}
public void doneMapToMemory(IToken token, Exception error, CodeArea[] areas) {
fMemContextResetMap.addValid(mem_id, this);
set(token, areas, error);
}
};
return mapCache(new MapToMemoryKey<MyCache>(MyCache.class, mem_id, file, line, column) {
@Override MyCache createCache() { return new MyCache(); }
});
}
interface DoneMapToMemory {
void doneMapToMemory(IToken token, Exception error, CodeArea[] areas);
}
private RunControlListener fRunControlListener = new RunControlListener() {
public void contextRemoved(String[] context_ids) {
for (String id : context_ids) {
resetContext(id);
}
}
public void contextAdded(RunControlContext[] contexts) {}
public void contextChanged(RunControlContext[] contexts) {}
public void contextSuspended(String context, String pc, String reason, Map<String, Object> params) {}
public void contextResumed(String context) {}
public void containerSuspended(String context, String pc, String reason, Map<String, Object> params,
String[] suspended_ids) {}
public void containerResumed(String[] context_ids) {}
public void contextException(String context, String msg) {}
};
private void resetContext(String id) {
fMemContextResetMap.reset(id);
}
private MemoryMapListener fMemoryMapListener = new MemoryMapListener() {
public void changed(String context_id) {
resetContext(context_id);
}
};
}