# EMF auf Modeländerung reagieren



## greeni (23. Sep 2010)

Ich habe da mal eine Verständnisfrage zu EMF. Ich hab verstanden das mir EMF in mein Model ein Observerpattern intigriert. Aber ich verstehe nicht wie ich auf Änderungen des Datenmodels reagieren kann. Wie bekomme ich in meinem EMF Editor mit (oder auch auf einer anderen GUI) wenn sich in meinem Datenmodell irgendetwas geändert hat?


----------



## Gast2 (23. Sep 2010)

Kannst auf dein Model ein Adapter adden


```
eAdapters().add(new Adapter() {
        public Notifier getTarget() {
            return null;
        }

        public boolean isAdapterForType(Object type) {
            return false;
        }

        public void notifyChanged(Notification notification) {
        }

        public void setTarget(Notifier newTarget) {
        }

     });
```


----------



## greeni (23. Sep 2010)

Cool, Danke es funktioniert!!


----------



## Wildcard (23. Sep 2010)

Tipp: Es gibt auch einen EContentAdapter. Damit kannst du auf alle Änderungen im gesamten Objektbaum (oder einem Teilbaum) hören. Soetwas ist zB praktisch um ein Dirty Flag oder ähnliches zu setzen.
Es gibt sogar einen Changerecorder der automatisch alle gemachten Änderungen mitschneidet. Diese kannst du dann zu jeder Zeit rückgängig machen, abspeichern, oder sonstwas damit anstellen.


----------



## Gast2 (24. Sep 2010)

Wildcard hat gesagt.:


> Tipp: Es gibt auch einen EContentAdapter. Damit kannst du auf alle Änderungen im gesamten Objektbaum (oder einem Teilbaum) hören. Soetwas ist zB praktisch um ein Dirty Flag oder ähnliches zu setzen.
> Es gibt sogar einen Changerecorder der automatisch alle gemachten Änderungen mitschneidet. Diese kannst du dann zu jeder Zeit rückgängig machen, abspeichern, oder sonstwas damit anstellen.



Gibts dafür ein Beispiel?


----------



## Wildcard (24. Sep 2010)

Für was denn konkret?


----------



## Gast2 (25. Sep 2010)

Für das rückgängig machen des changerecorders oder wie man den benutzt und das dirty flag zu setzten. Weil bei mir im Editor weiß ich nie richtig wie man ein Objekt dirty setzt und abpürft ob sich wirklich was geändert hat.


----------



## Wildcard (26. Sep 2010)

Für das dirty Flag brauchst du keinen Changerecorder, du kannst einfach die Resource nach isModified fragen


----------



## Gast2 (26. Sep 2010)

Okay hab noch nicht soviel Erfahrung mit EMF. Woher bekomm ich denn die Resource?


----------



## Wildcard (26. Sep 2010)

Die Resource bekommst du wenn du ein Modell lädst.


----------



## Gast2 (26. Sep 2010)

wenn ich ein neues model anlege, woher bekomm ich dann die Ressource? 
Gibt es irgendwo ein Beispiel dazu?


----------



## Wildcard (26. Sep 2010)

In dem du eine Resource instanzierst. Welche Resource, das hängt von deinem Modell ab.


----------



## Gast2 (26. Sep 2010)

Mhm check ich grad nicht von ws hängt es denn ab ? 
Ich hab einfach einen Editor in dem alle Attribute eines Models eingeben kann also wenn ein Attribut eingegeben wird kann man abspeichern. Danach natrülich nur noch wenn sich etwas geändert hat.


----------



## Wildcard (26. Sep 2010)

Wenn du etwas speicherst, dann hast du auch eine Resource, denn in EMF werden Resources gespeichert.


----------



## Gast2 (26. Sep 2010)

Wildcard hat gesagt.:


> Wenn du etwas speicherst, dann hast du auch eine Resource, denn in EMF werden Resources gespeichert.



Ich speicher etwas in die Datenbank... Wie gesagt ich versteh den zusammenhang gerade nicht


