【问题标题】:Rename feature for EMF ResourcesEMF 资源的重命名功能
【发布时间】:2017-12-21 02:21:06
【问题描述】:

我正在处理一个项目,其中我有 EMF 模型“A”,它在许多其他模型“B”、“C”...等中被引用。我想要的是我想为这些资源。因此,当用户重命名“A”时,必须更新其引用。

如果有任何框架工作,请提供一些想法,或者我必须获取所有引用,然后以编程方式迭代和更新引用。

【问题讨论】:

  • 您是否尝试过使用 EMF 观察者/通知?您可以注册观察者并对特定事件做出反应(例如,资源上的一组名称功能)。
  • 当您更改任何属性的名称时,我可以知道您希望在“B”、“C”等中执行哪种更新,以及是否考虑将该属性值用于 FQN 参考,然后它会自动更新。

标签: eclipse-emf emf


【解决方案1】:

我用另一种方式解决了同样的问题。

根本问题是引用的资源文件可能会被重命名,这会破坏引用。

我创建了一个修复文件引用命令,而不是自动更新所有引用的重构,用户可以在编辑后的模型上调用该命令。

该命令执行以下步骤:

  1. 提示用户选择要修复的缺失资源
  2. 提示用户选择替换文件
  3. 更新模型中具有与缺失资源匹配的代理 URI 的所有对象。用新资源中的已解析对象替换代理。

如果您仍然想进行重构,我认为您无论如何都可以使用我的代码作为起点。

/**
 * Locates and fixes unresolved references in a model.
 */
public class ReferenceRepairer {
    public static final String COMMAND_ID = Activator.PLUGIN_ID + ".commands.repairReferences";

    /**
     * 1) Prompts the user to select a missing resource to repair
     * 2) Prompts the user to select a replacement file
     * 3) Updates all objects in the model with a proxy URI that matches the missing resource. Replaces proxies
     *    with resolved objects in the new resource.  
     */
    public static void repairResourceReference(Shell shell, EditingDomain editingDomain) {
        Resource res = promptMissingResource(shell, editingDomain);

        if (res == null) return;

        IFile newFile = promptReplacementFile(shell);

        if (newFile == null) return;

        repairReferences(editingDomain, res, URI.createPlatformResourceURI(newFile.getFullPath().toString(), true));
    }

    private static void repairReferences(final EditingDomain editingDomain, Resource missingRes, final URI newUri) {
        URI missingUri = missingRes.getURI();

        // Create new resource for the replacement file
        Resource newRes = editingDomain.getResourceSet().getResource(newUri, true);

        Map<EObject, Collection<Setting>> proxies = UnresolvedProxyCrossReferencer.find(editingDomain.getResourceSet());

        CompoundCommand repairRefsCommand =  new CompoundCommand("Repair references") {
            /**
             * Disallow undo. The model changes could be undone, but it seems impossible to
             * recreate a non-existent resource in the resource set. 
             */
            @Override
            public boolean canUndo() {
                return false;
            }
        };

        // Resolve all proxies from this resource and repair reference to those objects

        for (Entry<EObject, Collection<Setting>> entry : proxies.entrySet()) {

            EObject proxy = entry.getKey();
            URI proxyUri = EcoreUtil.getURI(proxy);
            if (!proxyUri.trimFragment().equals(missingUri)) continue;

            EObject resolved = newRes.getEObject(proxyUri.fragment());

            if (resolved.eIsProxy()) continue;

            // Update all objects that have references to the resolved proxy

            for (Setting sett : entry.getValue()) {
                if (sett.getEStructuralFeature().isMany()) {
                    @SuppressWarnings("unchecked")
                    EList<Object> valueList = (EList<Object>) sett.get(true);
                    int proxyIx = valueList.indexOf(proxy);

                    repairRefsCommand.append(SetCommand.create(editingDomain,
                        sett.getEObject(), sett.getEStructuralFeature(), resolved, proxyIx));
                } else {
                    repairRefsCommand.append(SetCommand.create(editingDomain,
                        sett.getEObject(), sett.getEStructuralFeature(), resolved));
                }
            }
        }

        if (!repairRefsCommand.isEmpty()) {
            editingDomain.getCommandStack().execute(repairRefsCommand);
        }

        // Remove the 
        editingDomain.getResourceSet().getResources().remove(missingRes);
    }

    private static IFile promptReplacementFile(Shell shell) {
        ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(shell, 
            new WorkbenchLabelProvider(), new WorkbenchContentProvider()); 

        dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
        dialog.setTitle("Select Replacement Resource");
        dialog.setMessage("Select a file which will replace the missing file.");

        dialog.setValidator(new ISelectionStatusValidator() {
            @Override
            public IStatus validate(Object[] selection) {
                if (selection.length == 0 || !(selection[0] instanceof IFile)) {
                    return ValidationStatus.error("The selected object is not a file.");
                }

                return new Status(IStatus.OK, Activator.PLUGIN_ID, "");
            }
        });


        if (dialog.open() != Window.OK) return null;

        return (IFile) dialog.getFirstResult();
    }

    private static Resource promptMissingResource(Shell shell, EditingDomain editingDomain) {
        ElementListSelectionDialog dialog = new ElementListSelectionDialog(shell, 
                new LabelProvider() {
                    @Override
                    public String getText(Object elem) {
                        return ((Resource) elem).getURI().toString();
                    }
            })
        {
            /** Make dialog OK button enabled when there are errors, instead of vise-versa. */ 
            @Override
            protected void updateButtonsEnableState(IStatus status) {
                Button okButton = getOkButton();
                if (okButton != null && !okButton.isDisposed()) {
                    okButton.setEnabled(!status.isOK());
                }
            }

            /** Disable filter text field */
            @Override
            protected Text createFilterText(Composite parent) {
                Text text = super.createFilterText(parent);
                text.setSize(0, 0);
                text.setLayoutData(GridDataFactory.swtDefaults().exclude(true).create());
                text.setVisible(false);
                return text;
            }
        };

        dialog.setTitle("Select Missing Resource");
        dialog.setMessage(
            "Select a URI of a missing resource file that should be replaced by an URI to an existing file.");
        dialog.setElements(getMissingResources(editingDomain.getResourceSet().getResources()).toArray());

        if (dialog.open() != Window.OK) return null;

        return (Resource) dialog.getFirstResult();
    }

    private static List<Resource> getMissingResources(List<Resource> resources) {
        List<Resource> missingResources = new ArrayList<>();
        for (Resource res : resources) {
            try {
                if (res.getURI().isPlatformPlugin()) continue;
                URL url = FileLocator.toFileURL(new URL(res.getURI().toString()));
                java.net.URI uri = new java.net.URI(url.getProtocol(), "", "/" + url.getPath(), null);
                if (!Files.exists(Paths.get(uri))) {
                    missingResources.add(res);
                }
            } catch (InvalidPathException | IOException | URISyntaxException exc) {
                // Ignore. There mighe be weird Sirius resource in the resources set which we can't recognice
            }

        }
        return missingResources;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-29
    • 1970-01-01
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    相关资源
    最近更新 更多