]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.ui/src/org/simantics/ui/workbench/editor/EditorRegistry.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / workbench / editor / EditorRegistry.java
index c4d0dd294efe056e9d31e96f20c3a94212f2ec24..b952966e493509ad5e11e6b8897b29273c52deaa 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.ui.workbench.editor;\r
-\r
-import java.io.IOException;\r
-import java.lang.ref.WeakReference;\r
-import java.net.URL;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.WeakHashMap;\r
-\r
-import org.eclipse.core.commands.contexts.ContextManagerEvent;\r
-import org.eclipse.core.commands.contexts.IContextManagerListener;\r
-import org.eclipse.core.runtime.CoreException;\r
-import org.eclipse.core.runtime.FileLocator;\r
-import org.eclipse.core.runtime.IConfigurationElement;\r
-import org.eclipse.core.runtime.IExtension;\r
-import org.eclipse.core.runtime.IExtensionPoint;\r
-import org.eclipse.core.runtime.IStatus;\r
-import org.eclipse.core.runtime.MultiStatus;\r
-import org.eclipse.core.runtime.Platform;\r
-import org.eclipse.core.runtime.Status;\r
-import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;\r
-import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;\r
-import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;\r
-import org.eclipse.core.runtime.dynamichelpers.IFilter;\r
-import org.eclipse.jface.resource.ImageDescriptor;\r
-import org.eclipse.ui.IEditorDescriptor;\r
-import org.eclipse.ui.IWorkbench;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.eclipse.ui.contexts.IContextService;\r
-import org.osgi.framework.Bundle;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.common.request.PossibleIndexRoot;\r
-import org.simantics.db.common.utils.Logger;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.adapter.Instances;\r
-import org.simantics.modeling.ModelingResources;\r
-import org.simantics.scl.reflection.OntologyVersions;\r
-import org.simantics.ui.internal.Activator;\r
-import org.simantics.ui.utils.ResourceAdaptionUtils;\r
-import org.simantics.utils.datastructures.MapList;\r
-import org.simantics.utils.ui.ExceptionUtils;\r
-import org.simantics.utils.ui.action.IPriorityAction;\r
-\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- */\r
-public final class EditorRegistry implements IExtensionChangeHandler, IEditorRegistry {\r
-\r
-    /**\r
-     * The maximum amount of entries to cache\r
-     * {@link #getAdaptersFor(ReadGraph, Resource)} results for. Context activation\r
-     * changes invalidate this cache.\r
-     */\r
-    private static final int    MAX_CACHE_SIZE       = 50;\r
-\r
-\r
-    private final static String NAMESPACE            = Activator.PLUGIN_ID;\r
-\r
-    private final static String EP_NAME              = "resourceEditorAdapter";\r
-\r
-\r
-    private final static String EL_NAME_ADAPTER      = "adapter";\r
-\r
-    private final static String EL_NAME_ADAPTERCLASS = "adapterClass";\r
-\r
-    private final static String EL_NAME_GROUP        = "group";\r
-\r
-    private final static String EL_NAME_IN_CONTEXT   = "inContext";\r
-\r
-\r
-    private static final String ATTR_CLASS           = "class";\r
-\r
-    private static final String ATTR_IMAGE           = "image";\r
-\r
-    private static final String ATTR_LABEL           = "label";\r
-\r
-    private static final String ATTR_TYPE_URIS       = "type_uris";\r
-\r
-    private static final String ATTR_EDITOR_ID       = "editorId";\r
-\r
-    private static final String ATTR_PRIORITY        = "priority";\r
-\r
-    private static final String ATTR_GROUP_ID        = "groupId";\r
-\r
-    private static final String ATTR_ID              = "id";\r
-\r
-\r
-    private static class Group {\r
-        public final String id;\r
-        public final List<EditorAdapterDescriptor> adapters;\r
-\r
-        Group(String id) {\r
-            this.id = id;\r
-            this.adapters = new ArrayList<EditorAdapterDescriptor>();\r
-        }\r
-        Group(Group g) {\r
-            this.id = g.id;\r
-            this.adapters = new ArrayList<EditorAdapterDescriptor>(g.adapters);\r
-        }\r
-        void add(EditorAdapterDescriptor desc) {\r
-            adapters.add(desc);\r
-        }\r
-        void remove(EditorAdapterDescriptor desc) {\r
-            adapters.remove(desc);\r
-        }\r
-    }\r
-\r
-    private static final EditorAdapter[]         EMPTY_ADAPTER_ARRAY  = new EditorAdapter[0];\r
-\r
-    private static EditorRegistry                INSTANCE;\r
-\r
-    private ExtensionTracker                             tracker;\r
-\r
-    private EditorAdapterDescriptorImpl[]            extensions           = new EditorAdapterDescriptorImpl[0];\r
-\r
-    private Map<String, EditorAdapterDescriptorImpl> idToExtension        = new HashMap<String, EditorAdapterDescriptorImpl>();\r
-\r
-    private Map<String, Group>                           groupMap             = new HashMap<String, Group>();\r
-\r
-    private WeakHashMap<Object, EditorAdapter[]> adapterCache         = new WeakHashMap<Object, EditorAdapter[]>(\r
-            MAX_CACHE_SIZE);\r
-\r
-    private CircularBuffer<Object>                       cacheQueue           = new CircularBuffer<Object>(\r
-            MAX_CACHE_SIZE);\r
-\r
-    /**\r
-     * A set of all the context id's that are currently referenced by all the\r
-     * loaded resourceEditorAdapter extensions.\r
-     */\r
-    private Set<String>                                  referencedContextIds = new HashSet<String>();\r
-\r
-    /**\r
-     * The current set of active contexts.\r
-     */\r
-    private Set<String>                                  activeContextIds = new HashSet<String>();\r
-\r
-    /**\r
-     * Used to store all input -> editor mappings. In the Eclipse IDE, this\r
-     * information is stored as persistent properties in each IFile represented\r
-     * by eclipse Resource's. This implementation stores all the mappings in\r
-     * this single map.\r
-     * \r
-     * Maybe in the future it would be possible to store these mapping in the\r
-     * graph in a way that allows us not to publish those changes to the outside\r
-     * world.\r
-     */\r
-    private final EditorMappingImpl                                editorMapping        = new EditorMappingImpl();\r
-\r
-    public synchronized static IEditorRegistry getInstance() {\r
-        if (INSTANCE == null) {\r
-            INSTANCE = new EditorRegistry();\r
-        }\r
-        return INSTANCE;\r
-    }\r
-\r
-    public static synchronized void dispose() {\r
-        if (INSTANCE != null) {\r
-            INSTANCE.close();\r
-            INSTANCE = null;\r
-        }\r
-    }\r
-\r
-    private EditorRegistry() {\r
-        tracker = new ExtensionTracker();\r
-\r
-        // Cache defined actions\r
-        IExtensionPoint expt = Platform.getExtensionRegistry().getExtensionPoint(NAMESPACE, EP_NAME);\r
-        loadExtensions(expt.getConfigurationElements());\r
-\r
-        // Start tracking for new and removed extensions\r
-        IFilter filter = ExtensionTracker.createExtensionPointFilter(expt);\r
-        tracker.registerHandler(this, filter);\r
-\r
-        hookListeners();\r
-    }\r
-\r
-    private void close() {\r
-        unhookListeners();\r
-\r
-        tracker.close();\r
-        tracker = null;\r
-\r
-        editorMapping.clear();\r
-\r
-        extensions = null;\r
-        idToExtension = null;\r
-        groupMap = null;\r
-        adapterCache = null;\r
-        cacheQueue = null;\r
-    }\r
-\r
-//    /**\r
-//     * Must reset {@link #getAdaptersFor(ReadGraph, Resource)} query caches when\r
-//     * perspectives are changed because EditorAdapters may return\r
-//     * different results in different perspectives.\r
-//     */\r
-//    private IPerspectiveListener perspectiveListener = new PerspectiveAdapter() {\r
-//        public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {\r
-//            clearCache();\r
-//        }\r
-//    };\r
-\r
-    private final IContextManagerListener contextListener = new IContextManagerListener() {\r
-        @Override\r
-        public void contextManagerChanged(ContextManagerEvent event) {\r
-            if (event.isActiveContextsChanged()) {\r
-                //System.out.println("EVENT: " + event.isActiveContextsChanged() + ", " + event.isContextChanged() + ", " + event.isContextDefined() + ", " + Arrays.toString(event.getPreviouslyActiveContextIds().toArray()));\r
-\r
-                Collection<?> active = event.getContextManager().getActiveContextIds();\r
-                Collection<?> previouslyActive = event.getPreviouslyActiveContextIds();\r
-\r
-                Collection<String> added = new HashSet<String>(4);\r
-                Collection<String> removed = new HashSet<String>(4);\r
-\r
-                for (Object o : active) {\r
-                    if (!previouslyActive.contains(o))\r
-                        added.add((String) o);\r
-                }\r
-                for (Object o : previouslyActive) {\r
-                    if (!active.contains(o))\r
-                        removed.add((String) o);\r
-                }\r
-\r
-                //System.out.println("ADDED: " + Arrays.toString(added.toArray()) + ", REMOVED: " + Arrays.toString(removed.toArray()));\r
-                contextChange(added, removed);\r
-            }\r
-        }\r
-    };\r
-\r
-    private boolean containsAny(Collection<String> c, Collection<String> anyOf) {\r
-        if (anyOf.isEmpty())\r
-            return false;\r
-        for (String s : anyOf)\r
-            if (c.contains(s))\r
-                return true;\r
-        return false;\r
-    }\r
-\r
-    private void contextChange(Collection<String> added, Collection<String> removed) {\r
-        // Update active context id set\r
-        if (!added.isEmpty())\r
-            activeContextIds.addAll(added);\r
-        if (!removed.isEmpty())\r
-            activeContextIds.remove(removed);\r
-\r
-        // Clear caches if necessary\r
-        if (containsAny(referencedContextIds, added) || containsAny(referencedContextIds, removed)) {\r
-            clearCache();\r
-        }\r
-    }\r
-\r
-    @SuppressWarnings("unchecked")\r
-    private void hookListeners() {\r
-        IWorkbench wb = PlatformUI.getWorkbench();\r
-        IContextService contextService = (IContextService) wb.getService(IContextService.class);\r
-        contextService.addContextManagerListener(contextListener);\r
-        activeContextIds = new HashSet<String>(contextService.getActiveContextIds());\r
-    }\r
-\r
-    private void unhookListeners() {\r
-        IWorkbench wb = PlatformUI.getWorkbench();\r
-        IContextService contextService = (IContextService) wb.getService(IContextService.class);\r
-        if (contextService != null) {\r
-            contextService.removeContextManagerListener(contextListener);\r
-        }\r
-    }\r
-\r
-    private String[] parseInContexts(IConfigurationElement parent) {\r
-        List<String> contexts = null;\r
-        for (IConfigurationElement el : parent.getChildren(EL_NAME_IN_CONTEXT)) {\r
-            String id = el.getAttribute(ATTR_ID);\r
-            if (id != null) {\r
-                if (contexts == null)\r
-                    contexts = new ArrayList<String>(4);\r
-                contexts.add(id);\r
-            }\r
-        }\r
-        return contexts != null ? contexts.toArray(new String[contexts.size()]) : null;\r
-    }\r
-\r
-    private synchronized void loadExtensions(IConfigurationElement[] elements) {\r
-        org.eclipse.ui.IEditorRegistry editorRegistry = PlatformUI.getWorkbench().getEditorRegistry();\r
-\r
-        Set<EditorAdapterDescriptorImpl> newExtensions = new HashSet<EditorAdapterDescriptorImpl>(Arrays.asList(extensions));\r
-        Map<String, Group> newGroups = new HashMap<String, Group>();\r
-        Set<String> newReferencedContextIds = new HashSet<String>(referencedContextIds);\r
-\r
-        for (IConfigurationElement el : elements) {\r
-            String name = el.getName();\r
-            try {\r
-                String id = el.getAttribute(ATTR_ID);\r
-                String groupId = el.getAttribute(ATTR_GROUP_ID);\r
-                EditorAdapter adapter = null;\r
-\r
-                String priority = el.getAttribute(ATTR_PRIORITY);\r
-                int pri = IPriorityAction.NORMAL;\r
-                try {\r
-                    if (priority != null && !priority.trim().isEmpty())\r
-                        pri = Integer.parseInt(priority);\r
-                } catch (NumberFormatException e) {\r
-                    ExceptionUtils.logError("Non-integer priority value '" + priority + "' for '" + name + "' extension contributed by '" + el.getDeclaringExtension().getContributor().getName() + "'", e);\r
-                }\r
-\r
-                String[] inContexts = null;\r
-\r
-                if (EL_NAME_GROUP.equals(name)) {\r
-                    if (id == null || id.isEmpty()) {\r
-                        ExceptionUtils.logWarning("A group extension contributed by " + el.getDeclaringExtension().getContributor().getName() + " does not define a required id.", null);\r
-                    } else {\r
-                        if (!newGroups.containsKey(id)) {\r
-                            newGroups.put(id, new Group(id));\r
-                        }\r
-                    }\r
-                    continue;\r
-                } else if (EL_NAME_ADAPTER.equals(name)) {\r
-                    String editorId = el.getAttribute(ATTR_EDITOR_ID);\r
-                    IEditorDescriptor editorDesc = editorRegistry.findEditor(editorId);\r
-                    if (editorDesc == null) {\r
-                        ExceptionUtils.logError("Non-existent editorId '" + editorId + "' in extension contributed by '" + el.getDeclaringExtension().getContributor().getName() + "'", null);\r
-                        continue;\r
-                    }\r
-\r
-                    String type_uris = OntologyVersions.getInstance().currentVersion(el.getAttribute(ATTR_TYPE_URIS));\r
-                    String[] typeUris = type_uris != null ? type_uris.split(",") : new String[0];\r
-\r
-                    String label = el.getAttribute(ATTR_LABEL);\r
-                    String image = el.getAttribute(ATTR_IMAGE);\r
-                    ImageDescriptor imageDesc = null;\r
-                    if (label == null)\r
-                        label = editorDesc.getLabel();\r
-                    if (image != null) {\r
-                        try {\r
-                            URL resolved = FileLocator.resolve(new URL(image));\r
-                            imageDesc = ImageDescriptor.createFromURL(resolved);\r
-                        } catch (IOException e) {\r
-                            // Try fallback method\r
-                            Bundle bundle = Platform.getBundle(el.getDeclaringExtension().getContributor().getName());\r
-                            imageDesc = ImageDescriptor.createFromURL(bundle.getEntry(image));\r
-                        }\r
-                    } else {\r
-                        imageDesc = editorDesc.getImageDescriptor();\r
-                    }\r
-\r
-                    SimpleEditorAdapter _adapter = new SimpleEditorAdapter(label, imageDesc, editorId, (String[]) null, typeUris);\r
-                    _adapter.setPriority(pri);\r
-\r
-                    adapter = _adapter;\r
-\r
-                    inContexts = parseInContexts(el);\r
-                } else if (EL_NAME_ADAPTERCLASS.equals(name)) {\r
-                    adapter = (EditorAdapter) el.createExecutableExtension(ATTR_CLASS);\r
-                    if (adapter instanceof Prioritized) {\r
-                        ((Prioritized) adapter).setPriority(pri);\r
-                    }\r
-                    inContexts = parseInContexts(el);\r
-                }\r
-\r
-                if (adapter != null) {\r
-                    EditorAdapterDescriptorImpl ext = new EditorAdapterDescriptorImpl(id, groupId, adapter, inContexts);\r
-                    //System.out.println("Adding editor adapter extension from " +  el.getContributor().getName() + ": " + ext.getId() + ", " + ext.getAdapter());\r
-\r
-                    // Start tracking the new extension object, its removal will be notified of\r
-                    // with removeExtension(extension, Object[]).\r
-                    tracker.registerObject(el.getDeclaringExtension(), ext, IExtensionTracker.REF_STRONG);\r
-\r
-                    if (id != null && !id.isEmpty()) {\r
-                        idToExtension.put(id, ext);\r
-                    }\r
-                    if (inContexts != null)\r
-                        for (String ctx : inContexts)\r
-                            newReferencedContextIds.add(ctx);\r
-\r
-                    newExtensions.add(ext);\r
-                }\r
-            } catch (CoreException e) {\r
-                ExceptionUtils.logError("Failed to initialize resourceEditorAdapter extension \"" + name + "\": "\r
-                        + e.getMessage(), e);\r
-            }\r
-        }\r
-\r
-        for (EditorAdapterDescriptorImpl desc : idToExtension.values()) {\r
-            if (desc.getGroupId() != null) {\r
-                Group g = newGroups.get(desc.getGroupId());\r
-                if (g != null) {\r
-                    g.add(desc);\r
-                }\r
-            }\r
-        }\r
-\r
-        clearCache();\r
-        this.extensions = newExtensions.toArray(new EditorAdapterDescriptorImpl[newExtensions.size()]);\r
-        this.groupMap = newGroups;\r
-        this.referencedContextIds = newReferencedContextIds;\r
-    }\r
-\r
-\r
-    @Override\r
-    public void addExtension(IExtensionTracker tracker, IExtension extension) {\r
-        loadExtensions(extension.getConfigurationElements());\r
-    }\r
-\r
-    @Override\r
-    public synchronized void removeExtension(IExtension extension, Object[] objects) {\r
-        Set<EditorAdapterDescriptorImpl> newExtensions = new HashSet<EditorAdapterDescriptorImpl>(Arrays.asList(extensions));\r
-        Map<String, EditorAdapterDescriptorImpl> idMap = new HashMap<String, EditorAdapterDescriptorImpl>(idToExtension);\r
-        Set<String> removedContextReferences = new HashSet<String>();\r
-\r
-        Map<String, Group> newGroups = new HashMap<String, Group>();\r
-        for (Group g : groupMap.values()) {\r
-            newGroups.put(g.id, new Group(g));\r
-        }\r
-\r
-        for (Object o : objects) {\r
-            EditorAdapterDescriptor ext = (EditorAdapterDescriptor) o;\r
-\r
-            tracker.unregisterObject(extension, o);\r
-            newExtensions.remove(ext);\r
-            idMap.remove(ext.getId());\r
-\r
-            if (ext.getGroupId() != null) {\r
-                Group g = newGroups.get(ext.getGroupId());\r
-                if (g != null) {\r
-                    g.remove(ext);\r
-                }\r
-            }\r
-            for (String ctx : ext.getInContexts())\r
-                removedContextReferences.add(ctx);\r
-        }\r
-\r
-        // Go through the remaining editor adapters and\r
-        // check whether they still reference any of the removed\r
-        // context ids. Ids that are still referenced will not be\r
-        // removed from <code>referencedContextIds</code>\r
-        for (EditorAdapterDescriptorImpl desc : newExtensions) {\r
-            for (String ctx : desc.getInContexts()) {\r
-                removedContextReferences.remove(ctx);\r
-            }\r
-        }\r
-        Set<String> newReferencedContextIds = new HashSet<String>(referencedContextIds);\r
-        newReferencedContextIds.removeAll(removedContextReferences);\r
-\r
-        // Atomic assignment\r
-        this.extensions = newExtensions.toArray(new EditorAdapterDescriptorImpl[newExtensions.size()]);\r
-        this.idToExtension = idMap;\r
-        this.groupMap = newGroups;\r
-        this.referencedContextIds = newReferencedContextIds;\r
-    }\r
-\r
-    @Override\r
-    public EditorAdapterDescriptor getExtensionById(String id) {\r
-        return idToExtension.get(id);\r
-    }\r
-\r
-    @Override\r
-    public EditorAdapter getAdapterById(String id) {\r
-        EditorAdapterDescriptor ext = idToExtension.get(id);\r
-        return ext == null ? null : ext.getAdapter();\r
-    }\r
-\r
-    private void clearCache() {\r
-        synchronized (adapterCache) {\r
-            adapterCache.clear();\r
-            cacheQueue.clear();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public EditorAdapterDescriptor[] getEditorAdapters() {\r
-        return extensions;\r
-    }\r
-\r
-    @Override\r
-    public EditorAdapter[] getAdaptersFor(ReadGraph g, final Object r) throws DatabaseException {\r
-       \r
-        EditorAdapter[] result;\r
-        synchronized (adapterCache) {\r
-            result = adapterCache.get(r);\r
-            if (result != null)\r
-                return result;\r
-        }\r
-\r
-        MultiStatus status = null;\r
-\r
-        final MapList<String, EditorAdapter> l = new MapList<String, EditorAdapter>();\r
-        for (EditorAdapterDescriptor a : extensions) {\r
-            try {\r
-                // Filter out adapters that are not active in the current context configuration.\r
-                if (!a.isActive(activeContextIds))\r
-                    continue;\r
-                // Filter out adapters that just can't handle the input.\r
-                if (!a.getAdapter().canHandle(g, r))\r
-                    continue;\r
-\r
-                // NOTE: Group is null if there is no group.\r
-                l.add(a.getGroupId(), a.getAdapter());\r
-            } catch (RuntimeException e) {\r
-                if (status == null)\r
-                    status = new MultiStatus(Activator.PLUGIN_ID, 0, "Unexpected errors occured in EditorAdapters:" , null);\r
-                status.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
-            }\r
-        }\r
-        \r
-        \r
-        Resource res = ResourceAdaptionUtils.toSingleResource(r);\r
-        if (res != null) {\r
-               ModelingResources MOD = ModelingResources.getInstance(g);\r
-            Resource indexRoot = g.syncRequest(new PossibleIndexRoot(res));\r
-            if (indexRoot != null) {\r
-                Instances query = g.adapt(MOD.EditorContribution, Instances.class);\r
-                for(Resource contribution : query.find(g, indexRoot)) {\r
-\r
-                    try {\r
-\r
-                        String id = g.getRelatedValue(contribution, MOD.EditorContribution_editorId, Bindings.STRING);\r
-                        String label = NameUtils.getSafeLabel(g, contribution);\r
-\r
-                        Resource imageResource = g.getPossibleObject(contribution, MOD.EditorContribution_HasImage);\r
-                        ImageDescriptor image = imageResource == null ? null : g.adapt(imageResource, ImageDescriptor.class);\r
-\r
-                        Integer priority = g.getRelatedValue(contribution, MOD.EditorContribution_priority, Bindings.INTEGER);\r
-                        EditorAdapterDescriptor a = new GraphEditorAdapterDescriptor(id, label, image, contribution, priority);\r
-\r
-                        // Filter out adapters that are not active in the current context configuration.\r
-                        if (!a.isActive(activeContextIds))\r
-                            continue;\r
-                        // Filter out adapters that just can't handle the input.\r
-                        if (!a.getAdapter().canHandle(g, r))\r
-                            continue;\r
-\r
-                        l.add(a.getGroupId(), a.getAdapter());\r
-\r
-                    } catch (DatabaseException e) {\r
-                        Logger.defaultLogError(e);\r
-                    }\r
-               }\r
-            }\r
-        }\r
-        \r
-        result = gatherAdapterResult(l);\r
-        updateCache(r, result);\r
-\r
-        if (status != null && !status.isOK())\r
-            Activator.getDefault().getLog().log(status);\r
-\r
-        return result;\r
-    }\r
-\r
-    private EditorAdapter[] gatherAdapterResult(MapList<String, EditorAdapter> map) {\r
-        final List<EditorAdapter> result = new ArrayList<EditorAdapter>(8);\r
-        for (String group : map.getKeys()) {\r
-            List<EditorAdapter> grp = map.getValues(group);\r
-            if (group == null) {\r
-                if (grp != null)\r
-                    result.addAll(grp);\r
-            } else {\r
-                EditorAdapter highestPriorityAdapter = null;\r
-                for (EditorAdapter adapter : grp) {\r
-                    if (highestPriorityAdapter == null || adapter.getPriority() > highestPriorityAdapter.getPriority()) {\r
-                        highestPriorityAdapter = adapter;\r
-                    }\r
-                }\r
-                result.add(highestPriorityAdapter);\r
-            }\r
-        }\r
-        return result.toArray(EMPTY_ADAPTER_ARRAY);\r
-    }\r
-\r
-    @Override\r
-    public EditorMapping getMappings() {\r
-        return editorMapping;\r
-    }\r
-\r
-    private void updateCache(Object r, EditorAdapter[] result) {\r
-        synchronized (adapterCache) {\r
-            adapterCache.put(r, result);\r
-            Object removed = cacheQueue.write(r);\r
-            if (removed != null) {\r
-                adapterCache.remove(removed);\r
-            }\r
-        }\r
-    }\r
-\r
-\r
-    private static class CircularBuffer<T> {\r
-        private final WeakReference<?>[] buffer;\r
-\r
-        private int head;\r
-        private int tail;\r
-        private boolean full;\r
-        private final int size;\r
-\r
-        CircularBuffer(int size) {\r
-            if (size == 0)\r
-                throw new IllegalArgumentException("zero size not allowed");\r
-\r
-            this.buffer = new WeakReference[size];\r
-            this.size = size;\r
-            clear();\r
-        }\r
-\r
-        public void clear() {\r
-            this.head = this.tail = 0;\r
-            this.full = false;\r
-            Arrays.fill(buffer, null);\r
-        }\r
-\r
-        /**\r
-         * @param id an ID, other than 0L\r
-         * @return 0L if the buffer was not yet full, otherwise\r
-         * @throws IllegalArgumentException for 0L id\r
-         */\r
-        @SuppressWarnings("unchecked")\r
-        T write(T id) {\r
-            if (id == null)\r
-                throw new IllegalArgumentException("null resource id");\r
-\r
-            if (full) {\r
-                WeakReference<?> prev = buffer[head];\r
-                buffer[head++] = new WeakReference<T>(id);\r
-                head %= size;\r
-                tail = head;\r
-                return (T) prev.get();\r
-            } else {\r
-                buffer[head++] = new WeakReference<T>(id);\r
-                head %= size;\r
-                if (head == tail) {\r
-                    full = true;\r
-                }\r
-            }\r
-            // Nothing was yet overwritten\r
-            return null;\r
-        }\r
-\r
-        @Override\r
-        public String toString() {\r
-            return Arrays.toString(buffer);\r
-        }\r
-    }\r
-\r
-\r
-    @Override\r
-    public EditorAdapter[] getDefaultAdaptersFor(ReadGraph g, Object r) throws DatabaseException {\r
-        EditorAdapter[] results;\r
-\r
-        MultiStatus status = null;\r
-\r
-        final MapList<String, EditorAdapter> l = new MapList<String, EditorAdapter>();\r
-        for (EditorAdapterDescriptor a : extensions) {\r
-            try {\r
-\r
-                // NOTE: Group is null if there is no group.\r
-                l.add(a.getGroupId(), a.getAdapter());\r
-            } catch (RuntimeException e) {\r
-                if (status == null)\r
-                    status = new MultiStatus(Activator.PLUGIN_ID, 0, "Unexpected errors occured in EditorAdapters:" , null);\r
-                status.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));\r
-            }\r
-        }\r
-        results = gatherAdapterResult(l);\r
-\r
-        if (status != null && !status.isOK())\r
-            Activator.getDefault().getLog().log(status);\r
-\r
-        // If no default editor is found, get all that can handle\r
-        if (results.length > 0)\r
-            return results;\r
-        else\r
-            return getAdaptersFor(g, r);\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * 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:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.ui.workbench.editor;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.eclipse.core.commands.contexts.ContextManagerEvent;
+import org.eclipse.core.commands.contexts.IContextManagerListener;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IFilter;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.contexts.IContextService;
+import org.osgi.framework.Bundle;
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.PossibleIndexRoot;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.adapter.Instances;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.scl.reflection.OntologyVersions;
+import org.simantics.ui.internal.Activator;
+import org.simantics.ui.utils.ResourceAdaptionUtils;
+import org.simantics.utils.datastructures.MapList;
+import org.simantics.utils.ui.ExceptionUtils;
+import org.simantics.utils.ui.action.IPriorityAction;
+
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public final class EditorRegistry implements IExtensionChangeHandler, IEditorRegistry {
+
+    /**
+     * The maximum amount of entries to cache
+     * {@link #getAdaptersFor(ReadGraph, Resource)} results for. Context activation
+     * changes invalidate this cache.
+     */
+    private static final int    MAX_CACHE_SIZE       = 50;
+
+
+    private final static String NAMESPACE            = Activator.PLUGIN_ID;
+
+    private final static String EP_NAME              = "resourceEditorAdapter";
+
+
+    private final static String EL_NAME_ADAPTER      = "adapter";
+
+    private final static String EL_NAME_ADAPTERCLASS = "adapterClass";
+
+    private final static String EL_NAME_GROUP        = "group";
+
+    private final static String EL_NAME_IN_CONTEXT   = "inContext";
+
+
+    private static final String ATTR_CLASS           = "class";
+
+    private static final String ATTR_IMAGE           = "image";
+
+    private static final String ATTR_LABEL           = "label";
+
+    private static final String ATTR_TYPE_URIS       = "type_uris";
+
+    private static final String ATTR_EDITOR_ID       = "editorId";
+
+    private static final String ATTR_PRIORITY        = "priority";
+
+    private static final String ATTR_GROUP_ID        = "groupId";
+
+    private static final String ATTR_ID              = "id";
+
+
+    private static class Group {
+        public final String id;
+        public final List<EditorAdapterDescriptor> adapters;
+
+        Group(String id) {
+            this.id = id;
+            this.adapters = new ArrayList<EditorAdapterDescriptor>();
+        }
+        Group(Group g) {
+            this.id = g.id;
+            this.adapters = new ArrayList<EditorAdapterDescriptor>(g.adapters);
+        }
+        void add(EditorAdapterDescriptor desc) {
+            adapters.add(desc);
+        }
+        void remove(EditorAdapterDescriptor desc) {
+            adapters.remove(desc);
+        }
+    }
+
+    private static final EditorAdapter[]         EMPTY_ADAPTER_ARRAY  = new EditorAdapter[0];
+
+    private static EditorRegistry                INSTANCE;
+
+    private ExtensionTracker                             tracker;
+
+    private EditorAdapterDescriptorImpl[]            extensions           = new EditorAdapterDescriptorImpl[0];
+
+    private Map<String, EditorAdapterDescriptorImpl> idToExtension        = new HashMap<String, EditorAdapterDescriptorImpl>();
+
+    private Map<String, Group>                           groupMap             = new HashMap<String, Group>();
+
+    private WeakHashMap<Object, EditorAdapter[]> adapterCache         = new WeakHashMap<Object, EditorAdapter[]>(
+            MAX_CACHE_SIZE);
+
+    private CircularBuffer<Object>                       cacheQueue           = new CircularBuffer<Object>(
+            MAX_CACHE_SIZE);
+
+    /**
+     * A set of all the context id's that are currently referenced by all the
+     * loaded resourceEditorAdapter extensions.
+     */
+    private Set<String>                                  referencedContextIds = new HashSet<String>();
+
+    /**
+     * The current set of active contexts.
+     */
+    private Set<String>                                  activeContextIds = new HashSet<String>();
+
+    /**
+     * Used to store all input -> editor mappings. In the Eclipse IDE, this
+     * information is stored as persistent properties in each IFile represented
+     * by eclipse Resource's. This implementation stores all the mappings in
+     * this single map.
+     * 
+     * Maybe in the future it would be possible to store these mapping in the
+     * graph in a way that allows us not to publish those changes to the outside
+     * world.
+     */
+    private final EditorMappingImpl                                editorMapping        = new EditorMappingImpl();
+
+    public synchronized static IEditorRegistry getInstance() {
+        if (INSTANCE == null) {
+            INSTANCE = new EditorRegistry();
+        }
+        return INSTANCE;
+    }
+
+    public static synchronized void dispose() {
+        if (INSTANCE != null) {
+            INSTANCE.close();
+            INSTANCE = null;
+        }
+    }
+
+    private EditorRegistry() {
+        tracker = new ExtensionTracker();
+
+        // Cache defined actions
+        IExtensionPoint expt = Platform.getExtensionRegistry().getExtensionPoint(NAMESPACE, EP_NAME);
+        loadExtensions(expt.getConfigurationElements());
+
+        // Start tracking for new and removed extensions
+        IFilter filter = ExtensionTracker.createExtensionPointFilter(expt);
+        tracker.registerHandler(this, filter);
+
+        hookListeners();
+    }
+
+    private void close() {
+        unhookListeners();
+
+        tracker.close();
+        tracker = null;
+
+        editorMapping.clear();
+
+        extensions = null;
+        idToExtension = null;
+        groupMap = null;
+        adapterCache = null;
+        cacheQueue = null;
+    }
+
+//    /**
+//     * Must reset {@link #getAdaptersFor(ReadGraph, Resource)} query caches when
+//     * perspectives are changed because EditorAdapters may return
+//     * different results in different perspectives.
+//     */
+//    private IPerspectiveListener perspectiveListener = new PerspectiveAdapter() {
+//        public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
+//            clearCache();
+//        }
+//    };
+
+    private final IContextManagerListener contextListener = new IContextManagerListener() {
+        @Override
+        public void contextManagerChanged(ContextManagerEvent event) {
+            if (event.isActiveContextsChanged()) {
+                //System.out.println("EVENT: " + event.isActiveContextsChanged() + ", " + event.isContextChanged() + ", " + event.isContextDefined() + ", " + Arrays.toString(event.getPreviouslyActiveContextIds().toArray()));
+
+                Collection<?> active = event.getContextManager().getActiveContextIds();
+                Collection<?> previouslyActive = event.getPreviouslyActiveContextIds();
+
+                Collection<String> added = new HashSet<String>(4);
+                Collection<String> removed = new HashSet<String>(4);
+
+                for (Object o : active) {
+                    if (!previouslyActive.contains(o))
+                        added.add((String) o);
+                }
+                for (Object o : previouslyActive) {
+                    if (!active.contains(o))
+                        removed.add((String) o);
+                }
+
+                //System.out.println("ADDED: " + Arrays.toString(added.toArray()) + ", REMOVED: " + Arrays.toString(removed.toArray()));
+                contextChange(added, removed);
+            }
+        }
+    };
+
+    private boolean containsAny(Collection<String> c, Collection<String> anyOf) {
+        if (anyOf.isEmpty())
+            return false;
+        for (String s : anyOf)
+            if (c.contains(s))
+                return true;
+        return false;
+    }
+
+    private void contextChange(Collection<String> added, Collection<String> removed) {
+        // Update active context id set
+        if (!added.isEmpty())
+            activeContextIds.addAll(added);
+        if (!removed.isEmpty())
+            activeContextIds.remove(removed);
+
+        // Clear caches if necessary
+        if (containsAny(referencedContextIds, added) || containsAny(referencedContextIds, removed)) {
+            clearCache();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void hookListeners() {
+        IWorkbench wb = PlatformUI.getWorkbench();
+        IContextService contextService = (IContextService) wb.getService(IContextService.class);
+        contextService.addContextManagerListener(contextListener);
+        activeContextIds = new HashSet<String>(contextService.getActiveContextIds());
+    }
+
+    private void unhookListeners() {
+        IWorkbench wb = PlatformUI.getWorkbench();
+        IContextService contextService = (IContextService) wb.getService(IContextService.class);
+        if (contextService != null) {
+            contextService.removeContextManagerListener(contextListener);
+        }
+    }
+
+    private String[] parseInContexts(IConfigurationElement parent) {
+        List<String> contexts = null;
+        for (IConfigurationElement el : parent.getChildren(EL_NAME_IN_CONTEXT)) {
+            String id = el.getAttribute(ATTR_ID);
+            if (id != null) {
+                if (contexts == null)
+                    contexts = new ArrayList<String>(4);
+                contexts.add(id);
+            }
+        }
+        return contexts != null ? contexts.toArray(new String[contexts.size()]) : null;
+    }
+
+    private synchronized void loadExtensions(IConfigurationElement[] elements) {
+        org.eclipse.ui.IEditorRegistry editorRegistry = PlatformUI.getWorkbench().getEditorRegistry();
+
+        Set<EditorAdapterDescriptorImpl> newExtensions = new HashSet<EditorAdapterDescriptorImpl>(Arrays.asList(extensions));
+        Map<String, Group> newGroups = new HashMap<String, Group>();
+        Set<String> newReferencedContextIds = new HashSet<String>(referencedContextIds);
+
+        for (IConfigurationElement el : elements) {
+            String name = el.getName();
+            try {
+                String id = el.getAttribute(ATTR_ID);
+                String groupId = el.getAttribute(ATTR_GROUP_ID);
+                EditorAdapter adapter = null;
+
+                String priority = el.getAttribute(ATTR_PRIORITY);
+                int pri = IPriorityAction.NORMAL;
+                try {
+                    if (priority != null && !priority.trim().isEmpty())
+                        pri = Integer.parseInt(priority);
+                } catch (NumberFormatException e) {
+                    ExceptionUtils.logError("Non-integer priority value '" + priority + "' for '" + name + "' extension contributed by '" + el.getDeclaringExtension().getContributor().getName() + "'", e);
+                }
+
+                String[] inContexts = null;
+
+                if (EL_NAME_GROUP.equals(name)) {
+                    if (id == null || id.isEmpty()) {
+                        ExceptionUtils.logWarning("A group extension contributed by " + el.getDeclaringExtension().getContributor().getName() + " does not define a required id.", null);
+                    } else {
+                        if (!newGroups.containsKey(id)) {
+                            newGroups.put(id, new Group(id));
+                        }
+                    }
+                    continue;
+                } else if (EL_NAME_ADAPTER.equals(name)) {
+                    String editorId = el.getAttribute(ATTR_EDITOR_ID);
+                    IEditorDescriptor editorDesc = editorRegistry.findEditor(editorId);
+                    if (editorDesc == null) {
+                        ExceptionUtils.logError("Non-existent editorId '" + editorId + "' in extension contributed by '" + el.getDeclaringExtension().getContributor().getName() + "'", null);
+                        continue;
+                    }
+
+                    String type_uris = OntologyVersions.getInstance().currentVersion(el.getAttribute(ATTR_TYPE_URIS));
+                    String[] typeUris = type_uris != null ? type_uris.split(",") : new String[0];
+
+                    String label = el.getAttribute(ATTR_LABEL);
+                    String image = el.getAttribute(ATTR_IMAGE);
+                    ImageDescriptor imageDesc = null;
+                    if (label == null)
+                        label = editorDesc.getLabel();
+                    if (image != null) {
+                        try {
+                            URL resolved = FileLocator.resolve(new URL(image));
+                            imageDesc = ImageDescriptor.createFromURL(resolved);
+                        } catch (IOException e) {
+                            // Try fallback method
+                            Bundle bundle = Platform.getBundle(el.getDeclaringExtension().getContributor().getName());
+                            imageDesc = ImageDescriptor.createFromURL(bundle.getEntry(image));
+                        }
+                    } else {
+                        imageDesc = editorDesc.getImageDescriptor();
+                    }
+
+                    SimpleEditorAdapter _adapter = new SimpleEditorAdapter(label, imageDesc, editorId, (String[]) null, typeUris);
+                    _adapter.setPriority(pri);
+
+                    adapter = _adapter;
+
+                    inContexts = parseInContexts(el);
+                } else if (EL_NAME_ADAPTERCLASS.equals(name)) {
+                    adapter = (EditorAdapter) el.createExecutableExtension(ATTR_CLASS);
+                    if (adapter instanceof Prioritized) {
+                        ((Prioritized) adapter).setPriority(pri);
+                    }
+                    inContexts = parseInContexts(el);
+                }
+
+                if (adapter != null) {
+                    EditorAdapterDescriptorImpl ext = new EditorAdapterDescriptorImpl(id, groupId, adapter, inContexts);
+                    //System.out.println("Adding editor adapter extension from " +  el.getContributor().getName() + ": " + ext.getId() + ", " + ext.getAdapter());
+
+                    // Start tracking the new extension object, its removal will be notified of
+                    // with removeExtension(extension, Object[]).
+                    tracker.registerObject(el.getDeclaringExtension(), ext, IExtensionTracker.REF_STRONG);
+
+                    if (id != null && !id.isEmpty()) {
+                        idToExtension.put(id, ext);
+                    }
+                    if (inContexts != null)
+                        for (String ctx : inContexts)
+                            newReferencedContextIds.add(ctx);
+
+                    newExtensions.add(ext);
+                }
+            } catch (CoreException e) {
+                ExceptionUtils.logError("Failed to initialize resourceEditorAdapter extension \"" + name + "\": "
+                        + e.getMessage(), e);
+            }
+        }
+
+        for (EditorAdapterDescriptorImpl desc : idToExtension.values()) {
+            if (desc.getGroupId() != null) {
+                Group g = newGroups.get(desc.getGroupId());
+                if (g != null) {
+                    g.add(desc);
+                }
+            }
+        }
+
+        clearCache();
+        this.extensions = newExtensions.toArray(new EditorAdapterDescriptorImpl[newExtensions.size()]);
+        this.groupMap = newGroups;
+        this.referencedContextIds = newReferencedContextIds;
+    }
+
+
+    @Override
+    public void addExtension(IExtensionTracker tracker, IExtension extension) {
+        loadExtensions(extension.getConfigurationElements());
+    }
+
+    @Override
+    public synchronized void removeExtension(IExtension extension, Object[] objects) {
+        Set<EditorAdapterDescriptorImpl> newExtensions = new HashSet<EditorAdapterDescriptorImpl>(Arrays.asList(extensions));
+        Map<String, EditorAdapterDescriptorImpl> idMap = new HashMap<String, EditorAdapterDescriptorImpl>(idToExtension);
+        Set<String> removedContextReferences = new HashSet<String>();
+
+        Map<String, Group> newGroups = new HashMap<String, Group>();
+        for (Group g : groupMap.values()) {
+            newGroups.put(g.id, new Group(g));
+        }
+
+        for (Object o : objects) {
+            EditorAdapterDescriptor ext = (EditorAdapterDescriptor) o;
+
+            tracker.unregisterObject(extension, o);
+            newExtensions.remove(ext);
+            idMap.remove(ext.getId());
+
+            if (ext.getGroupId() != null) {
+                Group g = newGroups.get(ext.getGroupId());
+                if (g != null) {
+                    g.remove(ext);
+                }
+            }
+            for (String ctx : ext.getInContexts())
+                removedContextReferences.add(ctx);
+        }
+
+        // Go through the remaining editor adapters and
+        // check whether they still reference any of the removed
+        // context ids. Ids that are still referenced will not be
+        // removed from <code>referencedContextIds</code>
+        for (EditorAdapterDescriptorImpl desc : newExtensions) {
+            for (String ctx : desc.getInContexts()) {
+                removedContextReferences.remove(ctx);
+            }
+        }
+        Set<String> newReferencedContextIds = new HashSet<String>(referencedContextIds);
+        newReferencedContextIds.removeAll(removedContextReferences);
+
+        // Atomic assignment
+        this.extensions = newExtensions.toArray(new EditorAdapterDescriptorImpl[newExtensions.size()]);
+        this.idToExtension = idMap;
+        this.groupMap = newGroups;
+        this.referencedContextIds = newReferencedContextIds;
+    }
+
+    @Override
+    public EditorAdapterDescriptor getExtensionById(String id) {
+        return idToExtension.get(id);
+    }
+
+    @Override
+    public EditorAdapter getAdapterById(String id) {
+        EditorAdapterDescriptor ext = idToExtension.get(id);
+        return ext == null ? null : ext.getAdapter();
+    }
+
+    private void clearCache() {
+        synchronized (adapterCache) {
+            adapterCache.clear();
+            cacheQueue.clear();
+        }
+    }
+
+    @Override
+    public EditorAdapterDescriptor[] getEditorAdapters() {
+        return extensions;
+    }
+
+    @Override
+    public EditorAdapter[] getAdaptersFor(ReadGraph g, final Object r) throws DatabaseException {
+       
+        EditorAdapter[] result;
+        synchronized (adapterCache) {
+            result = adapterCache.get(r);
+            if (result != null)
+                return result;
+        }
+
+        MultiStatus status = null;
+
+        final MapList<String, EditorAdapter> l = new MapList<String, EditorAdapter>();
+        for (EditorAdapterDescriptor a : extensions) {
+            try {
+                // Filter out adapters that are not active in the current context configuration.
+                if (!a.isActive(activeContextIds))
+                    continue;
+                // Filter out adapters that just can't handle the input.
+                if (!a.getAdapter().canHandle(g, r))
+                    continue;
+
+                // NOTE: Group is null if there is no group.
+                l.add(a.getGroupId(), a.getAdapter());
+            } catch (RuntimeException e) {
+                if (status == null)
+                    status = new MultiStatus(Activator.PLUGIN_ID, 0, "Unexpected errors occured in EditorAdapters:" , null);
+                status.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
+            }
+        }
+        
+        
+        Resource res = ResourceAdaptionUtils.toSingleResource(r);
+        if (res != null) {
+               ModelingResources MOD = ModelingResources.getInstance(g);
+            Resource indexRoot = g.syncRequest(new PossibleIndexRoot(res));
+            if (indexRoot != null) {
+                Instances query = g.adapt(MOD.EditorContribution, Instances.class);
+                for(Resource contribution : query.find(g, indexRoot)) {
+
+                    try {
+
+                        String id = g.getRelatedValue(contribution, MOD.EditorContribution_editorId, Bindings.STRING);
+                        String label = NameUtils.getSafeLabel(g, contribution);
+
+                        Resource imageResource = g.getPossibleObject(contribution, MOD.EditorContribution_HasImage);
+                        ImageDescriptor image = imageResource == null ? null : g.adapt(imageResource, ImageDescriptor.class);
+
+                        Integer priority = g.getRelatedValue(contribution, MOD.EditorContribution_priority, Bindings.INTEGER);
+                        EditorAdapterDescriptor a = new GraphEditorAdapterDescriptor(id, label, image, contribution, priority);
+
+                        // Filter out adapters that are not active in the current context configuration.
+                        if (!a.isActive(activeContextIds))
+                            continue;
+                        // Filter out adapters that just can't handle the input.
+                        if (!a.getAdapter().canHandle(g, r))
+                            continue;
+
+                        l.add(a.getGroupId(), a.getAdapter());
+
+                    } catch (DatabaseException e) {
+                        Logger.defaultLogError(e);
+                    }
+               }
+            }
+        }
+        
+        result = gatherAdapterResult(l);
+        updateCache(r, result);
+
+        if (status != null && !status.isOK())
+            Activator.getDefault().getLog().log(status);
+
+        return result;
+    }
+
+    private EditorAdapter[] gatherAdapterResult(MapList<String, EditorAdapter> map) {
+        final List<EditorAdapter> result = new ArrayList<EditorAdapter>(8);
+        for (String group : map.getKeys()) {
+            List<EditorAdapter> grp = map.getValues(group);
+            if (group == null) {
+                if (grp != null)
+                    result.addAll(grp);
+            } else {
+                EditorAdapter highestPriorityAdapter = null;
+                for (EditorAdapter adapter : grp) {
+                    if (highestPriorityAdapter == null || adapter.getPriority() > highestPriorityAdapter.getPriority()) {
+                        highestPriorityAdapter = adapter;
+                    }
+                }
+                result.add(highestPriorityAdapter);
+            }
+        }
+        return result.toArray(EMPTY_ADAPTER_ARRAY);
+    }
+
+    @Override
+    public EditorMapping getMappings() {
+        return editorMapping;
+    }
+
+    private void updateCache(Object r, EditorAdapter[] result) {
+        synchronized (adapterCache) {
+            adapterCache.put(r, result);
+            Object removed = cacheQueue.write(r);
+            if (removed != null) {
+                adapterCache.remove(removed);
+            }
+        }
+    }
+
+
+    private static class CircularBuffer<T> {
+        private final WeakReference<?>[] buffer;
+
+        private int head;
+        private int tail;
+        private boolean full;
+        private final int size;
+
+        CircularBuffer(int size) {
+            if (size == 0)
+                throw new IllegalArgumentException("zero size not allowed");
+
+            this.buffer = new WeakReference[size];
+            this.size = size;
+            clear();
+        }
+
+        public void clear() {
+            this.head = this.tail = 0;
+            this.full = false;
+            Arrays.fill(buffer, null);
+        }
+
+        /**
+         * @param id an ID, other than 0L
+         * @return 0L if the buffer was not yet full, otherwise
+         * @throws IllegalArgumentException for 0L id
+         */
+        @SuppressWarnings("unchecked")
+        T write(T id) {
+            if (id == null)
+                throw new IllegalArgumentException("null resource id");
+
+            if (full) {
+                WeakReference<?> prev = buffer[head];
+                buffer[head++] = new WeakReference<T>(id);
+                head %= size;
+                tail = head;
+                return (T) prev.get();
+            } else {
+                buffer[head++] = new WeakReference<T>(id);
+                head %= size;
+                if (head == tail) {
+                    full = true;
+                }
+            }
+            // Nothing was yet overwritten
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            return Arrays.toString(buffer);
+        }
+    }
+
+
+    @Override
+    public EditorAdapter[] getDefaultAdaptersFor(ReadGraph g, Object r) throws DatabaseException {
+        EditorAdapter[] results;
+
+        MultiStatus status = null;
+
+        final MapList<String, EditorAdapter> l = new MapList<String, EditorAdapter>();
+        for (EditorAdapterDescriptor a : extensions) {
+            try {
+
+                // NOTE: Group is null if there is no group.
+                l.add(a.getGroupId(), a.getAdapter());
+            } catch (RuntimeException e) {
+                if (status == null)
+                    status = new MultiStatus(Activator.PLUGIN_ID, 0, "Unexpected errors occured in EditorAdapters:" , null);
+                status.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
+            }
+        }
+        results = gatherAdapterResult(l);
+
+        if (status != null && !status.isOK())
+            Activator.getDefault().getLog().log(status);
+
+        // If no default editor is found, get all that can handle
+        if (results.length > 0)
+            return results;
+        else
+            return getAdaptersFor(g, r);
+    }
+
+}