Universal Robots Forum

Should I add a Feature to DataModel?

In createfeatureswing sample, in CreateFeatureInstallationNodeContribution a feature is created by:

featureContributionModel = apiProvider.getInstallationAPI().getFeatureContributionModel();
Feature feature = featureContributionModel.addFeature(FEATURE_KEY, SUGGESTED_FEATURE_NAME, positionParameters.getPose());
model.set(FEATURE_KEY, feature);

I have tested in my URCap that, even removing:

model.set(FEATURE_KEY, feature);

if I save the installation, the feature is still present the next time I load the installation. The only difference I can see is that there is no * after the installation to mark it as unsaved. This happens also when updating the feature with


Is this the only difference in using model.set() for a Feature? Should I use it and why?

Hi Alessio,

storing the feature data additionally in the data-model is not required for adding it in the installation. After you call addFeature and save the installation it is stored in the feature list similar to a feature provided by the user directly.

The data-model is in this sample used later in the program node to assure the feature is defined and to retrieve the correspondent joint angles. If you use your provided feature differently, you do not need to store this info in data-model as well.


1 Like

Hi Stefan,

I think the fact that there is no * after the installation is a bug, because it’s unclear for the user that he should save the installation to keep the new feature.

Hi Alessio,

after adjusting the CreateFeatureSwing-Sample to remove all datamodel adjustments, I the installation was still marked as changed once I inserted the Feature.

Can you provide some sample code to replicate your behavior?

I have just created this sample in Starter Package 1.11.0.


package myurcap.FeatureTest.impl;

import com.ur.urcap.api.contribution.InstallationNodeContribution;
import com.ur.urcap.api.contribution.installation.CreationContext;
import com.ur.urcap.api.contribution.installation.InstallationAPIProvider;
import com.ur.urcap.api.domain.data.DataModel;
import com.ur.urcap.api.domain.feature.Feature;
import com.ur.urcap.api.domain.feature.FeatureContributionModel;
import com.ur.urcap.api.domain.script.ScriptWriter;
import com.ur.urcap.api.domain.userinteraction.keyboard.KeyboardInputCallback;
import com.ur.urcap.api.domain.userinteraction.keyboard.KeyboardInputFactory;
import com.ur.urcap.api.domain.userinteraction.keyboard.KeyboardNumberInput;
import com.ur.urcap.api.domain.value.PoseFactory;
import com.ur.urcap.api.domain.value.simple.Angle;
import com.ur.urcap.api.domain.value.simple.Length;

public class FeatureTestInstallationNodeContribution implements InstallationNodeContribution {

	private FeatureContributionModel featureContributionModel;
	private KeyboardInputFactory keyboardFactory;
	private PoseFactory poseFactory;
	private FeatureTestInstallationNodeView view;
	private static final String FEATURE_ID_KEY = "feature-id-key";

	public FeatureTestInstallationNodeContribution(InstallationAPIProvider apiProvider, FeatureTestInstallationNodeView view,
			DataModel model, CreationContext context) {
		this.view = view;
		featureContributionModel = apiProvider.getInstallationAPI().getFeatureContributionModel();
		keyboardFactory = apiProvider.getUserInterfaceAPI().getUserInteraction().getKeyboardInputFactory();
		poseFactory = apiProvider.getInstallationAPI().getValueFactoryProvider().getPoseFactory();

	private void createFeatureIfAbsent() {
		if (featureContributionModel.getFeature(FEATURE_ID_KEY) == null) {
			featureContributionModel.addFeature(FEATURE_ID_KEY, "Feature_Test", poseFactory.createPose(0, 0, 0, 0, 0, 0, Length.Unit.M, Angle.Unit.RAD));
	private Feature getFeature() {
		return featureContributionModel.getFeature(FEATURE_ID_KEY);

	public void openView() {
	private double getFeatureX() {
		return getFeature().getPose().getPosition().getX(Length.Unit.M);

	public void closeView() {
		// TODO Auto-generated method stub


	public void generateScript(ScriptWriter writer) {
		// TODO Auto-generated method stub

	public KeyboardNumberInput<Double> getKeyboardForDouble() {
		return keyboardFactory.createDoubleKeypadInput();

	public KeyboardInputCallback<Double> getCallBackForX() {
		return new KeyboardInputCallback<Double>() {
			public void onOk(Double value) {
				featureContributionModel.updateFeature(getFeatureKey(), poseFactory.createPose(value, 0, 0, 0, 0, 0, Length.Unit.M, Angle.Unit.RAD));

	private String getFeatureKey() {
		return FEATURE_ID_KEY;



package myurcap.FeatureTest.impl;

import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JPanel;
import javax.swing.JTextField;

import com.ur.urcap.api.contribution.ViewAPIProvider;
import com.ur.urcap.api.contribution.installation.swing.SwingInstallationNodeView;
import com.ur.urcap.api.domain.userinteraction.keyboard.KeyboardNumberInput;

public class FeatureTestInstallationNodeView implements SwingInstallationNodeView<FeatureTestInstallationNodeContribution> {

	private FeatureTestInstallationNodeContribution contribution;
	private JTextField xTextField;

	public FeatureTestInstallationNodeView(ViewAPIProvider apiProvider) {
		// TODO Auto-generated constructor stub

	public void buildUI(JPanel panel, FeatureTestInstallationNodeContribution contribution) {
		this.contribution = contribution;

	private Component createXTextField() {
		xTextField = new JTextField();
		xTextField.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent arg0) {
				KeyboardNumberInput<Double> keyboard = contribution.getKeyboardForDouble();
				keyboard.show(xTextField, contribution.getCallBackForX());
		return xTextField;
	public void setxTextFieldText(double value) {


I have tested that, when I do updateFeature() by editing the X text field, the feature is modified but I don’t see the * mark after the installation name.