/*******************************************************************************
* Copyright (c) 2011, 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.services.ResetMap.IResettable;
import org.eclipse.tcf.debug.test.util.AbstractCache;
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.IMemoryMap;
import org.eclipse.tcf.services.IMemoryMap.MemoryMapListener;
import org.eclipse.tcf.services.IRunControl.RunControlContext;
import org.eclipse.tcf.services.IRunControl.RunControlListener;
import org.eclipse.tcf.services.ISymbols;
import org.eclipse.tcf.services.ISymbols.Symbol;
/**
*
*/
public class SymbolsCM extends AbstractCacheManager {
private ResetMap fRunControlResetMap = new ResetMap();
private ResetMap fMemoryResetMap = new ResetMap();
private ISymbols fService;
private IMemoryMap fMemoryMap;
private RunControlCM fRunControlCM;
public SymbolsCM(IChannel channel, ISymbols service, RunControlCM runControl, IMemoryMap memoryMap) {
super(channel);
fService = service;
fRunControlCM = runControl;
fRunControlCM.addListener(fRunControlListener);
fMemoryMap = memoryMap;
fMemoryMap.addListener(fMemoryListener);
}
@Override
public void dispose() {
fRunControlCM.removeListener(fRunControlListener);
fMemoryMap.removeListener(fMemoryListener);
super.dispose();
}
abstract private class SymbolCache<V> extends TransactionCache<V> {
protected final AbstractCache<V> fInner;
public SymbolCache(AbstractCache<V> inner) {
fInner = inner;
}
abstract protected String getSymbolId();
@Override
protected V process() throws InvalidCacheException, ExecutionException {
validate(fInner);
Symbol sym = validate( getContext(getSymbolId()) );
addPending(sym, fInner);
RunControlContext rcContext = validate(fRunControlCM.getContext(sym.getOwnerID()));
addValid(sym, rcContext, fInner);
return validate(fInner);
}
}
private void addPending(Symbol sym, IResettable cache) {
if (sym.getUpdatePolicy() == ISymbols.UPDATE_ON_EXE_STATE_CHANGES) {
fRunControlResetMap.addPending(cache);
}
fMemoryResetMap.addPending(cache);
}
private void addValid(Symbol sym, RunControlContext rcContext, IResettable cache) {
if (sym.getUpdatePolicy() == ISymbols.UPDATE_ON_EXE_STATE_CHANGES) {
String ownerId = sym.getOwnerID();
fRunControlResetMap.addValid(ownerId, cache);
}
fMemoryResetMap.addValid(rcContext.getProcessID(), cache);
}
private class ChildrenCache extends SymbolCache<String[]> {
public ChildrenCache(InnerChildrenCache inner) {
super(inner);
}
@Override
protected String getSymbolId() {
return ((InnerChildrenCache)fInner).fId;
}
}
private class InnerChildrenCache extends TokenCache<String[]> implements ISymbols.DoneGetChildren {
private final String fId;
public InnerChildrenCache(String id) {
super(fChannel);
fId = id;
}
@Override
protected IToken retrieveToken() {
fRunControlResetMap.addPending(this);
return fService.getChildren(fId, this);
}
public void doneGetChildren(IToken token, Exception error, String[] context_ids) {
set(token, context_ids, error);
}
};
private class ChildrenCacheKey extends IdKey<ChildrenCache> {
public ChildrenCacheKey(String id) {
super(ChildrenCache.class, id);
}
@Override ChildrenCache createCache() { return new ChildrenCache( new InnerChildrenCache(fId) ); }
}
public ICache<String[]> getChildren(String id) {
return mapCache(new ChildrenCacheKey(id));
}
public ICache<Symbol> getContext(final String id) {
class MyCache extends TransactionCache<Symbol> {
class InnerCache extends TokenCache<Symbol> implements ISymbols.DoneGetContext{
InnerCache() { super(fChannel); }
@Override
protected IToken retrieveToken() {
return fService.getContext(id, this);
}
@Override
public void doneGetContext(IToken token, Exception error, Symbol context) {
set(token, context, error);
}
};
private final InnerCache fInner = new InnerCache();
@Override
protected Symbol process() throws InvalidCacheException, ExecutionException {
Symbol sym = validate(fInner);
addPending(sym, fInner);
RunControlContext rcContext = validate(fRunControlCM.getContext(sym.getOwnerID()));
addValid(sym, rcContext, fInner);
return validate(fInner);
}
};
return mapCache(new IdKey<MyCache>(MyCache.class, id) {
@Override MyCache createCache() { return new MyCache(); }
});
}
public ICache<Map<String, Object>> getLocationInfo(final String symbol_id) {
class InnerCache extends TokenCache<Map<String,Object>> implements ISymbols.DoneGetLocationInfo {
InnerCache() { super(fChannel); }
@Override
protected IToken retrieveToken() {
return fService.getLocationInfo(symbol_id, this);
}
public void doneGetLocationInfo(IToken token, Exception error, Map<String,Object> props) {
set(token, props, error);
}
}
class MyCache extends SymbolCache<Map<String,Object>> {
public MyCache() {
super(new InnerCache());
}
@Override
protected String getSymbolId() {
return symbol_id;
}
}
return mapCache(new IdKey<MyCache>(MyCache.class, symbol_id) {
@Override MyCache createCache() { return new MyCache(); }
});
}
/**
* Client call back interface for getLocationInfo().
*/
interface DoneGetLocationInfo {
/**
* Called when location information retrieval is done.
* @param token - command handle.
* @param error � error description if operation failed, null if succeeded.
* @param props - symbol location properties, see LOC_*.
*/
void doneGetLocationInfo(IToken token, Exception error, Map<String,Object> props);
}
private class FindCache extends SymbolCache<String> {
public FindCache(InnerFindCache inner) {
super(inner);
}
@Override
protected String getSymbolId() {
return fInner.getData();
}
}
class InnerFindCache extends TokenCache<String> implements ISymbols.DoneFind {
private final String fId;
private final Number fIp;
private final String fName;
public InnerFindCache(String id, Number ip, String name) {
super(fChannel);
fId = id;
fIp = ip;
fName = name;
}
@Override
protected IToken retrieveToken() {
return fService.find(fId, fIp, fName, this);
}
public void doneFind(IToken token, Exception error, String symbol_id) {
set(token, symbol_id, error);
}
}
private class FindCacheKey extends IdKey<FindCache> {
private final Number fIp;
private final String fName;
public FindCacheKey(String id, Number ip, String name) {
super(FindCache.class, id);
fIp = ip;
fName = name;
}
@Override FindCache createCache() { return new FindCache(new InnerFindCache(fId, fIp, fName)); }
@Override
public boolean equals(Object obj) {
if (super.equals(obj) && obj instanceof FindCacheKey) {
FindCacheKey other = (FindCacheKey)obj;
return fIp.equals(other.fIp) && fName.equals(other.fName);
}
return false;
}
@Override
public int hashCode() {
return super.hashCode() + fIp.hashCode() + fName.hashCode();
}
}
public ICache<String> find(String context_id, Number ip, String name) {
return mapCache(new FindCacheKey(context_id, ip, name));
}
private class FindByAddrCache extends SymbolCache<String> {
public FindByAddrCache(InnerFindByAddrCache inner) {
super(inner);
}
@Override
protected String getSymbolId() {
return fInner.getData();
}
}
private class InnerFindByAddrCache extends TokenCache<String> implements ISymbols.DoneFind {
private final String fId;
private final Number fAddr;
public InnerFindByAddrCache(String id, Number addr) {
super(fChannel);
fId = id;
fAddr = addr;
}
@Override
protected IToken retrieveToken() {
return fService.findByAddr(fId, fAddr, this);
}
public void doneFind(IToken token, Exception error, String symbol_id) {
set(token, symbol_id, error);
}
}
private class FindByAddrCacheKey extends IdKey<FindByAddrCache> {
private final Number fAddr;
public FindByAddrCacheKey(String id, Number addr) {
super(FindByAddrCache.class, id);
fAddr = addr;
}
@Override FindByAddrCache createCache() { return new FindByAddrCache(new InnerFindByAddrCache(fId, fAddr)); }
@Override
public boolean equals(Object obj) {
if (super.equals(obj) && obj instanceof FindByAddrCacheKey) {
FindByAddrCacheKey other = (FindByAddrCacheKey)obj;
return fAddr.equals(other.fAddr);
}
return false;
}
@Override
public int hashCode() {
return super.hashCode() + fAddr.hashCode();
}
}
public ICache<String> findByAddr(String context_id, Number addr) {
return mapCache(new FindByAddrCacheKey(context_id, addr));
}
private RunControlListener fRunControlListener = new RunControlListener() {
public void contextAdded(RunControlContext[] contexts) {
}
public void contextChanged(RunControlContext[] contexts) {
for (RunControlContext context : contexts) {
resetRunControlContext(context.getID());
}
}
public void contextRemoved(String[] context_ids) {
for (String id : context_ids) {
resetRunControlContext(id);
fMemoryResetMap.reset(id);
}
}
public void contextSuspended(String context, String pc, String reason, Map<String, Object> params) {
resetRunControlContext(context);
}
public void contextResumed(String context) {
resetRunControlContext(context);
}
public void containerSuspended(String context, String pc, String reason, Map<String, Object> params,
String[] suspended_ids)
{
for (String id : suspended_ids) {
resetRunControlContext(id);
}
}
public void containerResumed(String[] context_ids) {
for (String id : context_ids) {
resetRunControlContext(id);
}
}
public void contextException(String context, String msg) {
resetRunControlContext(context);
}
};
private void resetRunControlContext(String id) {
fRunControlResetMap.reset(id);
}
private MemoryMapListener fMemoryListener = new MemoryMapListener() {
public void changed(String context_id) {
fMemoryResetMap.reset(context_id);
}
};
}