Commit 6ebb387b authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

More readme and other improvements

parent b136b904
# fb-example
Facebook model example
\ No newline at end of file
Facebook model example
## Introduction
This example shows the use of basic ecore features. So far it covers users and posts/shares, with comments/replies and likes.
## Use of ecore feature
### EClass
Most concepts are modelled as EClasses, e.g. User, Post, Comment etc. This is similar to how it would have been modelled using UML. The Like EClass would correspond to an Association class in UML, at it conceptually is an association with attached data (the kind of like).
The main use of inheritance is for gathering features (attributes and references) that are common to several classes in abstract superclasses. Thus, AbstractContent is the abstract superclass of Post and Comment, since both these have an author and can be liked. Similarly, the body of posts and comments have AbstractContentBody as common abstract superclass.
### EDataType
EDataTypes is Ecore's way of supporting the use of ordinary Java classes for value-like objects. Here we define EDateTypes for time-related classes. Ecore already includes EDate, but since Java now have new classes for dates, time and time of day, we define our own for ELocalDate (used for birthday) and ELocalDateTime (used for timestamp). The naming convention seems to be to prefix the java class with an E.
For each EDataType we must ensure that the logic in the generated factory implementation for converting to and from Strings (for serialization or data input) is correct. In our case we changed the `convert` and `create` methods to use standard DataTimeFormatter instances that can convert back and forth. And make sure to change `@generated` to `@generated NOT`, to avoid overwriting the changed code when regenerating the code.
### EEnum
EEnums are similar to Java enums and represents a (small) set of fixed symbolic values, that may have some natural order (or at least an associated numeral). Here we use it for kinds of likes. My naming convention is to use "Kind" as suffix.
### EStructuralFeatures
EAttributes and EReferences are features (subclasses of EStructuralFeature) with types that are EDataTypes and EClasses, respectively. The most important feature of features besides the name and type is the multiplicity. By setting the upper bound to a value >1 makes it many-valued, and -1 makes it unbounded.
### Constraints
Constraints are declared using EAnnotations (which are attached to any model element and carry custom key/value pairs that are processed by certain tools) and provide predicates that check for the validity of whole instances (or structures of them) or feature values. The predicate logic can be implemented in two main ways, either by generating code and filling in stubs for the declared constraints, or by providing the implementation in another EAnnotation with the source code in a interpreted language like OCL.
This model has two constraints implemented by either means. The `userNotAuthor` constraint is attached to the Like EClass and checks that a user doesn't like his/her own content. It is implemented in OCL attached to the same EClass. The `shareAuthorNotPostAuthor` constraint checks that a user doesn't share his/her own Posts. It is implemented in Java in the generated FbValidator subclass of EObjectValidator (implements constraints that are common to all instances).
### Derived features
Feature values can be derived (or computed) from other features, with custom logic. Usually such a feature is not changeable (no setter), transient (not serialized) and volatile (no field for storing it), instead the value is computed on demand, either by manually written code in the generated getter or by an interpreted expression. A changeable derived feature also needs setter logic.
Our model derives the name of a User from the givenName and familyName using java code in UserImpl.getName.
## Genmodel and EMF features
### Generated tests
Code that is completely generated from the model, need not be tested, but features like derived features and constraints implemented using interpreted or compiled java code needs tests.
The generated **tests** project contains test classes for each domain class with stub methods that **fail()** for cases EMF knows needs tests. E.g. our derived **User.name** feature has a test covering relevant cases.
### Specialized editor for fb instances
To create a custom editor for instances of our model, we set the **File Extension** for our model to `fb` (the default) and set the **Resource Type** to **XMI**. By generating **edit** and **editor** projects, we get a pretty generic editor specialized to and registered for our model and its `fb` file extension. Using the generated wizard, we can create and edit instances that can be validated using both interpreted code, e.g. OCL, and compiled java code. Also derived features implemented in java will be available.
......@@ -55,3 +55,5 @@ _UI_AbstractContent_author_feature = Author
_UI_AbstractContent_likes_feature = Likes
_UI_AbstractContent_timestamp_feature = Timestamp
_UI_Comment_replies_feature = Replies
_UI_AbstractContentBody_type = Abstract Content Body
_UI_AbstractContentBody_contents_feature = Contents
......@@ -22,16 +22,16 @@ import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.eclipse.emf.edit.provider.ViewerNotification;
import tdt4250.fb.AbstractBody;
import tdt4250.fb.AbstractContentBody;
import tdt4250.fb.FbPackage;
/**
* This is the item provider adapter for a {@link tdt4250.fb.AbstractBody} object.
* This is the item provider adapter for a {@link tdt4250.fb.AbstractContentBody} object.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public class AbstractBodyItemProvider
public class AbstractContentBodyItemProvider
extends ItemProviderAdapter
implements
IEditingDomainItemProvider,
......@@ -45,7 +45,7 @@ public class AbstractBodyItemProvider
* <!-- end-user-doc -->
* @generated
*/
public AbstractBodyItemProvider(AdapterFactory adapterFactory) {
public AbstractContentBodyItemProvider(AdapterFactory adapterFactory) {
super(adapterFactory);
}
......@@ -76,9 +76,9 @@ public class AbstractBodyItemProvider
(createItemPropertyDescriptor
(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
getResourceLocator(),
getString("_UI_AbstractBody_contents_feature"),
getString("_UI_PropertyDescriptor_description", "_UI_AbstractBody_contents_feature", "_UI_AbstractBody_type"),
FbPackage.Literals.ABSTRACT_BODY__CONTENTS,
getString("_UI_AbstractContentBody_contents_feature"),
getString("_UI_PropertyDescriptor_description", "_UI_AbstractContentBody_contents_feature", "_UI_AbstractContentBody_type"),
FbPackage.Literals.ABSTRACT_CONTENT_BODY__CONTENTS,
true,
false,
false,
......@@ -87,17 +87,6 @@ public class AbstractBodyItemProvider
null));
}
/**
* This returns AbstractBody.gif.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object getImage(Object object) {
return overlayImage(object, getResourceLocator().getImage("full/obj16/AbstractBody"));
}
/**
* This returns the label text for the adapted class.
* <!-- begin-user-doc -->
......@@ -106,10 +95,10 @@ public class AbstractBodyItemProvider
*/
@Override
public String getText(Object object) {
String label = ((AbstractBody)object).getContents();
String label = ((AbstractContentBody)object).getContents();
return label == null || label.length() == 0 ?
getString("_UI_AbstractBody_type") :
getString("_UI_AbstractBody_type") + " " + label;
getString("_UI_AbstractContentBody_type") :
getString("_UI_AbstractContentBody_type") + " " + label;
}
......@@ -124,8 +113,8 @@ public class AbstractBodyItemProvider
public void notifyChanged(Notification notification) {
updateChildren(notification);
switch (notification.getFeatureID(AbstractBody.class)) {
case FbPackage.ABSTRACT_BODY__CONTENTS:
switch (notification.getFeatureID(AbstractContentBody.class)) {
case FbPackage.ABSTRACT_CONTENT_BODY__CONTENTS:
fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
return;
}
......
......@@ -19,7 +19,7 @@ import tdt4250.fb.CommentBody;
* <!-- end-user-doc -->
* @generated
*/
public class CommentBodyItemProvider extends AbstractBodyItemProvider {
public class CommentBodyItemProvider extends AbstractContentBodyItemProvider {
/**
* This constructs an instance from a factory and a notifier.
* <!-- begin-user-doc -->
......
......@@ -232,29 +232,6 @@ public class FbItemProviderAdapterFactory extends FbAdapterFactory implements Co
return commentBodyItemProvider;
}
/**
* This keeps track of the one adapter used for all {@link tdt4250.fb.AbstractBody} instances.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected AbstractBodyItemProvider abstractBodyItemProvider;
/**
* This creates an adapter for a {@link tdt4250.fb.AbstractBody}.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Adapter createAbstractBodyAdapter() {
if (abstractBodyItemProvider == null) {
abstractBodyItemProvider = new AbstractBodyItemProvider(this);
}
return abstractBodyItemProvider;
}
/**
* This keeps track of the one adapter used for all {@link tdt4250.fb.Share} instances.
* <!-- begin-user-doc -->
......@@ -278,29 +255,6 @@ public class FbItemProviderAdapterFactory extends FbAdapterFactory implements Co
return shareItemProvider;
}
/**
* This keeps track of the one adapter used for all {@link tdt4250.fb.AbstractContent} instances.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected AbstractContentItemProvider abstractContentItemProvider;
/**
* This creates an adapter for a {@link tdt4250.fb.AbstractContent}.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Adapter createAbstractContentAdapter() {
if (abstractContentItemProvider == null) {
abstractContentItemProvider = new AbstractContentItemProvider(this);
}
return abstractContentItemProvider;
}
/**
* This returns the root adapter factory that contains this factory.
* <!-- begin-user-doc -->
......@@ -403,13 +357,11 @@ public class FbItemProviderAdapterFactory extends FbAdapterFactory implements Co
if (facebookItemProvider != null) facebookItemProvider.dispose();
if (userItemProvider != null) userItemProvider.dispose();
if (postItemProvider != null) postItemProvider.dispose();
if (postBodyItemProvider != null) postBodyItemProvider.dispose();
if (likeItemProvider != null) likeItemProvider.dispose();
if (commentItemProvider != null) commentItemProvider.dispose();
if (postBodyItemProvider != null) postBodyItemProvider.dispose();
if (commentBodyItemProvider != null) commentBodyItemProvider.dispose();
if (abstractBodyItemProvider != null) abstractBodyItemProvider.dispose();
if (likeItemProvider != null) likeItemProvider.dispose();
if (shareItemProvider != null) shareItemProvider.dispose();
if (abstractContentItemProvider != null) abstractContentItemProvider.dispose();
}
}
......@@ -19,7 +19,7 @@ import tdt4250.fb.PostBody;
* <!-- end-user-doc -->
* @generated
*/
public class PostBodyItemProvider extends AbstractBodyItemProvider {
public class PostBodyItemProvider extends AbstractContentBodyItemProvider {
/**
* This constructs an instance from a factory and a notifier.
* <!-- begin-user-doc -->
......
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=11
......@@ -4,86 +4,52 @@ package tdt4250.fb.tests;
import junit.framework.TestCase;
import junit.textui.TestRunner;
import tdt4250.fb.AbstractBody;
import tdt4250.fb.FbFactory;
import tdt4250.fb.AbstractContentBody;
/**
* <!-- begin-user-doc -->
* A test case for the model object '<em><b>Abstract Body</b></em>'.
* A test case for the model object '<em><b>Abstract Content Body</b></em>'.
* <!-- end-user-doc -->
* @generated
*/
public class AbstractBodyTest extends TestCase {
public abstract class AbstractContentBodyTest extends TestCase {
/**
* The fixture for this Abstract Body test case.
* The fixture for this Abstract Content Body test case.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected AbstractBody fixture = null;
protected AbstractContentBody fixture = null;
/**
* Constructs a new Abstract Content Body test case with the given name.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public static void main(String[] args) {
TestRunner.run(AbstractBodyTest.class);
}
/**
* Constructs a new Abstract Body test case with the given name.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public AbstractBodyTest(String name) {
public AbstractContentBodyTest(String name) {
super(name);
}
/**
* Sets the fixture for this Abstract Body test case.
* Sets the fixture for this Abstract Content Body test case.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected void setFixture(AbstractBody fixture) {
protected void setFixture(AbstractContentBody fixture) {
this.fixture = fixture;
}
/**
* Returns the fixture for this Abstract Body test case.
* Returns the fixture for this Abstract Content Body test case.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected AbstractBody getFixture() {
protected AbstractContentBody getFixture() {
return fixture;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see junit.framework.TestCase#setUp()
* @generated
*/
@Override
protected void setUp() throws Exception {
setFixture(FbFactory.eINSTANCE.createAbstractBody());
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see junit.framework.TestCase#tearDown()
* @generated
*/
@Override
protected void tearDown() throws Exception {
setFixture(null);
}
} //AbstractBodyTest
} //AbstractContentBodyTest
......@@ -3,11 +3,7 @@
package tdt4250.fb.tests;
import junit.framework.TestCase;
import junit.textui.TestRunner;
import tdt4250.fb.AbstractContent;
import tdt4250.fb.FbFactory;
/**
* <!-- begin-user-doc -->
......@@ -15,7 +11,7 @@ import tdt4250.fb.FbFactory;
* <!-- end-user-doc -->
* @generated
*/
public class AbstractContentTest extends TestCase {
public abstract class AbstractContentTest extends TestCase {
/**
* The fixture for this Abstract Content test case.
......@@ -25,15 +21,6 @@ public class AbstractContentTest extends TestCase {
*/
protected AbstractContent fixture = null;
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public static void main(String[] args) {
TestRunner.run(AbstractContentTest.class);
}
/**
* Constructs a new Abstract Content test case with the given name.
* <!-- begin-user-doc -->
......@@ -64,26 +51,4 @@ public class AbstractContentTest extends TestCase {
return fixture;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see junit.framework.TestCase#setUp()
* @generated
*/
@Override
protected void setUp() throws Exception {
setFixture(FbFactory.eINSTANCE.createAbstractContent());
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see junit.framework.TestCase#tearDown()
* @generated
*/
@Override
protected void tearDown() throws Exception {
setFixture(null);
}
} //AbstractContentTest
......@@ -13,7 +13,7 @@ import tdt4250.fb.FbFactory;
* <!-- end-user-doc -->
* @generated
*/
public class CommentBodyTest extends AbstractBodyTest {
public class CommentBodyTest extends AbstractContentBodyTest {
/**
* <!-- begin-user-doc -->
......
......@@ -13,7 +13,7 @@ import tdt4250.fb.PostBody;
* <!-- end-user-doc -->
* @generated
*/
public class PostBodyTest extends AbstractBodyTest {
public class PostBodyTest extends AbstractContentBodyTest {
/**
* <!-- begin-user-doc -->
......
......@@ -97,12 +97,17 @@ public class UserTest extends TestCase {
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see tdt4250.fb.User#getName()
* @generated
* @generated NOT
*/
public void testGetName() {
// TODO: implement this feature getter test method
// Ensure that you remove @generated or mark it @generated NOT
fail();
User user = getFixture();
assertEquals(null, user.getName());
user.setGivenName("Hallvard");
assertEquals("Hallvard", user.getName());
user.setFamilyName("Trætteberg");
assertEquals("Hallvard Trætteberg", user.getName());
user.setGivenName(null);
assertEquals("Trætteberg", user.getName());
}
} //UserTest
......@@ -9,6 +9,8 @@
<eStructuralFeatures xsi:type="ecore:EReference" name="users" upperBound="-1"
eType="#//User" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EDataType" name="ELocalDateTime" instanceClassName="java.time.LocalDateTime"/>
<eClassifiers xsi:type="ecore:EDataType" name="ELocalDate" instanceClassName="java.time.LocalDate"/>
<eClassifiers xsi:type="ecore:EClass" name="User">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="givenName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="familyName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
......@@ -18,19 +20,38 @@
<eStructuralFeatures xsi:type="ecore:EReference" name="posts" upperBound="-1"
eType="#//Post" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EDataType" name="ELocalDate" instanceClassName="java.time.LocalDate"/>
<eClassifiers xsi:type="ecore:EClass" name="AbstractContent" abstract="true">
<eStructuralFeatures xsi:type="ecore:EReference" name="author" lowerBound="1"
eType="#//User"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="likes" upperBound="-1"
eType="#//Like" containment="true" eOpposite="#//Like/content"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="timestamp" eType="#//ELocalDateTime"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Post" eSuperTypes="#//AbstractContent">
<eStructuralFeatures xsi:type="ecore:EReference" name="body" eType="#//PostBody"
containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="comments" upperBound="-1"
eType="#//Comment" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="PostBody" eSuperTypes="#//AbstractBody"/>
<eClassifiers xsi:type="ecore:EDataType" name="ELocalDateTime" instanceClassName="java.time.LocalDateTime"/>
<eClassifiers xsi:type="ecore:EClass" name="Comment" eSuperTypes="#//AbstractContent">
<eStructuralFeatures xsi:type="ecore:EReference" name="body" eType="#//CommentBody"
containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="replies" upperBound="-1"
eType="#//Comment" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="AbstractContentBody" abstract="true">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="contents" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="PostBody" eSuperTypes="#//AbstractContentBody"/>
<eClassifiers xsi:type="ecore:EClass" name="CommentBody" eSuperTypes="#//AbstractContentBody"/>
<eClassifiers xsi:type="ecore:EEnum" name="LikeKind">
<eLiterals name="like"/>
<eLiterals name="heart" value="1"/>
<eLiterals name="compasion" value="2"/>
<eLiterals name="compassion" value="2"/>
<eLiterals name="funny" value="3"/>
<eLiterals name="wow" value="4"/>
<eLiterals name="sad" value="5"/>
<eLiterals name="angry" value="6"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Like">
<eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
......@@ -44,27 +65,10 @@
<eStructuralFeatures xsi:type="ecore:EReference" name="content" eType="#//AbstractContent"
eOpposite="#//AbstractContent/likes"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Comment" eSuperTypes="#//AbstractContent">
<eStructuralFeatures xsi:type="ecore:EReference" name="body" eType="#//CommentBody"
containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="replies" upperBound="-1"
eType="#//Comment" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="CommentBody" eSuperTypes="#//AbstractBody"/>
<eClassifiers xsi:type="ecore:EClass" name="AbstractBody">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="contents" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Share" eSuperTypes="#//Post">
<eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
<details key="constraints" value="shareAuthorNotPostAuthor"/>
</eAnnotations>
<eStructuralFeatures xsi:type="ecore:EReference" name="original" eType="#//Post"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="AbstractContent">
<eStructuralFeatures xsi:type="ecore:EReference" name="author" lowerBound="1"
eType="#//User"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="likes" upperBound="-1"
eType="#//Like" containment="true" eOpposite="#//Like/content"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="timestamp" eType="#//ELocalDateTime"/>
</eClassifiers>
</ecore:EPackage>
......@@ -12,8 +12,8 @@
<genEnumLiterals ecoreEnumLiteral="fb.ecore#//LikeKind/heart"/>
<genEnumLiterals ecoreEnumLiteral="fb.ecore#//LikeKind/compasion"/>
</genEnums>
<genDataTypes ecoreDataType="fb.ecore#//ELocalDate"/>
<genDataTypes ecoreDataType="fb.ecore#//ELocalDateTime"/>
<genDataTypes ecoreDataType="fb.ecore#//ELocalDate"/>
<genClasses ecoreClass="fb.ecore#//Facebook">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference fb.ecore#//Facebook/users"/>
</genClasses>
......@@ -24,31 +24,31 @@
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute fb.ecore#//User/birthday"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference fb.ecore#//User/posts"/>
</genClasses>
<genClasses ecoreClass="fb.ecore#//AbstractContent">
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference fb.ecore#//AbstractContent/author"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference fb.ecore#//AbstractContent/likes"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute fb.ecore#//AbstractContent/timestamp"/>
</genClasses>
<genClasses ecoreClass="fb.ecore#//Post">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference fb.ecore#//Post/body"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference fb.ecore#//Post/comments"/>
</genClasses>
<genClasses ecoreClass="fb.ecore#//PostBody"/>
<genClasses ecoreClass="fb.ecore#//Like">
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference fb.ecore#//Like/user"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute fb.ecore#//Like/like"/>
<genFeatures property="None" notify="false" createChild="false" ecoreFeature="ecore:EReference fb.ecore#//Like/content"/>
</genClasses>
<genClasses ecoreClass="fb.ecore#//Comment">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference fb.ecore#//Comment/body"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference fb.ecore#//Comment/replies"/>
</genClasses>
<genClasses image="false" ecoreClass="fb.ecore#//AbstractContentBody">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute fb.ecore#//AbstractContentBody/contents"/>
</genClasses>
<genClasses ecoreClass="fb.ecore#//PostBody"/>
<genClasses ecoreClass="fb.ecore#//CommentBody"/>
<genClasses ecoreClass="fb.ecore#//AbstractBody">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute fb.ecore#//AbstractBody/contents"/>
<genClasses ecoreClass="fb.ecore#//Like">
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference fb.ecore#//Like/user"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute fb.ecore#//Like/like"/>
<genFeatures property="None" notify="false" createChild="false" ecoreFeature="ecore:EReference fb.ecore#//Like/content"/>
</genClasses>
<genClasses ecoreClass="fb.ecore#//Share">
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference fb.ecore#//Share/original"/>
</genClasses>
<genClasses ecoreClass="fb.ecore#//AbstractContent">
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference fb.ecore#//AbstractContent/author"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference fb.ecore#//AbstractContent/likes"/>
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute fb.ecore#//AbstractContent/timestamp"/>
</genClasses>
</genPackages>
</genmodel:GenModel>
......@@ -23,7 +23,7 @@ import org.eclipse.emf.ecore.EObject;
* </ul>
*