ExtendedLibrariesModel.java
/**
* Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
* All Rights Reserved.
*
* NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
* OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
* MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
* SPDX-License-Identifier: EPL-2.0
*
* Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
*
* This program includes and/or can make use of certain third party source code, object code, documentation and other
* files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
* configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
* conditions contained in any such Third Party Software or separate license file distributed with such Third Party
* Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
* aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
* censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
*/
package org.osate.ge.errormodel.ui.viewmodels;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.swt.widgets.Display;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.util.Strings;
import org.osate.aadl2.AadlPackage;
import org.osate.ge.BusinessObjectSelection;
import org.osate.ge.aadl2.ui.AadlModelAccessUtil;
import org.osate.ge.errormodel.util.ErrorModelGeUtil;
import org.osate.ge.swt.BaseObservableModel;
import org.osate.ge.swt.selectors.FilteringSelectorDialog;
import org.osate.ge.swt.selectors.LabelFilteringListSelectorModel;
import org.osate.ge.swt.selectors.ListEditorModel;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorModelLibrary;
import org.osate.xtext.aadl2.errormodel.errorModel.ErrorModelPackage;
import com.google.common.collect.Streams;
/**
* View model which sets the extended error libraries for a {@link ErrorModelLibrary} objects associated with {@link AadlPackage} instances
* in a {@link BusinessObjectSelection}.
* The model will not provide element or allow editing with selections with more than one {@link AadlPackage} which has an {@link ErrorModelLibrary}.
*
*/
public class ExtendedLibrariesModel extends BaseObservableModel implements ListEditorModel<ErrorModelLibrary> {
private BusinessObjectSelection bos;
private ErrorModelLibrary selectedExtendedLib;
/**
* Creates a new instance
* @param bos the initial business object selection
*/
public ExtendedLibrariesModel(final BusinessObjectSelection bos) {
setBusinessObjectSelection(bos);
}
/**
* Refreshes the state of the model based on the specified business object selection
* @param value the business object selection
*/
public void setBusinessObjectSelection(final BusinessObjectSelection value) {
this.bos = Objects.requireNonNull(value, "value must not be null");
triggerChangeEvent();
}
@Override
public Stream<ErrorModelLibrary> getElements() {
if (!singleErrorModelSelected()) {
return Stream.empty();
}
final Optional<ErrorModelLibrary> selectedLib = getSelectedErrorModelLibraries().findFirst();
return selectedLib.map(lib -> lib.getExtends().stream()).orElse(Stream.empty());
}
@Override
public ErrorModelLibrary getSelectedElement() {
return selectedExtendedLib;
}
@Override
public void setSelectedElement(final ErrorModelLibrary value) {
if (!Objects.equals(selectedExtendedLib, value)) {
selectedExtendedLib = value;
triggerChangeEvent();
}
}
@Override
public String getLabel(final ErrorModelLibrary element) {
if (element == null) {
return "<null>";
}
final EObject root = element.getElementRoot();
if (!(root instanceof AadlPackage)) {
return "<Unable to Retrieve Package>";
}
return Strings.emptyIfNull(((AadlPackage) root).getQualifiedName());
}
@Override
public boolean canAdd() {
return singleErrorModelSelected();
}
@Override
public void addElement() {
getSelectedErrorModelLibraries().findFirst().ifPresent(readonlyLib -> {
final Resource resource = readonlyLib.getElementRoot().eResource();
if (resource == null) {
throw new RuntimeException("Unable to get resource");
}
// Prompt user to select an error model library
final ErrorModelLibraryDescriptionSingleSelectionModel model = new ErrorModelLibraryDescriptionSingleSelectionModel(
AadlModelAccessUtil.getAllEObjectsByType(resource,
ErrorModelPackage.eINSTANCE.getErrorModelLibrary()));
if (FilteringSelectorDialog.open(Display.getCurrent().getActiveShell(), "Select Error Library to Extend",
new LabelFilteringListSelectorModel<>(model))) {
// Add the selected error mode library
modifyErrorModelLibrary(lib -> {
final ErrorModelLibrary libToExtend = (ErrorModelLibrary) model.getSelectedElement()
.getEObjectOrProxy();
// Do not add library if it extends already
if (lib.getExtends()
.stream()
.map(EcoreUtil::getURI)
.noneMatch(uri -> uri.equals(EcoreUtil.getURI(libToExtend)))) {
lib.getExtends().add(libToExtend);
}
});
}
});
}
private class ErrorModelLibraryDescriptionSingleSelectionModel
extends ErrorModelObjectDescriptionCollectionSingleSelectorModel {
public ErrorModelLibraryDescriptionSingleSelectionModel(Collection<IEObjectDescription> objectDescriptions) {
super(objectDescriptions);
}
@Override
public Stream<IEObjectDescription> getElements() {
// Do not allow selection of ErrorModelLibraries of selected package resources
final Set<URI> selectedPkgContentURIs = bos.boStream(AadlPackage.class)
.map(AadlPackage::eResource)
.flatMap(resource -> Streams.stream(resource.getAllContents()))
.map(EcoreUtil::getURI)
.collect(Collectors.toSet());
return super.getElements().filter(desc -> !selectedPkgContentURIs.contains(desc.getEObjectURI()));
}
}
@Override
public void removeElement(final ErrorModelLibrary value) {
// Remove the error model library from the list of extended error model libraries based on URI
modifyErrorModelLibrary(lib -> {
final URI uriToRemove = EcoreUtil.getURI(value);
lib.getExtends().removeIf(t -> Objects.equals(uriToRemove, EcoreUtil.getURI(t)));
});
}
/**
* Modifies the error model library of all AADL packages which have an error model library contained in the business object selection.
* @param modifier is the function to use to modify the library
*/
private void modifyErrorModelLibrary(final Consumer<ErrorModelLibrary> modifier) {
bos.modify("Modify Extended Error Model Libraries",
boc -> ErrorModelGeUtil.getErrorModelLibrary((boc.getBusinessObject(AadlPackage.class).get()))
.isPresent(),
boc -> ErrorModelGeUtil.getErrorModelLibrary((boc.getBusinessObject(AadlPackage.class).get())).get(),
(lib, boc) -> modifier.accept(lib));
}
/**
* Finds {@link ErrorModelLibrary} based on the current business object selection
* @return a stream of {@link ErrorModelLibrary} which are owned by the {@link AadlPackage} instances in the current business object selection.
*/
private Stream<ErrorModelLibrary> getSelectedErrorModelLibraries() {
return bos.boStream(AadlPackage.class)
.flatMap(pkg -> ErrorModelGeUtil.getErrorModelLibrary(pkg).map(Stream::of).orElse(null));
}
private boolean singleErrorModelSelected() {
return getSelectedErrorModelLibraries().limit(2).count() == 1;
}
}