Addressing Industrial Needs with the Fulib Modeling Library
Albert Zündorf, Adrian Kunz and Christoph Eickhoff
Kassel University, Germany
Keywords:
Models, Model Transformations, Modeling Tools.
Abstract:
Fulib is a new lightweight modeling tool providing code generation and model transformations. Code generated
by Fulib does not need a Fulib runtime library. Fulib has been designed to be integrated into agile software
development processes. Fulib collaborates with versioning tools like Git. These features address practical
problems with modeling tools that frequently prevent their usage in industry.
1 INTRODUCTION
The International Conference on Model Transforma-
tion (ICMT) October 2019 in Eindhoven had a panel
discussion on “Is there a future for Model Transforma-
tion Languages?”. Basically, they answered this ques-
tion with “No!” and terminated the ICMT conference
series. The main argument was that model transforma-
tions were not able to gain industrial relevance. The
main reasons given by the panel were: 1) proprietary
libraries, 2) licence issues, 3) vendor lock-in to (im-
mature) university prototypes, 4) poor integration with
iterative software development approaches. There is
also the paper of Paige and Varro (Paige and Varró,
2012) that discusses similar insights.
Following that panel and reading (Paige and Varró,
2012), we recognized: “Well, these are exactly the
issues that forced us to stop working on Fujaba (Nickel
et al., 2000) and SDMLib (Zündorf et al., 2013) and
to come up with Fulib”. Actually, we have started to
work on Fulib in August 2018 and the first official
release was in October 2019. Thus, this paper outlines
how our new lightweight modeling FUjaba Library
Fulib addresses the typical industrial concerns with
modeling tools.
2 NO FULIB RUNTIME LIBRARY
Within the model transformation community, the
Eclipse Modeling Framework (EMF) (Steinberg et al.,
2008) has become the de-facto standard for the im-
plementation of models. Besides being a common
standard for many modern modeling tools, EMF does
a great job in generating model implementations and
providing model management functionality like seri-
alization to XML, generic model viewers and editors,
etc. However, if your model e.g. has a class Order or
Product, then the generated Java classes will inherit
from the basic library class (interface) EObject. If
your model uses to-many associations, these will be
implemented using the library class EList. Thus, your
model code relies heavily on an EMF runtime library.
In order to use the generated model code within your
final product you have to include the EMF runtime
library and thus you have to deal with the according
licence. Generally, the EMF tooling and especially the
EMF runtime library are pretty mature and ready for
industrial use and the Eclipse Public Licence is pretty
general. Still this triggers the industrial concerns raised
by the ICMT panel discussed in our introduction.
To avoid these industrial concerns, the Java classes
generated by Fulib do not require any runtime li-
brary. Fulib does not use a common superclass or
interface like EObject and our associations are im-
plemented with standard Java container classes (de-
fault ArrayList). Additional model functionalities like
bidirectional associations are generated into the Java
classes. Instead of runtime libraries, Fulib relies on
generated code and on generic reflection functionality
. Thus, you may use Fulib to generate (parts of) your
model and when you ship your product, you do not
ship any Fulib libraries or parts and there are no Fulib
licences involved.
Zündorf, A., Kunz, A. and Eickhoff, C.
Addressing Industrial Needs with the Fulib Modeling Library.
DOI: 10.5220/0010203501550162
In Proceedings of the 9th International Conference on Model-Driven Engineering and Software Development (MODELSWARD 2021), pages 155-162
ISBN: 978-989-758-487-9
Copyright
c
2021 by SCITEPRESS Science and Technology Publications, Lda. All rights reserved
155
1 p u b l i c c l a s s GenModel implem ents Cla s s M o d e l D e c o r a t o r {
2 @Ov erride
3 p u b l i c v o i d d e c o r a t e ( Cl a s s Model M a n a g er mm) {
4 C l a z z sh o p = mm. h a v e C l a s s ( " Shop " , c > {
5 c . a t t r i b u t e ( " name " , STRING ) ;
6 } ) ;
7 C l a z z c u s t o m e r = mm. h a v e C l a s s ( " Cu s tom e r " , c > {
8 c . a t t r i b u t e ( " c u s t o m e r I d " , STRING ) ;
9 c . a t t r i b u t e ( " name " , STRING ) ;
10 c . a t t r i b u t e ( " a d d r e s s " , STRING ) ;
11 } ) ;
12 C l a z z p r o d u c t = mm. h a v e C l a s s ( " P r o d u c t " , c > {
13 c . a t t r i b u t e ( " p r o d u c t I d " , STRING ) ;
14 c . a t t r i b u t e ( " d e s c r i p t i o n " , STRING ) ;
15 c . a t t r i b u t e ( " p r i c e " , DOUBLE ) ;
16 } ) ;
17 C l a z z o r d e r = mm. h a v e C l a s s ( " O r d e r " , c > {
18 c . a t t r i b u t e ( " o r d e r I d " , STRING ) ;
19 c . a t t r i b u t e ( " d a t e " , STRING ) ;
20 } ) ;
21 mm. a s s o c i a t e ( shop , " c u s t o m e r s " , MANY, c u s t o m e r , " sh o p " , ONE ) ;
22 mm. a s s o c i a t e ( shop , " p r o d u c t s " , MANY, p r o d u c t , " sh o p " , ONE ) ;
23 mm. a s s o c i a t e ( cu s t om e r , " o r d e r s " , MANY, o r d e r , " c u s t o m e r " , ONE ) ;
24 mm. a s s o c i a t e ( o r d e r , " p r o d u c t s " , MANY, p r o d u c t , " o r d e r s " , MANY) ;
25 }
26 }
Listing 1: Fulib class model e.g. in src/gen/java/theModelPackage/GenModel.java.
1 p l u g i n s {
2 i d ’ j a v a
3 i d o r g . F u l i b . F u l i b G r a d l e
4 v e r s i o n ’ 0 . 2 . 0
5 }
Listing 2: Including the Fulib Gradle Plugin into
build.gradle.
3 FULIB LIGHTWEIGHT
TOOLING
A major problem with many modeling tools is, that
you have to learn some complex diagram tool, e.g.
MagicDraw (mag, 2020) or Microsoft Visio or Enter-
prise Architect (ent, 2020) or UML-Lab (UML, 2020)
or others. Recently, many textual modeling languages
have popped up e.g. based on xCore (xCo, 2020) or
(Rumpe and Hölldobler, 2017). These textual model-
ing languages still require you to use some complex
tool and to learn some new language. To avoid this,
Fulib encodes your class model in Java using a small
API, cf. Listing 1. Fulib then renders your class model
as UML diagram for you, cf. Figure 1. To be hon-
est, to use Fulib, you still have to learn the Fulib API.
However, you may stick with your favorite Integrated
Development Environment (IDE) and your IDE will
provide you with comfortable editing support like com-
pletion and compile time checks.
To use Fulib you may download the Fulib libraries
and add them to your classpath. However, we also
provide a Gradle plugin that does this job for you (a
Maven plugin is current work), cf. Listing 2.
The FulibGradle plugin provides a generateSce-
narioSource task. This task looks for ClassMod-
elDecorators within a dedicated src/gen/java/... sub-
directory and compiles and runs these classes. This
generates source code within your src/main/java/... di-
rectory. The generateScenarioSource task runs before
your usual compile and test tasks.
4 FULIB INTEGRATION WITH
ITERATIVE SOFTWARE
DEVELOPMENT
As discussed, our FulibGradle plugins keeps your
model and your source code in sync, on each gra-
dle build. This addresses the next main problem with
modeling tools in industrial projects: their poor inte-
MODELSWARD 2021 - 9th International Conference on Model-Driven Engineering and Software Development
156
1 p u b l i c c l a s s M o d e l s w a r d S t o r y T e s t {
2 @Test
3 p u b l i c v o i d t e s t P a y P a l ( ) {
4 Shop uks Sh op = new Shop ( ) . setName ( " UKSShop " ) ;
5 Cus t omer a l i c e = new Cu s t ome r ( ) . s e t C u s t o m e r I d ( " a l i c e 1 " )
6 . setName ( " A l i c e " ) . s e t A d d r e s s ( " W ond er land 1 " ) . s e t S h o p ( uksShop ) ;
7 Cus t omer bob = new Cus t o mer ( ) . s e t C u s t o m e r I d ( " bob2 " ) . setName ( " Bob " )
8 . s e t A d d r e s s ( " W ond er land 1 " ) . s e t S h o p ( uksShop ) ;
9 P r o d u c t t s h i r t = new P r o d u c t ( ) . s e t P r o d u c t I d ( " t 4 2 " ) . s e t P r i c e ( 1 3 . 3 7 )
10 . s e t D e s c r i p t i o n ( "UKS T s h i r t " ) . s e t S h o p ( uks Sh op ) ;
11 P r o d u c t mug = new P r o d u c t ( ) . s e t P r o d u c t I d ( "m43 " ) . s e t P r i c e ( 4 . 2 0 )
12 . s e t D e s c r i p t i o n ( "UKS C o f f e e Mug" ) . s e t S h o p ( uksShop ) ;
13 Or de r o44 = new O r de r ( ) . s e t O r d e r I d ( " o44 " ) . s e t C u s t o m e r ( a l i c e )
14 . s e t D a t e ( " 2 0 2 0 . 0 9 . 0 2 " ) . w i t h P r o d u c t s ( t s h i r t , mug ) ;
15
16 u ksShop . p r o c e s s ( o44 ) ;
17
18 F u l i b T o o l s . o b j e c t D i a g r a m s ( )
19 . dumpSVG ( " p a p e r / p a y p a l O b j e c t s . s vg " , uksShop ) ;
20 a s s e r t T h a t ( o44 . g e t S t a t e ( ) , i s ( " pa y ed " ) ) ;
21 }
22 }
Listing 3: Test Driven Development.
Shop
name :String
Customer
customerId :String
name :String
address :String
shop
customers *
Product
productId :String
description :String
price :double
shop
products *
Order
orderId :String
date :String
customer
orders *
products *
orders *
Figure 1: Example Class Diagram.
gration into iterative software development processes.
Frequently, modelling tools are used only in initial
project phases and as soon as you start to add your
business logic, code generation is detached and your
code develops independent from the model.
If you use an agile or iterative software develop-
ment approach you may follow the ideas of Test Driven
Design. Therefore, you start writing a test that sets up
a scenario for a certain functionality and then invokes
the corresponding operation and validates that the de-
sired effects have been achieved. We call such a test
a scenario test, cf. (Zündorf et al., 1999). Such sce-
nario tests may also be related to use cases. A typical
scenario test will set up some example object model
and then invoke some business logic operation and
than validate the results. Fulib has no generic model
editor to set up an example object model. Actually, we
have a simple textual scenario language you could use
(cf. www.fulib.org). This textual scenario language
may e.g. be used to discuss examples with customers
or users during requirements engineering. However,
this paper focuses on the design and implementation
phase. Thus during design and implementation, you
may just code the creation of example object models
based on the class model implementation generated by
Fulib, cf. Listing 3. Building a model via Java code
leverages code completion and editing support from
your integrated development environment. Note also
that our set-methods return the underlying object and
thus they may be used in a ‘fluid’ code style.
To visualize the created object model you may
use the FulibTools library, e.g. Line 19 of Listing 3
dumps an object diagram of our model, cf. Figure 2.
As you use this within your tests only, it will not ship
with your product, thus still no licence issues. We use
these object diagram dumps a lot during debugging,
too.
Note, our test already contains a business logic
method (Shop.process(order)), cf. Line 16 of Listing 3
and see Listing 4. Following the test driven develop-
Addressing Industrial Needs with the Fulib Modeling Library
157
uKSShop :Shop
name = "UKSShop"
alice :Customer
address = "Wonderland 1"
customerId = "alice1"
name = "Alice"
customers
shop
bob :Customer
address = "Wonderland 1"
customerId = "bob2"
name = "Bob"
customers
shop
p :Product
description = "Great UKS Tshirt"
price = 13.37
productId = "t42"
products
shop
p1 :Product
description = "UKS Coffee Mug"
price = 4.2
productId = "m43"
products
shop
o :Order
date = "2020.09.02"
orderId = "o44"
state = "initial"
orders
customer
orders
products
orders
products
Figure 2: Example Object Diagram.
ment idea, we first wrote the method call in Line 16
of Listing 3 and the assert statement in Line20. Then
we used auto repair features and code completion of
our IDE to create method Shop.process(order) and the
state attribute within our Order class. Then we used
gradle to compile and run our test. This gradle build
did another code generation. During this code genera-
tion, the Fulib code generator recognized the manual
extensions of our model classes and merged them with
the generated parts, seamlessly.
While you could / should add things like the state
attribute to the model, sometimes you do not consider
such helper elements as relevant for the model or you
are focusing on your algorithms and do not want to
bother with the modeling level. Or you just follow
the test driven development approach and want to start
with the usage of a feature before adding it to your
system (or model). Actually, we might add the state
attribute to our model after introducing it to our code
via IDE. Then, the Fulib code generator will identify
the manually added implementation and replace it with
the (similar) generated implementation. To achieve
this, Fulib uses a Java parser to identify attribute and
method declarations and then these declarations are
related to model elements via their names. After all,
code and model would by in sync and the manually
added attribute becomes part of the model, too.
As manual code extension is frequently required,
there are many sophisticated techniques that allow
developers to protect their code modifications and ex-
tensions from being overridden by some code gener-
ator, e.g. special code regions marked with pseudo
comments or adaption of generated code via sub and
super classes (e.g. in (Rumpe and Hölldobler, 2017)
or generation gap pattern by Fowler (Fowler, 2010)).
To make this even simpler and more seamless, Fulib
identifies which code elements (attributes / methods,
etc.) stem from or correspond to a model element (Ful,
2020b). Such code fragments will be overwritten on
each project build. Manual changes to such code frag-
ments will be lost. (You may protect such elements
with a // no Fulib comment.) Any code fragment
that has been added manually, e.g. a helper (state)
attribute or business logic method (process()) remains
untouched and is preserved during each project build.
Thus, if developers extend the generated code with at-
tributes or methods, they do not need to bother with the
Fulib model or code generation. In other approaches,
the extra effort for code preservation frequently causes
developers to detach the model from the code i.e. re-
move the automatic code generation from the build
process or just never run the code generation again.
With Fulib, the code generation is such seamless that
you may keep the Fulib Gradle plugin included.
When breaking down our example
Shop.process(order) method, cf. Listing 4, we
recognized that we need an email address for our
customers. This time we just extend the class model
code from Listing 1 and run gradle build. This adds
the email attribute to our model and to the generated
code, still well integrated with the manual extensions.
A great functionality of integrated development
environments are refactorings, e.g. renaming a class
or an attribute together with all its usages. Most code
generators have difficulties when you do e.g. such a
renaming on generated code. As an example let us
rename our Shop class into a Store. Using your IDE
this will also update your test code and other usages
of the old Shop class. If we run a gradle build after
renaming Shop to Store, the Fulib code generator will
regenerate the Shop class. This will also regenerate
the association between Shop and e.g. Product. This
results in numerous compile errors e.g. between the
regenerated method Product.setShop(Shop) and the old
MODELSWARD 2021 - 9th International Conference on Model-Driven Engineering and Software Development
158
1 p u b l i c c l a s s Shop {
2 p u b l i c v o i d p r o c e s s ( Or d e r o r d e r ) {
3 i f ( o r d e r . g e t S t a t e ( ) . e q u a l s ( " i n i t i a l " ) ) {
4 r e q u e s t P a y m e n t ( o r d e r ) ;
5 }
6 e l s e i f ( o r d e r . g e t S t a t e ( ) . e q u a l s ( " pa y ed " ) ) {
7 d e l i v e r ( o r d e r ) ;
8 }
9 }
10
11 p r i v a t e vo id r e q u e s t P a y m e n t ( O r d e r o r d e r ) {
12 . . .
13 }
14
15 p r i v a t e vo id d e l i v e r ( O r d er o r d e r ) {
16 . . .
17 }
18 . . .
19 }
Listing 4: Business Logic Development.
refactored method Product.setShop(Store) that both
access the Product.shop attribute which the Fulib code
generator has changed back to type Shop.
Luckily, the Fulib code generator is able to repair
this mess, easily. We just rename Shop to Store in our
class model code (Listing 1) and run the gradle build
again. The Fulib code generator keeps a copy of the
class model that has been used during the last code
generation. On each new code generation, the Fulib
code generator compares the old class model and the
new class model. Thus Fulib recognizes that the Shop
class is gone and that the corresponding associations
are now referencing the new Store class. Thus, Fulib
removes all code generated for the old Shop and the old
associations. Then, the new elements are generated.
During the generation of new elements, Fulib merges
the new code with existing code (from the refactoring).
Thus, once we have completed the renaming of Shop to
Store in our model, Fulib repairs all code and the code
compiles and works, again. A disciplined developer
might do the renaming in code and model directly and
no problem occurs. If you forget about the model, you
will recognize the problem on the next gradle build,
repair the model, and you are good, too.
In the best of all worlds, such a renaming would
work on code and model, simultaneously. As far as
we know, UML-Lab (UML, 2020) is the only mod-
eling tool that supports this. To achieve this, your
modeling tool needs to be tightly integrated with your
IDE (which provides the code refactoring function-
ality including manually created code that is not ad-
dressed by your modeling tool.) However, Fulib is just
a lightweight tool that is integrated into your develop-
ment workflow via gradle and that works with any IDE.
Thus, you have to do both renamings, manually. At
least Fulib deals with the problem that you may forget
to adapt the model, directly. This works not only for
the renaming of classes but also for the renaming of
attributes and associations. We have used Fulib in a
Bachelor course on object oriented modeling in winter
term 2019/2020 at Kassel University with about 80
students with great success and no student removed
the FulibGradle plugin from his or her project. We
use it a lot in our research projects, again with very
good experiences. Code generation and manual code
extension works great with Fulib.
5 FULIB GIT INTEGRATION
Another frequent reason for decoupling the model
from your code is when the model is not under Git
or version control together with your code. EMF class
models are usually stored in ECore files using XML
format. XML based files have serious problems when
e.g. a Git version control tool is used and merge con-
flicts occur. Fulib uses a Java based API to create a
class model and to generate the implementation code,
cf. Listing 1. This class model description (code) is
compiled and executed by the FulibGradle plugin dur-
ing the code generation phase and code is generated
within the src/main/java/... directory of your project.
As developers may extend the generated code man-
ually, we recommend to put the whole src directory
(including the generated code) under Git version con-
trol. As the class model description (code) is now
Addressing Industrial Needs with the Fulib Modeling Library
159
1 . . .
2 Cu s t o m e r T a b l e c u s t o m e r T a b l e = new C u s t o m e r T a b l e ( a l i c e ) ;
3 O r d e r T a b l e o r d e r T a b l e = c u s t o m e r T a b l e . e x p a n d O r d e r s ( " O rd e r " ) ;
4 o r d e r T a b l e . f i l t e r ( o r d e r > o r d e r . g e t S t a t e ( ) . e q u a l s ( " i n i t i a l " ) ) ;
5 P r o d u c t T a b l e p r o d u c t T a b l e = o r d e r T a b l e . e x p a n d P r o d u c t s ( " P r o d u c t " ) ;
6 d o u b l e T a b l e p r i c e T a b l e = p r o d u c t T a b l e . e x p a n d P r i c e ( " P r i c e " ) ;
7 Syste m . o u t . p r i n t l n ( p r o d u c t T a b l e ) ;
8 Syste m . o u t . p r i n t l n ( " T o t a l : " + p r i c e T a b l e . sum ( ) ) ;
9 /
*
p r i n t s :
10 | Cu sto m e r | Orde r | P r o d u c t | P r i c e |
11 | | | | |
12 | a l i c e 1 A l i c e Wo nd erl an d 1 | o44 2 0 2 0 . 0 9 . 0 2 | t 4 2 UKS T s h i r t | 1 3 . 3 7 |
13 | a l i c e 1 A l i c e Wo nd erl an d 1 | o44 2 0 2 0 . 0 9 . 0 2 | m43 UKS C o f f e e Mug | 4 . 2 |
14 T o t a l : 1 7 . 5 7
15
*
/
16 p r o d u c t T a b l e . t o S e t ( ) . f o r E a c h ( p r o d u c t > uksSh op . r e t r i e v e ( p r o d u c t ) ) ;
17 . . .
Listing 5: Fulib generated query API.
versioned together with all other code of your project,
you may use all Git features for collaborative software
development on your model and your code together.
You may e.g. use multiple feature branches to develop
different features independently. For each feature you
may extend and adapt the model description code and
the other code parts of your system and then you merge
the feature into your main development branch. Your
model description code will merge similar to all other
code.
6 MODEL QUERIES AND
TRANSFORMATIONS
In addition to code generation for class models, sup-
port for model queries and transformations is another
major contribution of modeling tools and frameworks.
Again, 1) proprietary libraries, 2) licence issues, 3)
vendor lock-in to (immature) university prototypes,
and 4) poor integration with iterative software devel-
opment are major concerns. In addition, a proprietary
query and transformation language adds to the com-
plexity of the overall development process.
Fulib provides different approaches in order to
deal with these problems. First, on demand, the
Fulib.tablesGenerator generates model specific query
operations. Listing 5 shows the usage of such gen-
erated tables based on the object structure created in
Listing 3.
For each model class like Customer, Fulib gen-
erates a corresponding table class, in this case Cus-
tomerTable. These table classes provide expand opera-
tions for each attached association e.g. expandOrders,
cf. Line 3 of Listing 5. Operation expandOrders cre-
ates a new wrapper object of type OrderTable that
refers to the original underlying table data. Operation
expandOrders takes each row of the original table (in
our case one row with one column with content alice1)
and computes the set of all objects reachable via an
orders link (in our case e.g. order o44). For each
combination of source and target object a new row is
added to the underlying table data. (The old rows are
removed.) The filter operation in line 4 of Listing 5
iterates through all rows of the underlying table and
applies the passed lambda expression on the element
of the current column (in our case on the order ele-
ment). In our example this evaluates to true and we
keep our single row. Now line 5 expands the current
order(s) via its (their) products link. This results in two
rows consisting of a copy of the old row extended by
one of the two ordered products. Line 6 adds a price
column for each product. Line 7 prints the resulting
table. This has been added to Listing 5 as comment in
lines 10 to 13. Line 8 calls sum on the price column
of our table and prints the result, cf. Line 14. If you
want to do not only a model query but also a model
transformation you may e.g run a lambda expression
on each element of a certain column, cf. line 16 of
Listing 5. Alternatively, you might iterate through all
rows of the underlying table. This allows you to access
e.g. customer, order, and product together.
The code generated for these table operations is
again self contained and does not need any runtime
library. The code only relies on the typical get opera-
tions. Thus, the generated table code works not only
with model classes generated by Fulib, but also with
model classes from other frameworks (e.g. EMF) or
manually crafted model classes.
MODELSWARD 2021 - 9th International Conference on Model-Driven Engineering and Software Development
160
1 . . .
2 P a t h T a b l e t a b l e = new P a t h T a b l e ( " Cu s tom e r " , a l i c e ) ;
3 t a b l e . e x p and ( " C u stom e r " , Cu s tom e r . PROPERTY_orders , " O r d e r " ) ;
4 t a b l e . f i l t e r ( " O rd e r " , o r d e r >(( O rd e r ) o r d e r ) . g e t S t a t e ( ) . e q u a l s ( " i n i t i a l " ) ) ;
5 t a b l e = t a b l e . e x pand ( " Ord e r " , Or d e r . PROPERTY_products , " P r o d u c t " ) ;
6 t a b l e . e x p and ( " P r o d u c t " , P r o d u c t . PROPERTY_price , " P r i c e " ) ;
7 Syste m . o u t . p r i n t l n ( t a b l e ) ;
8 Syste m . o u t . p r i n t l n ( " T o t a l : " + t a b l e . sum ( " P r i c e " ) ) ;
9 /
*
p r i n t s :
10 | Cu sto m e r | Orde r | P r o d u c t | P r i c e |
11 | | | | |
12 | a l i c e 1 A l i c e Wo nd erl an d 1 | o44 2 0 2 0 . 0 9 . 0 2 | t 4 2 UKS T s h i r t | 1 3 . 3 7 |
13 | a l i c e 1 A l i c e Wo nd erl an d 1 | o44 2 0 2 0 . 0 9 . 0 2 | m43 UKS C o f f e e Mug | 4 . 2 |
14 T o t a l : 1 7 . 5 7
15
*
/
16 t a b l e . t o S e t ( " P r o d u c t " ) . f o r E a c h ( p > uksSho p . r e t r i e v e ( ( P r o d u c t ) p ) ) ;
17 . . .
Listing 6: FulibTables runtime library query API.
1 . . .
2 P a t t e r n B u i l d e r pb = F u l i b T a b l e s . p a t t e r n B u i l d e r ( ) ;
3 P a t t e r n O b j e c t c u s t o m e r = pb . b u i l d P a t t e r n O b j e c t ( " c u s t o m e r " ) ;
4 P a t t e r n O b j e c t o r d e r = pb . b u i l d P a t t e r n O b j e c t ( " o r d e r " ) ;
5 P a t t e r n O b j e c t s t a t e = pb . b u i l d P a t t e r n O b j e c t ( " s t a t e " ) ;
6 P a t t e r n O b j e c t p r o d u c t = pb . b u i l d P a t t e r n O b j e c t ( " p r o d u c t " ) ;
7 P a t t e r n O b j e c t p r i c e = pb . b u i l d P a t t e r n O b j e c t ( " p r i c e " ) ;
8 pb . b u i l d P a t t e r n L i n k ( c u s t o m er , O r d e r . PROPERTY_customer ,
9 Cus t omer . PROPERTY_orders , o r d e r ) ;
10 pb . b u i l d P a t t e r n L i n k ( o r d e r , n u l l , " s t a t e " , s t a t e ) ;
11 pb . b u i l d A t t r i b u t e C o n s t r a i n t ( s t a t e , s t r > s t r . e q u a l s ( " i n i t i a l " ) ) ;
12 pb . b u i l d P a t t e r n L i n k ( o r d e r , P r o d u c t . PROPERTY_orders ,
13 Or de r . PROPERTY_products , p r o d u c t ) ;
14 pb . b u i l d P a t t e r n L i n k ( p r o d u c t , " p r i c e " , p r i c e ) ;
15 P a t t e r n M a t c h e r m a t c h e r = F u l i b T a b l e s . m a t c h e r ( pb . g e t P a t t e r n ( ) ) ;
16 O b j e c t T a b l e t a b l e = m a t c h e r . match ( " c u s t o m e r " , a l i c e ) ;
17 Syste m . o u t . p r i n t l n ( t a b l e ) ;
18 /
*
19 | c u s t o m e r | o r d e r | s t a t e | p r o d u c t | p r i c e
20 | | | | | |
21 | a l i c e 1 A l i c e | o44 2 0 2 0 . 0 9 . 0 2 | i n i t i a l | t 4 2 UKS T s h i r t | 1 3 . 3 7
22 | a l i c e 1 A l i c e | o44 2 0 2 0 . 0 9 . 0 2 | i n i t i a l | m43 UKS C o f f e e Mug | 4 . 2
23
*
/
Listing 7: FulibTables query pattern.
However, code generation for this model specific table
code relies on the existence of a Fulib class model (as
created e.g. in Listing 1). If you have created your
model (code) in a different way, you could reverse
engineer the class model for Fulib and then use only
the table generator. If you do not want to generate the
table code, Fulib also provides a generic PathTable
within a small runtime library (i.e. FulibTables).
Listing 6 shows the same query as Listing 5, but
this time using our generic PathTable. Thus, in List-
ing 6 we need to provide the names of table columns
and associations and attributes as string parameters.
This has three drawbacks: first, we loose static type
checking, you may accidentally ask a Customer ob-
ject to expand via link "xy" which is not possible as
the class Customer does not have such an associa-
tion. Correlated with missing type information is the
lack of auto completion support in your IDE. Finally,
PathTables rely on Java reflection. This is a little bit
slower than the generated solution. Again PathTable
Addressing Industrial Needs with the Fulib Modeling Library
161
works with Fulib models, EMF models, manually
crafted models, etc.
In addition to PathTables our FulibTables runtime
library also provides more general model queries via
object patterns, cf. Listing 7. These patterns are in-
spired by graph transformations, cf. (Zündorf et al.,
2017). Note, patterns are still compatible to all mod-
els that stick to the Java Beans conventions. Thus,
you may e.g. use our patterns on EMF models or on
manually crafted models.
In (Eickhoff et al., 2019) we also provide EMFeR
a generic model checking tool based on model queries
and model transformations. EMFeR works perfectly
well with Fulib queries and transformations, too.
7 SUMMARY
The Fulib modeling library tries to address typical
concerns and requirements of industrial software de-
velopers. You get a lot of Fulib functionality without
the need of a runtime library. Code generation is in-
tegrated into your Gradle build. Fulib supports itera-
tive software development as good as we can. Fulib
deals with Git version management reasonably well.
Model specific query functionality may be generated
which again avoids runtime libraries and licence is-
sues. Generic query functionality is provided within
a small runtime library (MIT licence). The generic
query functionality is agnostic to different model im-
plementations. It works not only for Fulib generated
code but also for code generated by other tools or for
manually crafted code. We have evaluated the Fulib
library within a modeling course with about 80 partici-
pants at Kassel University in winter term 2019/2020
and within several research projects at our department.
We are now ready to approach industrial partners to get
their feedback. We have already demonstrated Fulib
within a talk to local industry at the Java User Group
Hessia, Germany, in August 2020 (Ful, 2020a).
REFERENCES
(2020). Enterprise architect. https://www.sparxsystems.de/
uml/neweditions/. Accessed: 2020-09-02.
(2020a). Fulib - macht java code aus klassendi-
agrammen. https://www.youtube.com/watch?v=
eamdeXCxysk. Accessed: 2020-09-02.
(2020b). Fulib class org.fulib.generator. https://github.com/
fujaba/fulib. Accessed: 2020-02-12.
(2020). Magic draw. https://www.nomagic.com/products/
magicdraw. Accessed: 2020-09-02.
(2020). Uml-lab, yatta solutions gmbh. https://www.uml-lab.
com/de/uml-lab/. Accessed: 2020-09-02.
(2020). xcore. https://wiki.eclipse.org/Xcore. Accessed:
2020-09-02.
Eickhoff, C., Lange, M., Raesch, S.-L., and Zündorf, A.
(2019). Emfer: Model checking for object oriented
(emf) models. In MODELSWARD, pages 511–518.
Fowler, M. (2010). Domain-specific languages. Pearson
Education.
Nickel, U., Niere, J., and Zündorf, A. (2000). The fujaba
environment. In Proceedings of the 22nd international
conference on Software engineering, pages 742–745.
Paige, R. F. and Varró, D. (2012). Lessons learned from
building model-driven development tools. Software &
Systems Modeling, 11(4):527–539.
Rumpe, B. and Hölldobler, K. (2017). Monticore 5 language
workbench. edition 2017.
Steinberg, D., Budinsky, F., Merks, E., and Paternostro, M.
(2008). EMF: eclipse modeling framework. Pearson
Education.
Zündorf, A., Gebauer, D., and Reichmann, C. (2017). Table
graphs. In International Conference on Graph Trans-
formation, pages 221–230. Springer.
Zündorf, A., George, T., Lindel, S., and Norbisrath, U.
(2013). Story driven modeling libary (sdmlib): an
inline dsl for modeling and model transformations, the
petrinet-statechart case. Sixth Transformation Tool
Contest (TTC 2013), ser. EPTCS.
Zündorf, A., Schürr, A., and Winter, A. J. (1999). Story
driven modeling. Univ.-Gesamthochsch. Paderborn,
Fachbereich Mathematik-Informatik.
MODELSWARD 2021 - 9th International Conference on Model-Driven Engineering and Software Development
162