| /////////////////////////////////////////////////////////////// |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| /////////////////////////////////////////////////////////////// |
| |
| [[thirty-minutes-intro,Zest™ in 30 minutes]] |
| = Zest™ in 30 minutes = |
| |
| TIP: Theses tutorials are based on actual code found in the `tutorials/` directory of the |
| https://zest.apache.org/download.html[Zest™ SDK sources]. You should start your favorite editor and find the code related to |
| this tutorial, run it and play with it. |
| |
| |
| This introduction will deepen your understanding of Zest™, as we touches on a couple of the common features of Zest™. It |
| is expected that you have gone through and understood the "Zest™ in 10 minutes" introduction. |
| |
| If you want to reproduce what's explained in this tutorial, remember to depend on the Core Runtime artifact that depends |
| on Core API, Core SPI, Core Bootstrap and Core Functional & I/O APIs: |
| |
| include::../../../../../core/runtime/build/docs/buildinfo/artifact.txt[] |
| |
| Moreover, you'll need an EntityStore for persistence and an Indexing engine for querying. Choose among the available |
| implementations listed in the <<extensions>> section. |
| |
| See the <<howto-depend-on-zest>> tutorial for details. |
| |
| We will go back to the OrderEntity example; |
| [snippet,java] |
| ----------- |
| source=tutorials/introduction/tenminutes/src/main/java/org/qi4j/demo/tenminute/OrderEntity.java |
| tag=mainClass |
| ----------- |
| |
| Let's say that this is an existing Composite, perhaps found in a library or used in a previous object, but we want to |
| add that it tracks all the changes to the order and the confirmation of such order. |
| |
| First we need to create (or also find in a library) the mechanics of the audit trail. It could be something like this; |
| |
| [snippet,java] |
| ----------- |
| source=tutorials/introduction/thirtyminutes/src/main/java/org/qi4j/demo/thirtyminutes/ThirtyMinutesDocs.java |
| tag=2 |
| ----------- |
| |
| Quite a lot of Zest™ features are leveraged above; |
| [1] Property is a first class citizen in Zest™, instead of getters/setters naming convention to declare properties. |
| [2] ValueComposite for Action means that it is among other things Immutable. |
| [3] The Action extends a Property. We call that Property subtyping and highly recommended. |
| [4] The CompositeBuilder creates Immutable Action instances. |
| |
| We also need a Concern to hang into the methods of the Order interface. |
| |
| [snippet,java] |
| ----------- |
| source=tutorials/introduction/thirtyminutes/src/main/java/org/qi4j/demo/thirtyminutes/ThirtyMinutesDocs.java |
| tag=3 |
| ----------- |
| |
| In this case, we have chosen to make an Order specific Concern for the more generic AuditTrail subsystem, and would |
| belong in the client (Order) code and not with the library (AuditTrail). |
| Pay attention to the @This annotation for a type that is not present in the Composite type interface. This is called a |
| private Mixin, meaning the Mixin is only reachable from Fragments within the same Composite instance. |
| |
| But the AuditTrail subsystem could provide a Generic Concern, that operates on a naming pattern (for instance). In this |
| case, we would move the coding of the concern from the application developer to the library developer, again increasing |
| the re-use value. It could look like this; |
| |
| [snippet,java] |
| ----------- |
| source=tutorials/introduction/thirtyminutes/src/main/java/org/qi4j/demo/thirtyminutes/ThirtyMinutesDocs.java |
| tag=4 |
| ----------- |
| |
| The above construct is called a Generic Concern, since it implements java.lang.reflect.InvocationHandler instead of the |
| interface of the domain model. The ConcernOf baseclass will also need to be of InvocationHandler type, and the |
| Zest™ Runtime will handle the chaining between domain model style and this generic style of interceptor call chain. |
| |
| Finally, we need to declare the Concern in the OrderEntity; |
| |
| [snippet,java] |
| ----------- |
| source=tutorials/introduction/thirtyminutes/src/main/java/org/qi4j/demo/thirtyminutes/ThirtyMinutesDocs.java |
| tag=5 |
| ----------- |
| |
| We also place it first, so that the AuditTrailConcern will be the first Concern in the interceptor chain |
| (a.k.a InvocationStack), so that in case any of the other Concerns throws an Exception, the AuditTrail is not updated |
| (In fact, the AuditTrail should perhaps be a SideEffect rather than a Concern. It is largely depending on how we define |
| SideEffect, since the side effect in this case is within the composite instance it is a border case.). |
| |
| So let's move on to something more complicated. As we have mentioned, EntityComposite is automatically persisted to an |
| underlying store (provided the Runtime is setup with one at bootstrap initialization), but how do I locate an Order? |
| |
| Glad you asked. It is done via the Query API. It is important to understand that Indexing and Query are separated from |
| the persistence concern of storage and retrieval. This enables many performance optimization opportunities as well as a |
| more flexible Indexing strategy. The other thing to understand is that the Query API is using the domain model, in Java, |
| and not some String based query language. We have made this choice to ensure refactoring safety. In rare cases, the |
| Query API is not capable enough, in which case Zest™ still provides the ability to look up and execute native queries. |
| |
| Let's say that we want to find a particular Order from its SequenceNumber. |
| |
| [snippet,java] |
| ----------- |
| source=tutorials/introduction/thirtyminutes/src/main/java/org/qi4j/demo/thirtyminutes/ThirtyMinutesDocs.java |
| tag=6 |
| ----------- |
| |
| The important bits are; |
| |
| * The QueryExpressions.templateFor() method is used to define the template used in the query upon execution. In |
| this case, we choose to template only the HasSequenceNumber, an interface used in OrderEntity, but is not part of |
| Order (may or may not be a good design choice). |
| |
| * The where() clause, which has a statically imported method eq(), which builds up the expression logic, and will |
| be translated into the underlying query language upon execution, which happens in the iterator() method. |
| |
| Another example, |
| |
| [snippet,java] |
| ----------- |
| source=tutorials/introduction/thirtyminutes/src/main/java/org/qi4j/demo/thirtyminutes/ThirtyMinutesDocs.java |
| tag=7 |
| ----------- |
| |
| In the above case, we find the Orders that has been created in the last 90 days, and add them to a report to be |
| generated. This example assumes that the Order type has a Property<Date> createdDate() method. |
| |
| Now, Orders has a relation to the CustomerComposite which is also an Entity. Let's create a query for all customers |
| that has made an Order in the last 30 days; |
| |
| [snippet,java] |
| ----------- |
| source=tutorials/introduction/thirtyminutes/src/main/java/org/qi4j/demo/thirtyminutes/ThirtyMinutesDocs.java |
| tag=8 |
| ----------- |
| |
| This covers the most basic Query capabilities and how to use it. For Querying to work, an Indexing subsystem must be |
| assembled during bootstrap. At the time of this writing, only an RDF indexing subsystem exist, and is added most easily |
| by assembly.addAssembler( new RdfNativeSesameStoreAssembler() ). |
| |
| It can be a bit confusing to see Zest™ use Java itself as a Query language, but since we have practically killed the |
| classes and only operate with interfaces, it is possible to do a lot of seemingly magic stuff. Just keep in mind that |
| it is pure Java, albeit heavy use of dynamic proxies to capture the intent of the query. |
| |
| == Conclusion == |
| |
| We have now explored a couple more intricate features of Zest™, hopefully without being overwhelmed with details on how |
| to create applications from scratch, how to structure applications, and how the entire Zest™ Extension system works. |
| We have looked at how to add a Concern that uses a private Mixin, we have touched a bit on Generic Concerns, and |
| finally a short introduction to the Query API. |