From: aclement Date: Tue, 13 Jun 2006 13:23:14 +0000 (+0000) Subject: 141730: underpinning changes for new handles support. No longer 'leak' implementatio... X-Git-Tag: V1_5_2rc1~41 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f58b5d89371ed4454e65dbbca54032db4039151a;p=aspectj.git 141730: underpinning changes for new handles support. No longer 'leak' implementation details of the handles out into the rest of the code. --- diff --git a/asm/src/org/aspectj/asm/IElementHandleProvider.java b/asm/src/org/aspectj/asm/IElementHandleProvider.java index d88799b62..3e5ef9570 100644 --- a/asm/src/org/aspectj/asm/IElementHandleProvider.java +++ b/asm/src/org/aspectj/asm/IElementHandleProvider.java @@ -37,6 +37,11 @@ public interface IElementHandleProvider { */ public String createHandleIdentifier(File sourceFile, int line,int column,int offset); + /** + * @return a String uniquely identifying this element + */ + public String createHandleIdentifier(IProgramElement ipe); + /** * NOTE: this is necessary for the current implementation to look up nodes, * but we may want to consider removing it. diff --git a/asm/src/org/aspectj/asm/IProgramElement.java b/asm/src/org/aspectj/asm/IProgramElement.java index f88c2dbba..6fbc15b09 100644 --- a/asm/src/org/aspectj/asm/IProgramElement.java +++ b/asm/src/org/aspectj/asm/IProgramElement.java @@ -127,9 +127,11 @@ public interface IProgramElement extends Serializable { * The format of the string handle is not specified, but is stable across * compilation sessions. * - * @return a string representtaion of this element + * @return a string representation of this element */ public String getHandleIdentifier(); + public String getHandleIdentifier(boolean create); + public void setHandleIdentifier(String handle); /** * @return a string representation of this node and all of its children (recursive) diff --git a/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java b/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java index 8260c4805..8c525b083 100644 --- a/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java +++ b/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java @@ -37,16 +37,7 @@ public class AspectJElementHierarchy implements IHierarchy { public IProgramElement getElement(String handle) { IProgramElement cachedEntry = (IProgramElement)handleMap.get(handle); if (cachedEntry!=null) return cachedEntry; - -// StringTokenizer st = new StringTokenizer(handle, ProgramElement.ID_DELIM); -// int line = new Integer(st.nextToken()).intValue(); - // int col = new Integer(st.nextToken()).intValue(); TODO: use column number when available - String file = AsmManager.getDefault().getHandleProvider().getFileForHandle(handle); // st.nextToken(); - int line = AsmManager.getDefault().getHandleProvider().getLineNumberForHandle(handle); // st.nextToken(); - int offSet = AsmManager.getDefault().getHandleProvider().getOffSetForHandle(handle); - - String canonicalSFP = AsmManager.getDefault().getCanonicalFilePath(new File(file)); - IProgramElement ret = findNodeForSourceLineHelper(root,canonicalSFP, line, offSet); + IProgramElement ret = findElementForHandle(handle); if (ret!=null) { cache(handle,ret); } @@ -68,7 +59,10 @@ public class AspectJElementHierarchy implements IHierarchy { } public boolean removeFromFileMap(Object key) { - return (fileMap.remove(key)!=null); + if (fileMap.containsKey(key)) { + return (fileMap.remove(key)!=null); + } + return true; } public void setFileMap(HashMap fileMap) { @@ -344,30 +338,26 @@ public class AspectJElementHierarchy implements IHierarchy { IProgramElement ret = (IProgramElement) handleMap.get(handle); if (ret != null) return ret; -// StringTokenizer st = new StringTokenizer(handle, ProgramElement.ID_DELIM); -// String file = st.nextToken(); -// int line = new Integer(st.nextToken()).intValue(); -// int col = new Integer(st.nextToken()).intValue(); - // TODO: use column number when available - String file = AsmManager.getDefault().getHandleProvider().getFileForHandle(handle); // st.nextToken(); - int line = AsmManager.getDefault().getHandleProvider().getLineNumberForHandle(handle); // st.nextToken(); - int offSet = AsmManager.getDefault().getHandleProvider().getOffSetForHandle(handle); - - ret = findElementForOffSet(file, line, offSet); - if (ret != null) { + ret = findElementForHandle(root,handle); + if (ret != null) { cache(handle,(ProgramElement)ret); } return ret; - -// IProgramElement parent = findElementForType(packageName, typeName); -// if (parent == null) return null; -// if (kind == IProgramElement.Kind.CLASS || -// kind == IProgramElement.Kind.ASPECT) { -// return parent; -// } else { -// return findElementForSignature(parent, kind, name); -// } } + + private IProgramElement findElementForHandle(IProgramElement parent, String handle) { + for (Iterator it = parent.getChildren().iterator(); it.hasNext(); ) { + IProgramElement node = (IProgramElement)it.next(); + if (handle.equals(node.getHandleIdentifier())) { + return node; + } else { + IProgramElement childSearch = findElementForHandle(node,handle); + if (childSearch != null) return childSearch; + } + } + return null; + } + // // private IProgramElement findElementForBytecodeInfo( // IProgramElement node, diff --git a/asm/src/org/aspectj/asm/internal/FullPathHandleProvider.java b/asm/src/org/aspectj/asm/internal/FullPathHandleProvider.java index d58834ae3..6ab254d45 100644 --- a/asm/src/org/aspectj/asm/internal/FullPathHandleProvider.java +++ b/asm/src/org/aspectj/asm/internal/FullPathHandleProvider.java @@ -17,9 +17,12 @@ import java.util.StringTokenizer; import org.aspectj.asm.AsmManager; import org.aspectj.asm.IElementHandleProvider; +import org.aspectj.asm.IProgramElement; import org.aspectj.bridge.ISourceLocation; /** + * HandleProvider of the form '|line|column|offset' + * * @author Mik Kersten */ public class FullPathHandleProvider implements IElementHandleProvider { @@ -70,4 +73,18 @@ public class FullPathHandleProvider implements IElementHandleProvider { st.nextToken(); // skip over the column return new Integer(st.nextToken()).intValue(); } + + public String createHandleIdentifier(IProgramElement ipe) { + if (ipe.getHandleIdentifier(false) != null) { + return ipe.getHandleIdentifier(false); + } + String handle = null; + if (ipe.getSourceLocation() != null) { + handle = createHandleIdentifier(ipe.getSourceLocation()); + } else { + handle = createHandleIdentifier(ISourceLocation.NO_FILE,-1,-1,-1); + } + ipe.setHandleIdentifier(handle); + return handle; + } } diff --git a/asm/src/org/aspectj/asm/internal/OptimizedFullPathHandleProvider.java b/asm/src/org/aspectj/asm/internal/OptimizedFullPathHandleProvider.java index 39013169d..e7b364241 100644 --- a/asm/src/org/aspectj/asm/internal/OptimizedFullPathHandleProvider.java +++ b/asm/src/org/aspectj/asm/internal/OptimizedFullPathHandleProvider.java @@ -21,10 +21,11 @@ import java.util.StringTokenizer; import org.aspectj.asm.AsmManager; import org.aspectj.asm.IElementHandleProvider; +import org.aspectj.asm.IProgramElement; import org.aspectj.bridge.ISourceLocation; /** - * Not currently used - uses int keys rather than the full file path as the first part of the handle. + * Uses int keys rather than the full file path as the first part of the handle. */ public class OptimizedFullPathHandleProvider implements IElementHandleProvider { @@ -96,4 +97,18 @@ public class OptimizedFullPathHandleProvider implements IElementHandleProvider { st.nextToken(); // skip over the column return new Integer(st.nextToken()).intValue(); } + + public String createHandleIdentifier(IProgramElement ipe) { + if (ipe.getHandleIdentifier(false) != null) { + return ipe.getHandleIdentifier(false); + } + String handle = null; + if (ipe.getSourceLocation() != null) { + handle = createHandleIdentifier(ipe.getSourceLocation()); + } else { + handle = createHandleIdentifier(ISourceLocation.NO_FILE,-1,-1,-1); + } + ipe.setHandleIdentifier(handle); + return handle; + } } diff --git a/asm/src/org/aspectj/asm/internal/ProgramElement.java b/asm/src/org/aspectj/asm/internal/ProgramElement.java index af5a16960..7bf2b3e44 100644 --- a/asm/src/org/aspectj/asm/internal/ProgramElement.java +++ b/asm/src/org/aspectj/asm/internal/ProgramElement.java @@ -493,19 +493,25 @@ public class ProgramElement implements IProgramElement { } public String getHandleIdentifier() { - if (null == handle) { - if (sourceLocation != null) { - handle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(sourceLocation); -// return genHandleIdentifier(sourceLocation); - } - } - return handle; + return getHandleIdentifier(true); + } + + public String getHandleIdentifier(boolean create) { + if (null == handle && create) { + handle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(this); + } + return handle; + } + + public void setHandleIdentifier(String handle) { + this.handle = handle; } public List getParameterNames() { List parameterNames = (List)kvpairs.get("parameterNames"); return parameterNames; } + public void setParameterNames(List list) { if (list==null || list.size()==0) return; if (kvpairs==Collections.EMPTY_MAP) kvpairs = new HashMap(); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java index 73ffafee3..b7f81415f 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AsmInterTypeRelationshipProvider.java @@ -15,6 +15,7 @@ package org.aspectj.ajdt.internal.compiler.lookup; //import java.io.IOException; import org.aspectj.asm.AsmManager; +import org.aspectj.asm.IProgramElement; import org.aspectj.asm.IRelationship; import org.aspectj.asm.IRelationshipMap; import org.aspectj.weaver.ResolvedType; @@ -48,17 +49,15 @@ public class AsmInterTypeRelationshipProvider { if (munger.getSourceLocation() != null && munger.getSourceLocation() != null) { - String sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - munger.getSourceLocation().getSourceFile(), - munger.getSourceLocation().getLine(), - munger.getSourceLocation().getColumn(), - munger.getSourceLocation().getOffset()); - - String targetHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - onType.getSourceLocation().getSourceFile(), - onType.getSourceLocation().getLine(), - onType.getSourceLocation().getColumn(), - onType.getSourceLocation().getOffset()); + IProgramElement sourceIPE = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(munger.getSourceLocation()); + String sourceHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(sourceIPE); + + IProgramElement targetIPE = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(onType.getSourceLocation()); + String targetHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(targetIPE); IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap(); if (sourceHandle != null && targetHandle != null) { diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java index 8d90795f5..a65cfbf77 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AsmHierarchyBuilder.java @@ -430,10 +430,18 @@ public class AsmHierarchyBuilder extends ASTVisitor { ReferencePointcut rp = (ReferencePointcut) it.next(); ResolvedMember member = getPointcutDeclaration(rp, declaration); if (member != null) { - IRelationship foreward = AsmManager.getDefault().getRelationshipMap().get(peNode.getHandleIdentifier(), IRelationship.Kind.USES_POINTCUT, "uses pointcut", false, true); - foreward.addTarget(AsmManager.getDefault().getHandleProvider().createHandleIdentifier(member.getSourceLocation())); + IRelationship foreward = AsmManager.getDefault().getRelationshipMap() + .get(peNode.getHandleIdentifier(), + IRelationship.Kind.USES_POINTCUT, "uses pointcut", false, true); + IProgramElement forwardIPE = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(member.getSourceLocation()); + foreward.addTarget(AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(forwardIPE)); - IRelationship back = AsmManager.getDefault().getRelationshipMap().get(AsmManager.getDefault().getHandleProvider().createHandleIdentifier(member.getSourceLocation()), IRelationship.Kind.USES_POINTCUT, "pointcut used by", false, true); + IRelationship back = AsmManager.getDefault().getRelationshipMap() + .get(AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(forwardIPE), + IRelationship.Kind.USES_POINTCUT, "pointcut used by", false, true); back.addTarget(peNode.getHandleIdentifier()); } } diff --git a/tests/src/org/aspectj/systemtest/incremental/tools/AbstractMultiProjectIncrementalAjdeInteractionTestbed.java b/tests/src/org/aspectj/systemtest/incremental/tools/AbstractMultiProjectIncrementalAjdeInteractionTestbed.java index 57ac60c9e..f0a063c38 100644 --- a/tests/src/org/aspectj/systemtest/incremental/tools/AbstractMultiProjectIncrementalAjdeInteractionTestbed.java +++ b/tests/src/org/aspectj/systemtest/incremental/tools/AbstractMultiProjectIncrementalAjdeInteractionTestbed.java @@ -26,6 +26,7 @@ public class AbstractMultiProjectIncrementalAjdeInteractionTestbed extends protected void tearDown() throws Exception { super.tearDown(); AjState.FORCE_INCREMENTAL_DURING_TESTING = false; + configureBuildStructureModel(false); } public void build(String projectName) { diff --git a/weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java b/weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java index 7ea351930..033503e53 100644 --- a/weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java +++ b/weaver/src/org/aspectj/weaver/AsmRelationshipProvider.java @@ -55,33 +55,25 @@ public class AsmRelationshipProvider { // Ensure a node for the target exists IProgramElement targetNode = getNode(AsmManager.getDefault().getHierarchy(), shadow); - - String sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - checker.getSourceLocation().getSourceFile(), - checker.getSourceLocation().getLine(), - checker.getSourceLocation().getColumn(), - checker.getSourceLocation().getOffset()); - + IProgramElement sourceNode = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(checker.getSourceLocation()); + String sourceHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(sourceNode); + String targetHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(targetNode); + if (World.createInjarHierarchy) { checker.createHierarchy(); } - String targetHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - shadow.getSourceLocation().getSourceFile(), - shadow.getSourceLocation().getLine(), - shadow.getSourceLocation().getColumn(), - shadow.getSourceLocation().getOffset()); - IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap(); if (sourceHandle != null && targetHandle != null) { IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE, MATCHED_BY,false,true); foreward.addTarget(targetHandle); -// foreward.getTargets().add(targetHandle); IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE, MATCHES_DECLARE,false,true); if (back != null && back.getTargets() != null) { back.addTarget(sourceHandle); - //back.getTargets().add(sourceHandle); } } } @@ -95,25 +87,21 @@ public class AsmRelationshipProvider { if (!AsmManager.isCreatingModel()) return; String sourceHandle = ""; if (munger.getSourceLocation()!=null && munger.getSourceLocation().getOffset()!=-1) { - sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - munger.getSourceLocation().getSourceFile(), - munger.getSourceLocation().getLine(), - munger.getSourceLocation().getColumn(), - munger.getSourceLocation().getOffset()); + IProgramElement sourceNode = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(munger.getSourceLocation()); + sourceHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(sourceNode); } else { - sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - originatingAspect.getSourceLocation().getSourceFile(), - originatingAspect.getSourceLocation().getLine(), - originatingAspect.getSourceLocation().getColumn(), - originatingAspect.getSourceLocation().getOffset()); + IProgramElement sourceNode = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(originatingAspect.getSourceLocation()); + sourceHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(sourceNode); } if (originatingAspect.getSourceLocation() != null) { - - String targetHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - onType.getSourceLocation().getSourceFile(), - onType.getSourceLocation().getLine(), - onType.getSourceLocation().getColumn(), - onType.getSourceLocation().getOffset()); + IProgramElement targetNode = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(onType.getSourceLocation()); + String targetHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(targetNode); IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap(); if (sourceHandle != null && targetHandle != null) { @@ -131,17 +119,15 @@ public class AsmRelationshipProvider { public void addDeclareParentsRelationship(ISourceLocation decp,ResolvedType targetType, List newParents) { if (!AsmManager.isCreatingModel()) return; - String sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(decp.getSourceFile(),decp.getLine(),decp.getColumn(),decp.getOffset()); - - IProgramElement ipe = AsmManager.getDefault().getHierarchy().findElementForHandle(sourceHandle); + IProgramElement sourceNode = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(decp); + String sourceHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(sourceNode); + IProgramElement targetNode = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(targetType.getSourceLocation()); + String targetHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(targetNode); - - String targetHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - targetType.getSourceLocation().getSourceFile(), - targetType.getSourceLocation().getLine(), - targetType.getSourceLocation().getColumn(), - targetType.getSourceLocation().getOffset()); - IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap(); if (sourceHandle != null && targetHandle != null) { IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES,false,true); @@ -159,15 +145,16 @@ public class AsmRelationshipProvider { */ public void addDeclareAnnotationRelationship(ISourceLocation declareAnnotationLocation,ISourceLocation annotatedLocation) { if (!AsmManager.isCreatingModel()) return; - String sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(declareAnnotationLocation.getSourceFile(),declareAnnotationLocation.getLine(), - declareAnnotationLocation.getColumn(),declareAnnotationLocation.getOffset()); - IProgramElement declareAnnotationPE = AsmManager.getDefault().getHierarchy().findElementForHandle(sourceHandle); - - String targetHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - annotatedLocation.getSourceFile(), - annotatedLocation.getLine(), - annotatedLocation.getColumn(), - annotatedLocation.getOffset()); + + IProgramElement sourceNode = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(declareAnnotationLocation); + String sourceHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(sourceNode); + + IProgramElement targetNode = AsmManager.getDefault().getHierarchy() + .findElementForSourceLine(annotatedLocation); + String targetHandle = AsmManager.getDefault().getHandleProvider() + .createHandleIdentifier(targetNode); IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap(); if (sourceHandle != null && targetHandle != null) { @@ -205,7 +192,9 @@ public class AsmRelationshipProvider { AdviceKind ak = ((Advice)munger).getKind(); ai.setExtraAdviceInformation(ak.getName()); IProgramElement adviceElement = AsmManager.getDefault().getHierarchy().findElementForHandle(adviceHandle); - adviceElement.setExtraInfo(ai); + if (adviceElement != null) { + adviceElement.setExtraInfo(ai); + } if (adviceHandle != null && targetNode != null) { @@ -392,9 +381,9 @@ public class AsmRelationshipProvider { if (methodElem == null) return; try { - String sourceHandle = - AsmManager.getDefault().getHandleProvider().createHandleIdentifier(sourceLocation.getSourceFile(),sourceLocation.getLine(), - sourceLocation.getColumn(),sourceLocation.getOffset()); + + IProgramElement sourceNode = AsmManager.getDefault().getHierarchy().findElementForSourceLine(sourceLocation); + String sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(sourceNode); String targetHandle = methodElem.getHandleIdentifier(); IRelationshipMap mapper = AsmManager.getDefault().getRelationshipMap(); @@ -433,9 +422,8 @@ public class AsmRelationshipProvider { IProgramElement fieldElem = AsmManager.getDefault().getHierarchy().findElementForSignature(typeElem,IProgramElement.Kind.FIELD,field.getName()); if (fieldElem== null) return; - String sourceHandle = - AsmManager.getDefault().getHandleProvider().createHandleIdentifier(sourceLocation.getSourceFile(),sourceLocation.getLine(), - sourceLocation.getColumn(),sourceLocation.getOffset()); + IProgramElement sourceNode = AsmManager.getDefault().getHierarchy().findElementForSourceLine(sourceLocation); + String sourceHandle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(sourceNode); String targetHandle = fieldElem.getHandleIdentifier(); diff --git a/weaver/src/org/aspectj/weaver/ShadowMunger.java b/weaver/src/org/aspectj/weaver/ShadowMunger.java index 6e045e83b..df21a4a82 100644 --- a/weaver/src/org/aspectj/weaver/ShadowMunger.java +++ b/weaver/src/org/aspectj/weaver/ShadowMunger.java @@ -101,11 +101,8 @@ public abstract class ShadowMunger implements PartialOrder.PartialComparable, IH if (World.createInjarHierarchy) { createHierarchy(); } - handle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier( - sl.getSourceFile(), - sl.getLine(), - sl.getColumn(), - sl.getOffset()); + IProgramElement ipe = AsmManager.getDefault().getHierarchy().findElementForSourceLine(sl); + handle = AsmManager.getDefault().getHandleProvider().createHandleIdentifier(ipe); } } return handle;