Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • af3/kernel
  • diewald/kernel
2 results
Show changes
Showing
with 608 additions and 159 deletions
DelegatingControllerFactory.java ad214d83b5821b39862b7c382c91a13c3dfddbd0 GREEN
DelegatingFactoryBase.java f421742267610f41bb6196346026d2f239d90ed0 GREEN
DelegatingModelFactory.java 717b706781879efe9efcb5ce4bf53723e39a3e1b GREEN
DelegatingVisualFactory.java 7e834acd12ae4d1c2b2b32a5456dc9f2b6d4e466 GREEN
/*-------------------------------------------------------------------------+
| Copyright 2019 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.kernel.ui.extension.base.factory;
import java.util.List;
import java.util.Optional;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.controller.IController;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.controller.IControllerFactory;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.IContentAnchorageMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.IContentMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.IDiagramAnchorageMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.IDiagramMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.ILinkMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.IMVCBundle;
/**
* Delegates the creational calls to concrete {@link IControllerFactory}s. The first non-null
* element returned by the factories of the initially given list is returned. If no element is
* created (all delegates returned null), this factory throws a {@link RuntimeException}.
*
* @author hoelzl
* @author diewald
*/
public class DelegatingControllerFactory extends DelegatingFactoryBase<IControllerFactory>
implements IControllerFactory {
/** Constructor. */
public DelegatingControllerFactory(List<Class<? extends IControllerFactory>> factories) {
super(factories, null);
}
/** {@inheritDoc} */
@Override
public IController createContentController(IContentMVCBundle modelBundle) {
Optional<IController> controller =
getDelegateFactories().stream().map(f -> f.createContentController(modelBundle))
.filter(cc -> cc != null).findFirst();
if(controller.isPresent()) {
return controller.get();
}
throw createNoControllerException(modelBundle);
}
/** {@inheritDoc} */
@Override
public IController createDiagramAnchorageController(IDiagramAnchorageMVCBundle modelBundle) {
Optional<IController> controller = getDelegateFactories().stream()
.map(f -> f.createDiagramAnchorageController(modelBundle)).filter(cc -> cc != null)
.findFirst();
if(controller.isPresent()) {
return controller.get();
}
throw createNoControllerException(modelBundle);
}
/** {@inheritDoc} */
@Override
public IController createContentAnchorageController(IContentAnchorageMVCBundle modelBundle) {
Optional<IController> controller = getDelegateFactories().stream()
.map(f -> f.createContentAnchorageController(modelBundle)).filter(cc -> cc != null)
.findFirst();
if(controller.isPresent()) {
return controller.get();
}
throw createNoControllerException(modelBundle);
}
/** {@inheritDoc} */
@Override
public IController createLinkController(ILinkMVCBundle modelBundle) {
Optional<IController> controller = getDelegateFactories().stream()
.map(f -> f.createLinkController(modelBundle)).filter(cc -> cc != null).findFirst();
if(controller.isPresent()) {
return controller.get();
}
throw createNoControllerException(modelBundle);
}
/** {@inheritDoc} */
@Override
public IController createDiagramController(IDiagramMVCBundle diagramBundle) {
Optional<IController> controller = getDelegateFactories().stream().map(f -> {
return f.createDiagramController(diagramBundle);
}).filter(cc -> cc != null).findFirst();
if(controller.isPresent()) {
return controller.get();
}
throw createNoControllerException(diagramBundle);
}
/** Throws a runtime exception indicating a missing controller. */
private RuntimeException createNoControllerException(IMVCBundle modelBundle) {
return new RuntimeException("No controller has been specified for model elements of the" +
" type " + modelBundle.getModel().getClass().getSimpleName() + ". Please check" +
" the editor bindings and the delegate controllers.");
}
}
/*-------------------------------------------------------------------------+
| Copyright 2019 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.kernel.ui.extension.base.factory;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.reflect.ConstructorUtils.getMatchingAccessibleConstructor;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.error;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.fortiss.tooling.kernel.ui.ToolingKernelUIActivator;
import com.google.common.collect.ImmutableList;
/**
* Base class for delegating MVC factories that wrap 1..n factories for editors of a defined type.
*
* @author diewald
*/
/* package */ abstract class DelegatingFactoryBase<T> {
/** References the edited Object in case it is needed by some factory. May be {@code null}. */
protected final Object editedObject;
/** References the */
private List<T> delegateFactories = new ArrayList<>();
/** Constructor. */
protected DelegatingFactoryBase(List<Class<? extends T>> factories, Object editedObject) {
this.editedObject = editedObject;
delegateFactories = factories.stream().map(fCls -> constructFactory(fCls))
.flatMap(Optional::stream).collect(toList());
}
/** Creates an instance of the given {@code delegateFactory}. */
protected Optional<? extends T> constructFactory(Class<? extends T> delegateFactory) {
Constructor<? extends T> ctor = null;
try {
ctor = getMatchingAccessibleConstructor(delegateFactory);
try {
return Optional.of(ctor.newInstance());
} catch(InstantiationException | IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
error(ToolingKernelUIActivator.getDefault(), "Failed to instantiate the factory " +
delegateFactory.getSimpleName() + ".");
return Optional.empty();
}
} catch(NullPointerException | SecurityException e1) {
error(ToolingKernelUIActivator.getDefault(), "The factory " +
delegateFactory.getSimpleName() +
" is missing a no-arg Constructor. Only such constructors are allowed for" +
" these factories.");
return Optional.empty();
}
}
/** Returns the list of delegate factory instances whose types are given during construction. */
protected ImmutableList<T> getDelegateFactories() {
return ImmutableList.copyOf(delegateFactories);
}
}
/*-------------------------------------------------------------------------+
| Copyright 2019 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.kernel.ui.extension.base.factory;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.reflect.ConstructorUtils.getMatchingAccessibleConstructor;
import static org.conqat.lib.commons.collections.CollectionUtils.isNullOrEmpty;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.getInterfaceType;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.error;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.model.IModelFactory;
import org.fortiss.tooling.kernel.ui.ToolingKernelUIActivator;
/**
* Delegates the creational and getter calls to concrete {@link IModelFactory}s. The first non-null
* element returned by the factories of the initially given list is returned. If no element is
* created (all delegates returned null), this factory also returns null.
* <p>
* Only the root model must be identical for all delegate factories. Hence, the root element of the
* first delegate is returned.
*
* @author hoelzl
*/
public class DelegatingModelFactory extends DelegatingFactoryBase<IModelFactory>
implements IModelFactory {
/** Constructor. */
public DelegatingModelFactory(List<Class<? extends IModelFactory>> factories,
Object editedObject) {
super(factories, editedObject);
}
/** {@inheritDoc} */
@Override
protected Optional<? extends IModelFactory>
constructFactory(Class<? extends IModelFactory> delegateFactory) {
Constructor<? extends IModelFactory> ctor = null;
try {
Class<?> ctorParamType = (editedObject instanceof EObject)
? getInterfaceType((EObject)editedObject) : editedObject.getClass();
ctor = getMatchingAccessibleConstructor(delegateFactory, ctorParamType);
try {
return Optional.of(ctor.newInstance(editedObject));
} catch(InstantiationException | IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
error(ToolingKernelUIActivator.getDefault(), "Failed to instantiate the factory " +
delegateFactory.getSimpleName() + ".");
return Optional.empty();
}
} catch(NullPointerException | SecurityException e1) {
error(ToolingKernelUIActivator.getDefault(), "The factory " +
delegateFactory.getSimpleName() +
" is missing a single argument Constructor accepting the edited model." +
" Only such constructors are allowed for " +
IModelFactory.class.getSimpleName() + "s.");
return Optional.empty();
}
}
/** {@inheritDoc} */
@Override
public List<?> getContentAnchorageModels(Object parent) {
return getDelegateFactories().stream().map(f -> f.getContentAnchorageModels(parent))
.filter(lm -> !isNullOrEmpty(lm)).flatMap(Collection::stream).distinct()
.collect(toList());
}
/** {@inheritDoc} */
@Override
public Object getLinkStart(Object link) {
return getDelegateFactories().stream().map(f -> f.getLinkStart(link))
.filter(cc -> cc != null).findFirst().orElse(null);
}
/** {@inheritDoc} */
@Override
public Object getLinkEnd(Object link) {
return getDelegateFactories().stream().map(f -> f.getLinkEnd(link)).filter(cc -> cc != null)
.findFirst().orElse(null);
}
/** {@inheritDoc} */
@Override
public Object getParent(Object element) {
return getDelegateFactories().stream().map(f -> f.getParent(element))
.filter(cc -> cc != null).findFirst().orElse(null);
}
/** {@inheritDoc} */
@Override
public Object getRootModel() {
return editedObject;
}
/** {@inheritDoc} */
@Override
public List<?> getContentModels() {
return getDelegateFactories().stream().map(f -> f.getContentModels())
.filter(lm -> !isNullOrEmpty(lm)).flatMap(Collection::stream).distinct()
.collect(toList());
}
/** {@inheritDoc} */
@Override
public List<?> getDiagramAnchorageModels() {
return getDelegateFactories().stream().map(f -> f.getDiagramAnchorageModels())
.filter(lm -> !isNullOrEmpty(lm)).flatMap(Collection::stream).distinct()
.collect(toList());
}
/** {@inheritDoc} */
@Override
public List<?> getLinkModels() {
return getDelegateFactories().stream().map(f -> f.getLinkModels())
.filter(lm -> !isNullOrEmpty(lm)).flatMap(Collection::stream).distinct()
.collect(toList());
}
/** {@inheritDoc} */
@Override
public void update() {
// Not yet needed.
}
}
/*-------------------------------------------------------------------------+
| Copyright 2019 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.kernel.ui.extension.base.factory;
import java.util.List;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.IContentAnchorageMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.IContentMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.IDiagramAnchorageMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.mvc.ILinkMVCBundle;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.visual.IContentAnchorageVisual;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.visual.IContentVisual;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.visual.IDiagramAnchorageVisual;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.visual.ILinkVisual;
import org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.visual.IVisualFactory;
import org.eclipse.ui.IEditorPart;
import org.fortiss.tooling.kernel.service.ITransformationService;
import org.fortiss.tooling.kernel.ui.extension.base.LWFXEFEditorBase;
/**
* Base class for {@link IVisualFactory}s of extendable {@link LWFXEFEditorBase}
* {@link IEditorPart}s.The first non-null element returned by the factories of the initially given
* list is returned. If no element is
* created (all delegates returned null), this factory also returns null.
* <P>
* This class uses the {@link ITransformationService} to find a delegate visual factory for the
* model elements in question.
*
* @author hoelzl
*/
public class DelegatingVisualFactory extends DelegatingFactoryBase<IVisualFactory>
implements IVisualFactory {
/** Constructor. */
public DelegatingVisualFactory(List<Class<? extends IVisualFactory>> factories) {
super(factories, null);
}
/** {@inheritDoc} */
@Override
public IContentVisual createContentVisual(IContentMVCBundle modelBundle) {
return getDelegateFactories().stream().map(f -> f.createContentVisual(modelBundle))
.filter(cc -> cc != null).findFirst().orElse(null);
}
/** {@inheritDoc} */
@Override
public IDiagramAnchorageVisual
createDiagramAnchorageVisual(IDiagramAnchorageMVCBundle modelBundle) {
return getDelegateFactories().stream().map(f -> f.createDiagramAnchorageVisual(modelBundle))
.filter(cc -> cc != null).findFirst().orElse(null);
}
/** {@inheritDoc} */
@Override
public IContentAnchorageVisual
createContentAnchorageVisual(IContentAnchorageMVCBundle modelBundle) {
return getDelegateFactories().stream().map(f -> f.createContentAnchorageVisual(modelBundle))
.filter(cc -> cc != null).findFirst().orElse(null);
}
/** {@inheritDoc} */
@Override
public ILinkVisual createLinkVisual(ILinkMVCBundle modelBundle) {
return getDelegateFactories().stream().map(f -> f.createLinkVisual(modelBundle))
.filter(cc -> cc != null).findFirst().orElse(null);
}
}
......@@ -5,7 +5,7 @@ ConstraintUIService.java 433e35bb1c9bbc628c6ee070ff45632400becf4a GREEN
ContextMenuService.java ca3c899293f25b70ce8e5f0d86ca2f9683329d81 GREEN
EditPartFactoryService.java e9180c0020f1769d9e24ef3c08f9ca5599dbc5c3 GREEN
MarkerService.java b01b7706034691683df7bbc2e7828c42574b3147 GREEN
ModelEditorBindingService.java 948fcdc298a74e366351ad8835a145af6cd238be GREEN
ModelEditorBindingService.java 577f5db41abf240291434dbad6bc6b0fde1eeb2b GREEN
ModelElementHandlerService.java 07a30545ad687ff0fe13bf7a9348c41fb03e0b2c GREEN
NavigatorService.java 2b1361eac805996e22e5409dafff9707fbac3376 GREEN
ToolingKernelUIInternal.java 38903445a9084b7908716a00f41621dfb3126fca GREEN
......
......@@ -16,10 +16,13 @@
package org.fortiss.tooling.kernel.ui.internal;
import static java.util.Collections.emptyList;
import static java.util.Collections.sort;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.getParentElement;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.isChildElementOf;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.error;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
......@@ -96,6 +99,16 @@ public class ModelEditorBindingService extends EObjectAwareServiceBase<IModelEdi
@Override
public void startService() {
IKernelIntrospectionSystemService.getInstance().registerService(this);
for(List<IModelEditorBinding<EObject>> bindings : handlerMap.values()) {
sort(bindings, new Comparator<IModelEditorBinding<EObject>>() {
@Override
public int compare(IModelEditorBinding<EObject> o1,
IModelEditorBinding<EObject> o2) {
return o2.getPriority() - o1.getPriority();
}
});
}
}
/** Registers the given editor binding with the service. */
......@@ -169,12 +182,18 @@ public class ModelEditorBindingService extends EObjectAwareServiceBase<IModelEdi
/** {@inheritDoc} */
@Override
public List<IModelEditorBinding<EObject>> getBindings(EObject element) {
List<IModelEditorBinding<EObject>> bindings = getRegisteredHandlers(element.getClass());
public List<IModelEditorBinding<EObject>> getBindings(Class<? extends EObject> elementType) {
List<IModelEditorBinding<EObject>> bindings = getRegisteredHandlers(elementType);
if(bindings == null) {
bindings = emptyList();
}
return bindings;
return new ArrayList<>(bindings);
}
/** {@inheritDoc} */
@Override
public List<IModelEditorBinding<EObject>> getBindings(EObject element) {
return getBindings(element.getClass());
}
/** {@inheritDoc} */
......
ActionBarContributor.java 18d9db3744c5381cca8b6823b5f7bc18183a1cfa GREEN
ExtendableMultiPageEditor.java f8eb6fdc347098fb03e776f23fab61109aa55d6e GREEN
ExtendableMultiPageEditor.java b18b5eed364eaa1c83cbcb64a89288d1ad263f7d GREEN
IActionContributingEditor.java 4aa7496d67822de919a8cf0af0ddaafc61bf2919 GREEN
ModelElementEditorInput.java e269eff5d992d375a646e54d048f1f0efc6144dd GREEN
TutorialStepUIEditor.java 9eadc96c302b5131ff4cc3715777718fa06ec7e8 GREEN
......
......@@ -15,11 +15,10 @@
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.kernel.ui.internal.editor;
import static java.util.Collections.sort;
import static org.conqat.ide.commons.ui.logging.LoggingUtils.error;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.Comparator;
import java.util.EventObject;
import java.util.List;
......@@ -185,18 +184,13 @@ public class ExtendableMultiPageEditor extends MultiPageEditorPart
int pageIndex = 0;
List<IModelEditorBinding<EObject>> bindings =
IModelEditorBindingService.getInstance().getBindings(editedObject);
sort(bindings, new Comparator<IModelEditorBinding<EObject>>() {
@Override
public int compare(IModelEditorBinding<EObject> o1, IModelEditorBinding<EObject> o2) {
return o2.getPriority() - o1.getPriority();
}
});
for(IModelEditorBinding<EObject> editorBinding : bindings) {
try {
Class<? extends IEditorPart> editorClass =
editorBinding.getEditorClass(editedObject);
if(editorClass != null) {
IEditorPart editorPart = editorClass.newInstance();
Class<? extends EObject> inputType = editedObject.getClass();
IEditorPart editorPart = constructEditorPart(editorClass, inputType);
addPage(editorPart, getEditorInput());
setPageText(pageIndex++, editorBinding.getLabel(editedObject));
}
......@@ -206,6 +200,23 @@ public class ExtendableMultiPageEditor extends MultiPageEditorPart
}
}
/**
* Constructs an {@link IEditorPart} instance of the given {@code editorClass}.
* {@link IEditorPart}s that take the input model element type as a parameter are preferred over
* no-arg constructors.
*/
protected IEditorPart constructEditorPart(Class<? extends IEditorPart> editorClass,
Class<? extends EObject> inputType) throws Exception {
try {
Constructor<? extends IEditorPart> ctor = editorClass.getConstructor(Class.class);
return ctor.newInstance(inputType);
} catch(NoSuchMethodException | SecurityException e) {
// Fallback for no-arg constructors.
Constructor<? extends IEditorPart> ctor = editorClass.getConstructor();
return ctor.newInstance();
}
}
/** {@inheritDoc} */
@Override
public void doSave(IProgressMonitor monitor) {
......
......@@ -4,7 +4,7 @@ IConstraintUIService.java 07df6b9553bf04f8c414c976dc630e6a1dd5ec96 GREEN
IContextMenuService.java cfb6b8237b6cd2b0e461991a9ceb95969f330265 GREEN
IEditPartFactoryService.java c448bff63fb81f57037c9f1dc5319859c12d0c4d GREEN
IMarkerService.java d433e838e387dd2fe61b8dea7395ebb7203ae39b GREEN
IModelEditorBindingService.java e000fb7faf558d1201c5c26e449e0019b4ec24b0 GREEN
IModelEditorBindingService.java ce2ae1957e2232bb0fac1d1d262103f9adfc5266 GREEN
IModelElementHandlerService.java c04c2876ccb8b3f8597c8e443f9c7c3db0945430 GREEN
INavigatorService.java 8d2ffeb6f075d3abea904b84d8a40090d97837fd GREEN
ITutorialUIService.java 72707c60c3d23d8ffc5c579cb9b022bb614eb094 GREEN
......@@ -54,6 +54,9 @@ public interface IModelEditorBindingService {
/** Returns the currently active editor. */
IModelEditor<EObject> getActiveEditor();
/** Returns registered editor bindings for the given class. */
List<IModelEditorBinding<EObject>> getBindings(Class<? extends EObject> elementType);
/** Returns registered editor bindings for the given {@link EObject}. */
List<IModelEditorBinding<EObject>> getBindings(EObject element);
......
......@@ -6,7 +6,7 @@ IEclipseResourceStorageLocationProvider.java 0ab7f304d52a9d86f01f66e308e9a7ca420
IElementCompositor.java 5b0ab1732f71b3f8467e0276c844f0dd549e191f GREEN
ILibraryElementHandler.java 00ef5b25c63b8570006e6f6748aed0da1f33a5f1 GREEN
ILogMessageHandler.java 9ab53e836a095ef00fd84ecc0375167edf593b46 GREEN
IMigrationProvider.java fdb1078dfca10a82a18f79b862d7b8644e80e14e GREEN
IMigrationProvider.java 241bfd8594dfb86ce0f89dc95b43662f52d9e450 GREEN
IPrototypeProvider.java d5e3dbae19b5654caf28b81da6b1609d3c12be12 GREEN
IStorageProvider.java d9b14cdd254d0c956dc5715c1c4d4d955a705dd5 GREEN
ITransformationProvider.java a4ee2ea08720bb2fce29806062eb01499bb5071e GREEN
......
......@@ -45,12 +45,12 @@ public interface IMigrationProvider extends IObjectAware<ITopLevelElement> {
/**
* Applies the provider to the given element.
*
* The parameter "unknownFeatures" returns a map indicating the features that are not recognized
* The parameter "unknownFeatures" indicates the features that are not recognized
* in the model. This can be useful to detect features coming from old models and can be then
* translated to the new model by a migrator.
*
* The migrator should remove from unknownFeatures the features that it dealt with.
* If one forgets to do so, the migrator will run into an infinite loop!
* @return all unknown features that have successfully been migrated.
*/
void migrate(ITopLevelElement modelElement, Map<EObject, AnyType> unknownFeatures);
Map<EObject, AnyType> migrate(ITopLevelElement modelElement,
Map<EObject, AnyType> unknownFeatures);
}
/*-------------------------------------------------------------------------+
| Copyright 2018 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.kernel.extension.base;
import static org.conqat.lib.commons.reflect.ReflectionUtils.isInstanceOfAny;
import static org.eclipse.emf.ecore.util.EcoreUtil.delete;
import static org.fortiss.tooling.common.util.LambdaUtils.asStream;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.xml.type.AnyType;
import org.fortiss.tooling.kernel.extension.IMigrationProvider;
import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
import org.fortiss.tooling.kernel.model.INamedCommentedElement;
/**
* Remove artificats related to deprecated use case model.
*
* @author barner
*/
public abstract class RemoveDeprecatedArtifactsMigrationProviderBase implements IMigrationProvider { // NO_UCD
// Migrators are retired after a release, but this base class should be available when needed.
// See https://af3-developer.fortiss.org/projects/autofocus3/wiki/Model_Migration
/** Returns the {@link Collection} of deprecated artifact types to be removed from the model. */
protected abstract Collection<Class<? extends EObject>> getDeprecatedArtifacts();
/**
* Returns the {@link Collection} of deprecated root artifact types (possibly empty subset of
* {@link #getDeprecatedArtifacts()}) for which a comment is added to the migrated model that
* deprecated artifacts have been removed.
*/
protected abstract Collection<Class<? extends EObject>> getDeprecatedRootArtifacts();
/** Returns the {@link Stream} of deprecated model elements to be removed. */
private Stream<EObject> getDeprecatedModelElements(ITopLevelElement modelElement) {
Stream<EObject> root = asStream(modelElement.getRootModelElement().eAllContents());
Collection<Class<? extends EObject>> deprArtifacts = getDeprecatedArtifacts();
return root.filter(
e -> isInstanceOfAny(e, deprArtifacts.toArray(new Class[deprArtifacts.size()])));
}
/** {@inheritDoc} */
@Override
public boolean needMigration(ITopLevelElement modelElement,
Map<EObject, AnyType> unknownFeatures) {
return getDeprecatedModelElements(modelElement).findAny().isPresent();
}
/** {@inheritDoc} */
@Override
public void migrate(ITopLevelElement modelElement, Map<EObject, AnyType> unknownFeatures) {
EObject object;
do {
object = null;
Stream<EObject> deprecatedModelElements = getDeprecatedModelElements(modelElement);
Optional<EObject> anyObject = deprecatedModelElements.findAny();
if(anyObject.isPresent()) {
object = anyObject.get();
if(object.eContainer() instanceof INamedCommentedElement) {
INamedCommentedElement parent = (INamedCommentedElement)object.eContainer();
if(parent.getComment() == null || parent.getComment().isEmpty()) {
for(Class<? extends EObject> rootType : getDeprecatedRootArtifacts()) {
if(rootType.isAssignableFrom(object.getClass())) {
parent.setComment(rootType.getSimpleName() +
" models are no longer supported. This sub-model has been removed automatically!");
break;
}
}
}
}
delete(object);
}
} while(object != null);
}
}
......@@ -7,7 +7,7 @@ ElementCompositorService.java 98c5d27e09881e60aa4f87c1ac0c7787cdec9f7c GREEN
LibraryPrototypeProvider.java b77eddbdca78f561ffb1233e98817be361c690ae GREEN
LibraryService.java d22671ba820466062852c15873698adf28960d94 GREEN
LoggingService.java da784259f7b456b54bf75c41ec268f64919ce78d GREEN
MigrationService.java 632c13563a3d69681e2a608023fcdadbe5340c4b GREEN
MigrationService.java 2f800eac9793aa736089a802bbfc2c4c1c09770d GREEN
PersistencyService.java 103eef642c038ef63fa49b743d803aaa3fea2724 GREEN
PrototypeService.java 18c3db05ab11f189a9711bf241c3c7f35c954a9e GREEN
ToolingKernelInternal.java d624a5f6b237ce993e150e2b8d1b4390e3fc8f7a GREEN
......
......@@ -16,18 +16,21 @@
package org.fortiss.tooling.kernel.internal;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toSet;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstChildWithType;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.error;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.warning;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Stream;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.xml.type.AnyType;
import org.fortiss.tooling.kernel.ToolingKernelActivator;
import org.fortiss.tooling.kernel.extension.IMigrationProvider;
......@@ -97,19 +100,6 @@ public class MigrationService extends ObjectAwareServiceBase<IMigrationProvider>
return false;
}
/** Extracts the list of feature names from a map of features. */
private List<String> featuresToStrings(Map<EObject, AnyType> features) {
List<String> res = new BasicEList<String>();
for(AnyType featuresPerKey : features.values()) {
FeatureMap actualFeatures = featuresPerKey.getMixed();
actualFeatures.addAll(featuresPerKey.getAnyAttribute());
for(FeatureMap.Entry feature : actualFeatures) {
res.add(feature.getEStructuralFeature().getName());
}
}
return res;
}
/** {@inheritDoc} */
@Override
public void migrate(final ITopLevelElement input, final Map<EObject, AnyType> unknownFeatures) {
......@@ -117,17 +107,12 @@ public class MigrationService extends ObjectAwareServiceBase<IMigrationProvider>
@Override
public void run() {
Map<EObject, AnyType> migratedFeatures = new HashMap<EObject, AnyType>();
for(IMigrationProvider provider : getProviders(input)) {
if(provider.needMigration(input, unknownFeatures)) {
provider.migrate(input, unknownFeatures);
migratedFeatures.putAll(provider.migrate(input, unknownFeatures));
}
}
if(!unknownFeatures.isEmpty()) {
error(ToolingKernelActivator.getDefault(),
input.getSaveableName() + " contains one or more unknown feature(s): " +
featuresToStrings(unknownFeatures));
}
for(IMigrationProvider provider : getProviders(input)) {
if(provider.needMigration(input, unknownFeatures)) {
error(ToolingKernelActivator.getDefault(),
......@@ -136,6 +121,19 @@ public class MigrationService extends ObjectAwareServiceBase<IMigrationProvider>
"already performed. Please fix the migrator (or model).");
}
}
unknownFeatures.entrySet().removeAll(migratedFeatures.entrySet());
if(!unknownFeatures.isEmpty()) {
Stream<AnyType> anyTypes = unknownFeatures.values().stream()
.map(v -> v.getMixed()).flatMap(f -> f.stream()).map(e -> e.getValue())
.filter(AnyType.class::isInstance).map(AnyType.class::cast);
String removedTypes = anyTypes.map(a -> a.eClass().getName()).collect(toSet())
.stream().collect(joining(", "));
warning(ToolingKernelActivator.getDefault(), input.getSaveableName() +
" contains one or more feature(s) of the following unkown types that will be deleted: " +
removedTypes + ".");
unknownFeatures.clear();
}
}
});
......
AutoUndoCommandStack.java fc326adf66c6cea2354884cdc240da5f2f82689a GREEN
EMFTransactionalCommand.java ba4b5bead9768b6ce6c955b9238cd96cb722533c GREEN
EclipseResourceStorageService.java e29e32272286921c5e43963253902b3ba54490c7 GREEN
ModelContext.java 55de5f19c5d625f935fb8136ff72d80b3a54ff19 GREEN
ModelContext.java db1735834c85e7b508266f56463d011f2b72af0e GREEN
NonDirtyingEMFTransactionalCommand.java d288ebe35d22442c603496b0c917fb99a8febeea GREEN
......@@ -330,7 +330,9 @@ class ModelContext implements ITopLevelElement, CommandStackListener {
// Step 3..n: Save resources not managed by kernel
for(Resource currentResource : rset.getResources()) {
if(currentResource != resource && !editingDomain.isReadOnly(currentResource)) {
if(currentResource != resource && !editingDomain.isReadOnly(currentResource) &&
!currentResource.getContents().isEmpty()) {
// do not save resources which are not contained (by a FileProject)
try {
currentResource.save(saveOptions);
} catch(IOException e) {
......
......@@ -10,6 +10,6 @@ JavaUtils.java 65cdadfb9137a240ad59992eacf53a15b7f20804 GREEN
KernelModelElementUtils.java fded09befe7e543fc04ea5184ffc1c8a309d7a66 GREEN
LoggingUtils.java 0e0aa5d466d80ea29cfc7e91178b23a5cdd4ddf7 GREEN
PrototypesUtils.java ec75bed75cfc5103f1f38e3a29df86f729428775 GREEN
ResourceUtils.java 698c7db34acb4f1a258a1953e6afcca9823763a8 GREEN
ResourceUtils.java e31eda3fdbedd2e44c85d471f717b14f92a3c663 GREEN
TransformationUtils.java 552d3a9d56d34450be781af828efe0b8aa5d359e GREEN
UniqueIDUtils.java 665955b1790c1bd1c2087e23114da920bfec2265 GREEN
......@@ -51,6 +51,11 @@ import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceFactoryImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.PackageNotFoundException;
import org.eclipse.emf.ecore.xmi.XMLHelper;
import org.eclipse.emf.ecore.xmi.XMLLoad;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.SAXXMIHandler;
import org.eclipse.emf.ecore.xmi.impl.XMILoadImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl;
import org.eclipse.emf.ecore.xml.type.AnyType;
......@@ -58,6 +63,7 @@ import org.fortiss.tooling.kernel.ToolingKernelActivator;
import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
import org.fortiss.tooling.kernel.model.IIdLabeled;
import org.fortiss.tooling.kernel.service.IPersistencyService;
import org.xml.sax.helpers.DefaultHandler;
/**
* Utility class for dealing with EMF {@link Resource}s.
......@@ -77,12 +83,79 @@ public final class ResourceUtils {
*/
public static class KernelResourceFactory extends ResourceFactoryImpl {
/**
* XMIHandler that cleans up dangling references when loading models with unknown types
* instead of throwing an exception.
*/
private final class DanglingReferencesCleanupXMIHandler extends SAXXMIHandler {
/** Constructor. */
private DanglingReferencesCleanupXMIHandler(XMLResource xmiResource, XMLHelper helper,
Map<?, ?> options) {
super(xmiResource, helper, options);
}
/** {@inheritDoc} */
@Override
protected void handleForwardReferences(boolean isEndDocument) {
List<SingleReference> toRemoveFwdSingleRefs = new ArrayList<>();
for(SingleReference ref : forwardSingleReferences) {
EObject obj;
try {
obj = xmlResource.getEObject((String)ref.getValue());
} catch(RuntimeException exception) {
obj = null;
}
if(obj == null || obj instanceof AnyType) {
warnRefWithUnknownType((AnyType)obj, ref.getLineNumber(),
ref.getColumnNumber());
toRemoveFwdSingleRefs.add(ref);
}
}
forwardSingleReferences.removeAll(toRemoveFwdSingleRefs);
List<ManyReference> toRemoveFwdManyRefs = new ArrayList<>();
for(ManyReference ref : forwardManyReferences) {
Object[] values = ref.getValues();
for(String id : (String[])values) {
EObject obj;
try {
obj = xmlResource.getEObject(id);
} catch(RuntimeException exception) {
obj = null;
}
if(obj == null || obj instanceof AnyType) {
warnRefWithUnknownType((AnyType)obj, ref.getLineNumber(),
ref.getColumnNumber());
toRemoveFwdManyRefs.add(ref);
break;
}
}
}
forwardManyReferences.removeAll(toRemoveFwdManyRefs);
super.handleForwardReferences(isEndDocument);
}
/** Issues a warning for a given {@link AnyType}d object. */
private void warnRefWithUnknownType(AnyType obj, int line, int col) {
String message = "Removing reference to element with unknown type" +
(obj != null ? " \"" + obj.eClass().getName() + "\"" : "") + " in line " +
line + ", column " + col + ".";
// Static inline not possible: name clash with XMLHandler::warning()
LoggingUtils.warning(ToolingKernelActivator.getDefault(), message);
}
}
/**
* {@link XMIResourceImpl} used to persist models managed by the tooling kernel.
*
* @author barner
*/
private final class KernelXMIResource extends XMIResourceImpl {
/** Constructs a new {@link KernelXMIResource}. */
private KernelXMIResource(URI uri) {
super(uri);
......@@ -99,7 +172,7 @@ public final class ResourceUtils {
public String getID(EObject eObject) {
String id = super.getID(eObject);
if(id == null && eObject instanceof IIdLabeled) {
id = new Integer(((IIdLabeled)eObject).getId()).toString();
id = String.valueOf(((IIdLabeled)eObject).getId());
setID(eObject, id);
}
return id;
......@@ -140,6 +213,18 @@ public final class ResourceUtils {
}
return eObjectToExtensionMap;
}
/** {@inheritDoc} */
@Override
protected XMLLoad createXMLLoad() {
return new XMILoadImpl(createXMLHelper()) {
/** {@inheritDoc} */
@Override
protected DefaultHandler makeDefaultHandler() {
return new DanglingReferencesCleanupXMIHandler(resource, helper, options);
}
};
}
}
/** {@inheritDoc} */
......@@ -196,13 +281,13 @@ public final class ResourceUtils {
/**
* <p>
* Determines the {@link ITopLevelElement} which shares the same {@link ResourceSet} as the a
* {@link Resource} with the specified {@link URI}. If no such {@link Resource} has been loaded,
* {@code null} is returned.
* Determines the {@link ITopLevelElement} which shares the same {@link ResourceSet} as the
* a {@link Resource} with the specified {@link URI}. If no such {@link Resource} has been
* loaded, {@code null} is returned.
* </p>
* <p>
* This is useful to determine to which model managed by the Kernel a given (external) model is
* linked.
* This is useful to determine to which model managed by the Kernel a given (external) model
* is linked.
* </p>
*
* @param uri
......@@ -226,8 +311,8 @@ public final class ResourceUtils {
}
/**
* Obtains a model of a given type from a {@code resourceSet}, or {@code null} if it could not
* be found.
* Obtains a model of a given type from a {@code resourceSet}, or {@code null} if it could
* not be found.
*
* @param resourceSet
* {@link ResourceSet} from which model of given type should be determined
......@@ -251,25 +336,30 @@ public final class ResourceUtils {
}
/**
* Obtains a model of a given type from a {@code resourceSet}, and creates the model if it does
* not exist yet (and adds it to the given {@code resourceSet}). Returns {@code null} if the
* model could not be created.
* Obtains a model of a given type from a {@code resourceSet}, and creates the model if it
* does not exist yet (and adds it to the given {@code resourceSet}). Returns {@code null} if
* the model could not be created.
*
* @param resourceSet
* {@link ResourceSet} from which model of given type should be determined
* @param clazz
* Type of model to be returned.
* @param factory
* {@link EFactory} to create root model element in case the model does not exist in
* {@link EFactory} to create root model element in case the model does not exist
* in
* the {@code resourceSet} yet.
* @param fileExtension
* File extension to be used in case a new resource has to be created and added to
* the given given {@code resourceSet}. In case this parameter is {@code null}, this
* File extension to be used in case a new resource has to be created and added
* to
* the given given {@code resourceSet}. In case this parameter is {@code null},
* this
* method effectively behaves like {@link #getModel(ResourceSet, Class)}.
* @param referenceClazz
* Type of root model element whose {@link Resource} {@link URI} should be used to
* Type of root model element whose {@link Resource} {@link URI} should be used
* to
* derive the base name in case a new {@link Resource} has to be created. In case
* this parameter is {@code null}, the {@link URI} of the first {@link Resource} in
* this parameter is {@code null}, the {@link URI} of the first {@link Resource}
* in
* the given {@link ResourceSet} is used.
*
* @return Model of a given type, or {@code null} if it could not be created.
......@@ -368,12 +458,14 @@ public final class ResourceUtils {
* {@link Resource} for which {@link URI}s of directly or indirectly referencing
* resources should be determined.
* @param includeSelf
* Flag if the {@link URI} of the given {@code resource} should be contained in the
* Flag if the {@link URI} of the given {@code resource} should be contained in
* the
* result.
* @param progressMonitor
* {@link IProgressMonitor} (may be {@code null}). Loading all resources in a
* directory may be a long-running operation.
* @return {@link URI}s of directly or indirectly referencing resources, possibly including the
* @return {@link URI}s of directly or indirectly referencing resources, possibly including
* the
* {@link URI} of the given {@code resource} itself (see {@code includeSelf}).
*/
public static Collection<URI> getReferencingResourceURIs(Resource resource, boolean includeSelf,
......