Part 2 : Create Annotation Model
— — No ABAP development skills required — —
Part 1: Preparation
* Quick-View on Prerequisites
* Service-Oriented View
Part 2: Create the Annotation Model (this blog)
* Create Project
* Reference the Gateway Service
* Reference the vocabulary
* Create the Annotation Model
* Runtime Artifacts
Part 3: Explore the Annotation Model
Part 4: Connect the Cloud
* SAP HANA Cloud Connector
** Configure 1
** Configure 2
** Access HCP trial
** Tip: Avoid SSO
Part 5: OData provisioning
* Find it
* Configure it
** Assign Roles
** Create Destination
* Register Service
Part 6: The Fiori Application
* Create destination pointing to OData provisioning in HCP
* Generate application
* Run the application
Part 7: Trouble-Tips
This is the second part of our tutorial. After choosing a Gateway service in the first part, we’ll be creating the annotation model in this blog.
Basically, following the SAP Gateway development paradigm, the annotation model is defined in an ABAP class, the AnnotationProviderClass.
Creating and maintaining that class is easy, because the Service Builder tool provides the necessary support (see Links section for more info).
In the following sections, we’re going to create a project, import service and vocabulary, create annotations, generate the ABAP class / runtime artifacts, finally view the annotation model.
We are here:
Change to your SAP system and open a new window via the main menu:
System -> Create Session
Open Service Builder tool with transaction SEGW (or /n/SEGW).
Create a new Project via the main menu
Project -> Create
Enter project name and description and choose the third entry as project type: Annotation Model for Referenced Service
Finally press Local Object to create the project.
Reference the Gateway service
We want to define annotations which are bound to EntityTypes and Properties of an existing OData service.
As such, in our project we need to have the knowledge about the exact metadata of that service (e.g. the EntityType names etc).
How do we get the knowledge?
-> we “import” the service.
Don’t worry: there’s no risk of modifying that service 😉
It is only a reference.
In your project, select the subnode
ZGWSAMPLE_ANNOTATIONS -> Data Model
and from the context menu choose
Import -> Service Reference
In the Wizard open the value help.
From the value help, choose /IWBEP/GWSAMPLE_BASIC,
and click the green tick to confirm the selection.
Back in the wizard, press “Next”.
The second wizard page allows to view the model (the metadata) of the selected service.
Finally click “Finish”.
After successful import, a green message is displayed in the message area of Service Builder.
The metadata of the service can be viewed (again) in the project explorer tree of the Service Builder.
Reference the vocabulary
We’ve said that we’re going to “create” annotations. This is not totally true…
In our example, the annotations themselves do exist, they are pre-defined and we can use them for binding them to properties of the service.
So we’re using existing annotations when we create the annotation model.
You’ll understand after going through this section.
The UI annotations that we want to use are defined in a so-called “vocabulary”. We can think of it as a kind of xml-schema, or simply a collection of predefined elements.
We’re using the predefined UI vocabulary, because this one is understood by the UI5 runtime.
(Apart from that, self-defined vocabularies could be used as well.)
The Service Builder allows to view the predefined vocabularies via the menu entry:
Extras -> Vocabulary Repository
At this point, a screenshot would be expected … 😉 … but we skip it because the same will be shown in the following step:
Select the subnode
ZGWSAMPLE_ANNOTATIONS -> Data Model
and from the context menu choose
Import -> Vocabulary
In the “Import Vocabularies” dialog, select the “UI” – vocabulary line
(yes, you have to highlight the whole line)
and press the green tick.
After import, a green success message is briefly displayed in the status line.
The imported vocabulary can be viewed in the project explorer tree of the Service Builder.
The imported vocabulary depends on other vocabularies, which themselves can depend on others; all those recursive dependencies have been imported implicitly.
Let’s have a quick view.
Expand the node “Terms” and double-click on “Line Item”
The table on the right side shows some details about this term:
What does that tell me?
The term “LineItem” can be used to annotate an EntityType. It consists of “DataFields”.
The UI5 docu describes the smart template “List Report Table” and one of the annotations used for it is the “LineItem”
A single-click on the “DataFieldAbstract” takes us to the definition of that type:
it defines a “Label”.
It has a subtype “DataField” which inherits the “Label” and additionally defines a “Value”.
This “Value” will at the end of the day carry the data from the backend, delivered by the Gateway service.
Whereas the “Label” will carry a hard-coded string, defined by us.
The property “Label” is an “Edm.String” whereas the property “Value” is an “Edm.PrimitiveType”
You can export the vocabulary (via the main menu, Extras -> Vocab Repo -> Choose -> Download), then view the exported xml file. There you can see the definition of the DataField, which extends the DataFieldAbstract:
In case you don’t see the property “Value”, please stay calm…
The reason is probably that your Service Builder has an older version which didn’t support the data type (Edm.PrimitiveType) of the property.
In that case please refer to SAP Note 2323443
Create the annotation model
After doing the 2 preparation steps, we’re ready for the actual work: define the annotation model.
What we want to do:
1. Choose the relevant properties from the referenced service
2. Choose the desired annotations from the referenced UI vocabulary
Like that, we decide which properties are displayed (1), and how they are displayed (2)
To avoid confusion, we’ll keep the annotation model that we’re going to create, as simple as possible.
So now we have to think about the UI of the application that we want to have at the very end of this tutorial.
… think about …
The app should display a table which contains a list of sales orders and the table should have 2 columns with the ID and a note.
In our imagination, we start dreaming of the table…
…each row has 2 cells,
…the first contains a stupid number (the sales order ID),
…the second a silly text (the note which was entered when the sales order was created)
…all these rows and cells are filled with values that are delivered by the OData service
…But the table itself has also a header row, with a title for each column.
…These 2 titles are static, we can write any text that we personally like.
Since in this part of our tutorial we’re acting as backend-developer, we feel proud to do the work that usually is done by the frontend-developer (define the UI)…
Let’s not only talk about the work – let’s do it…
Choose the EntityType of the referenced service.
In the project explorer tree of the Service Builder, navigate to the subnode
ZGWSAMPLE_ANNOTATIONS -> Data Model -> Entity Types
Double click it.
In the right pane, the editor is opened, displaying a list of the EntityTypes defined in the service.
That’s fine, but what we want to do is to maintain annotations.
So let’s switch:
in the toolbar of the Entity Types editor, there’s a button “Annotations”.
It is a drop-down, because there might be multiple (imported) vocabularies
Click the arrow to display the list of imported vocabularies:
In our case, there’s only one. Click it.
The editor for vocabularies opens.
our goal is that at the end of the tutorial, the sales orders are listed in a table.
the way to achieve it is to combine the concrete EntityType and the suitable Annotation.
So what we have to do now is to find the SalesOrder (EntityType) and to find the LineItem (Annotation).
And then mark the cell.
The screenshot shows it:
Then we have to click the button “Create Annotation” as shown in below screenshot.
After clicking, we have annotated the EntityType SalesOrder with an annotation that is a collection (it is marked with a collection-icon), and the collection consists of DataFields (as shown by the tooltip).
Aha, it is a collection…
For us, that means that our work is not yet finished.
We have to fill the collection.
So the “Adventure of Unknown User Interface” continues… (wow, this could have been a nice title for a blog…)
OK, after the last click, the cell (marked with collection-icon) is still selected.
If not, select it.
Underneath the editor, a new pane is shown, which is used to further define the selected annotation:
The collection is empty and wants to be filled with “DataFields”
To do so, select the “Collection” node, then click the “Append Row” button:
The row is created and appended.
Now click the value help in the “Type” cell in order to open the selection dialog.
In the previous section, we’ve seen that the term “LineItem” declares the type “DataFieldAbstract”. That’s the reason why we now get a list of types to choose.
We choose the “DataField”, then press the green tick.
The type is entered, now we have to specify the value for this type. The cell is empty, no value help.
This is an adventure, so let’s just try a double-click…
Double-click in the empty “Value”-cell.
In this moment, the schema is parsed. We now remember that the DataField type has the inherited and the own properties.
Both can be maintained now.
The “Label” – property is a constant for us, we type the text that should be displayed as column header in the future application.
I suggest to type a text that will clearly identify us, as a human text writer,
“The Sales Order ID (nobody reads it …)”
The “Value” – property is more interesting: the value comes from the backend, the Gateway service brings it and stores it in a property.
So here we enter the name of the property of the referenced service. The Entity Type was already chosen above, so now we type the name of the property of the Entity Type.
We have to make sure that it is correctly spelled, so we have to check the metadata of the service.
We have it in our Service Builder project. It is in the tree:
Make sure to type it correctly… otherwise, this adventure becomes a horror-trip…
why is it name as “Path” in the tool?
Most probably, because the property can be part of a ComplexType which itself can be nested in another ComplexType.
This is how it looks like:
We could stop here, but a table with only one column looks a bit strange, so we repeat the steps to add a second DataField to the Collection, this time for the property “Note”:
So again, select the “Collection” node, append a row.
Choose the “DataField” type, double-click into the empty cell, enter a Label (e.g. “The stupid note”), enter a “Value” which is the name of a property.
In this case type “Note”. The name can be checked in the tree, just like before.
We’re done, we have created the annotation model.
Later, we’ll see the model in its full beauty, as xml-structure.
Until now, we’ve only clicked around in the tool.
It was fun, but it doesn’t help anybody… because, at the end, what counts is: ABAP … !
(Hey, remember the advertisement…)
Don’t worry, in our example, as promised, we don’t really care about the ABAP code.
We let the Service Builder tool generate the ABAP classes and implementation for us.
Wow, from now on we even start loving this tool…
The magic “Generate”-button looks like a soccer ball and can be found in the main toolbar of Service Builder:
Pressing it will automatically do a “Save” of the project.
Which doesn’t mean that we shouldn’t “Save” from time to time manually
(should I have mentioned that earlier…?)
After pressing the “Generate” button, a dialog is displayed, informing us about what is going to be generated:
Pouh – I cannot explain everything here… just a little background info:
Base Class: the Annotation Provider class (…APC) which will be invoked by the SAP Gateway framework
Class: the extension class (…APC_EXT), used by experienced ABAP-cracks to write own code
Annotation Model Registration: in addition, a model-artifact is generated.
It has a “Technical Model Name” (you’ll remember it, as you’ll see it later on) and a Description, which is rarely read.
A Namespace can be defined as well, cool.
Since we are not experienced, we better don’t touch any of the proposed names, just press the green tick to start the generation, which still doesn’t start, as we have to press “Local Object”
Finally the generation happens and we see the success message in the status line (as usual in the ABAP world) and an interesting list of success messages in the “Messages” pane
The last entry tells us that the annotation model not only has been created and registered, but also the service which we’ve referenced, has been assigned to our model. This is a separate step.
If we want, we can manually assign or remove services to our annotation model. We can even assign multiple services to our annotation model (if it makes sense)
This step can be viewed or maintained in the transaction /IWBEP/REG_VOCAN
Actually, we’re done with the task “Create Annotation Model”.
However, if you’re curious, and if you do like to see the ABAP class and the annotation model maintenance, proceed to the next part or our tutorial.
Otherwise, you can directly jump to part 4
— — Stay tuned and you’ll be lucky — —