----------



## Wildcard (27. Sep 2010)

Auch Teneo hat Resourcen:
Teneo/Hibernate/EMF Resource - Eclipsepedia


----------



## Gast2 (27. Sep 2010)

Ich benutze EclipseLink mal schauen ob es dafür auch was gibt.

Edit: Also über EclipseLink und Resourcen finde ich nichts =(...

Edit Edit: EMF/Teneo 1.0.4/EclipseLink Support - Eclipsepedia


----------



## Gast2 (27. Sep 2010)

Also ich habs mal hinbekommen mit EcliseLink testweise ein Model zu speichern

```
@Override
	public Kunde createKunde(Kunde kunde) {
		String query = EclipseLinkURIUtil.createContentsEqualQuery(kunde.eClass(), VerwaltungPackage.eINSTANCE.getPerson_Name(), kunde.getName());
		URI libraryURI = EclipseLinkURIUtil.createEclipseLinkURI("verwaltung",query);
		ResourceSet resourceSet1 = new ResourceSetImpl();
		resourceSet1.getLoadOptions().put(
				PersistenceUnitProperties.CLASSLOADER,
				this.getClass().getClassLoader());
		Resource kundeResource1 = resourceSet1.createResource(libraryURI);
		
		
		kundeResource1.getContents().add(kunde);
		try {
			kundeResource1.save(Collections.EMPTY_MAP);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(kunde.eResource());
		System.out.println(kunde.getId());
		return kunde;
	}
```
1. wie läuft das jetzt mit Transaktionen ab?
2.

```
private boolean isKundeChange() {
		bindingContext.updateModels();
		return kunde.eResource() == null ? true : kunde.eResource().isModified();
	}
```
ist immer false, muss ich das isModified selber auf true setzen???


EDIT: mit kunde.eResource().setTrackingModification(true); hab ich es auch schon probiert wird immer wieder auf false gesetzt...


----------



## Gast2 (29. Sep 2010)

Also die Funktionen werden wohl nicht unterstützt...

```
public class EclipseLinkResourceImpl extends ResourceImpl implements EclipseLinkResource {
	@Override
	public final boolean isTrackingModification() {
		return false;
	}

	@Override
	public final void setTrackingModification(boolean isTrackingModification) {
		// do nothing
	}

	@Override
	public boolean isModified() {
		return false;
	}

	@Override
	public void setModified(boolean isModified) {
		// do nothing
	}
```

Gibt es sonst noch Vorteile Resource zum Laden und Speichern zu benutzen? Weil die Änderungen wären für mich das einzigst interessante gewesen...

Weil für eigene Abfragen muss man von der Klasse erben und ein paar Methoden überschreiben.


----------



## Wildcard (29. Sep 2010)

EclipseLink ist ein Spezialfall, im Normalfall kannst du nur über eine Resource laden und speichern.
Die Änderungen mitzubekommen ist auch ohne Resource kein Problem, dafür kannst du den ContentAdapter verwenden.


----------



## Gast2 (29. Sep 2010)

Ja ich hätte Resourcen gerne genutzt, damit ich beim Standard bleibe, aber ich hab mir wie gesagt mal den src angeschaut und es ist brutal umständlich gescheite Abfragen zu generieren oder am besten selbst eine Klasse für die Abfragen zu machen die von der EclipseLinkResourceImpl erbt.

Okay wie kann kann ich die Änderungen mitbekommen un abfragen? Weil ich möchte ein Objekt natürlich nur speichern können, wenn es dirty ist, sowie im Eclipse Text Editor.


----------



## Wildcard (29. Sep 2010)

Editierst du innerhalb eines Editors? Wenn ja, häng dich doch an den Undo Stack. 
Etwas vereinfacht: Wenn keine Undos mehr auf dem Stack liegen ist deine Resource unverändert.


----------



## Gast2 (29. Sep 2010)

Ja ich hab einen Editor mit einem EMF Objekt welches ich über JFace-Databinding angebunden habe und nun weiß ich nicht wie ich die isDirty Methode gescheit implementiere:
Hab mir überlegt extra ein dirtyObjekt anzulegen und dass immer mit dem orginal zu verlgeichen und bei änderungen dann zu speichern. hat geklappt fand ich unsauber.
Hier vielleicht mal ein Bsp:

```
@Autowired
	private BaseService service;
	private Verwaltung verwaltung = VerwaltungFactory.eINSTANCE.createVerwaltung();
	private Text lastName;
	private EMFDataBindingContext m_bindingContext;


	public void createPartControl(Composite parent) {
		verwaltung = VerwaltungFactory.eINSTANCE.createVerwaltung();
		parent.setLayout(new GridLayout());
		lastName = new Text(parent, SWT.BORDER);
		lastName.setMessage("Name eingeben");
		bindValue();
	}

	private void bindValue() {
		m_bindingContext = new EMFDataBindingContext();
		lastName.addModifyListener(new ModifyListener() {
			
			@Override
			public void modifyText(ModifyEvent e) {
				firePropertyChange(PROP_DIRTY);
				
			}
		});
		m_bindingContext.bindValue(SWTObservables.observeText(lastName,SWT.Modify), EMFObservables.observeValue(verwaltung,
				VerwaltungPackage.Literals.VERWALTUNG__NAME), null, null);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		lastName.setFocus();
	}
	
	

	@Override
	public void doSave(IProgressMonitor monitor) {
		service.saveOrUpdate(verwaltung);
		firePropertyChange(PROP_DIRTY);
		
	}

	@Override
	public void doSaveAs() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean isDirty() {
		// 1. Versuch war verwaltung.eResource().isModified();
		// 2ter Versuch war !EcoreUtil.equals(verwaltung, dirtyObjekt);
		
		return true;
	}

	@Override
	public boolean isSaveAsAllowed() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isSaveOnCloseNeeded() {
		// TODO Auto-generated method stub
		return true;
	}
```


----------



## Wildcard (29. Sep 2010)

(Content)Adapter oder UndoStack, ich weiß nicht was ich sonst noch dazu sagen soll. EMF gibt dir die Werkzeuge an die Hand, du musst sie nur noch verwenden.


----------



## Gast2 (29. Sep 2010)

Hab ich den UndoStack und ContentAdapter nur wenn ich Resourcen verwende oder kann die auch ohne Resourcen verwenden.

Ich hab noch nie was mit EMF gemacht, deshalb hab ich auch grad kein plan wie man einen  ContentAdapter benutzt.


----------



## Wildcard (29. Sep 2010)

Hat nichts mit Resourcen zu tun. Mit Undo Stack meine ich die Undo Redo History deines Editors.
Ein ContentAdapter wird einfach als Adapter auf ein EObject gesetzt und über alle Changes in diesem Objekt und den Kindern des Objekts informiert.


----------



## Gast2 (29. Sep 2010)

Damit wir nicht aneinander vorbei reden. Du meinst schon diesen Adapter?

```
eObject.eAdapters().add(new EContentAdapter());
```


----------



## Wildcard (30. Sep 2010)

Ja. Allerdings musst du die notifyChanged Methode überschreiben, sonst tut der ContentAdapter nicht viel


----------



## Gast2 (30. Sep 2010)

Ja okay soweit war es mir klar.
Aber z.B. ich hab ein Textfeld in dem man den Namen eingeben kann. Ich lad das Objekt steht als Anfangwert: "Test" drin. So jetzt tipp ich was neues ein. Im notifyChange merk ich mir für das Objekt das es dirty ist. Jetzt macht der Benutzer die Eingabe rückgängig oder schreibt das gleiche rein. Dann wird das ja trotzdem als Änderung durchgehen.

Das mit dem UndoStack muss ich mir nochmal anschaun, hab mir aus dem CVS die Beispiele geholt aber sieht auf den ersten blick komplex aus.


----------

