OSGi Community Event 2014
Abstract:
The main topic of the session is the content of the blog post Modularized Persistence: Development of reusable modules that handle relational persistent data.
Additional subjects of the session
Reasons why we chose this technology stack instead of JEE
Transaction handling with the transaction-helper component (without EJB or Spring)
Caching the persistent data based on everit-cache-api
More details about the already implemented use-cases (localization, authorization, authentication, etc.)
During the session, there will be live examples of:
Code generation of Querydsl Metadata classes (same as static metamodel in JPA)
Converting a standard query to one that contains authorization logic
Speaker's goal
Introducing our modules to others so they can:
use them as they are
start discussions about improvements so others can use them in the future
Speaker Bio:
Balazs Zsoldos is the co-founder of Everit. He is the leader of the development of Everit OpenSource Components. Developing Java based solutions is not only his job but also his passion.
He believes in simplicity. That is why he decided to design and build as many simple, but useful goal-oriented modules as he can. As the base of the stack, he chose OSGi.
Balazs does not believe in monoholitic frameworks, therefore all of the solutions that was designed by him can be used separately.
In the beginning of his career, Balazs was a big fan of JEE and Spring. After a while, he changed his mind and started to try replacing everything with non-magical solutions that do not contain interceptors, weaving, etc.
25. Write Liquibase changelog
Write LQMG file
Add LQMG to the Capability
Add inclusions
Generate Querydsl Metadata
26. LQMG
Start embedded
OSGi container
Deploy modules
Start embedded
H2 database
Initialize database
schema
Generate Querydsl
Metadata
Evil magic here!!!
If Capability is not found after
deployments, unsatisfied
bundles are enhanced in the
way that unsatisfied
requirements are marked to be
optional.
33. SELECT ...
FROM document d
JOIN document.attachment a
WHERE …
LIMIT 10 OFFSET 1000;
EXISTS(SELECT 1 FROM permission p
WHERE p.authorized_resource_id IN (?, …, ?)
AND p.target_resource_id = d.resource_id
AND action = ?)
SELECT ...
FROM document d
JOIN document.attachment a
WHERE EXISTS(SELECT 1 FROM permission p
WHERE p.authorized_resource_id IN (?, …, ?)
AND p.target_resource_id = d.resource_id
AND action = ?)
AND …
LIMIT 10 OFFSET 1000;
34. @Override
public BooleanExpression authorizationPredicate(final long authorizedResourceId,
final Expression<Long> targetResourceId, final String... actions) {
if (authorizedResourceId == systemResourceId) {
return BooleanTemplate.TRUE;
}
Objects.requireNonNull(targetResourceId, "Parameter targetResourceId must not be null");
validateActionsParameter(actions);
long[] authorizationScope = getAuthorizationScope(authorizedResourceId);
SQLSubQuery subQuery = new SQLSubQuery();
QPermission permission = QPermission.permission;
BooleanExpression authorizedResourceIdPredicate;
if (authorizationScope.length == 1) {
authorizedResourceIdPredicate = permission.authorizedResourceId.eq(authorizationScope[0]);
} else {
// More than one as the scope contains at least one value (other branch)
Long[] authorizationScopeLongArray = new Long[authorizationScope.length];
for (int i = 0, n = authorizationScope.length; i < n; i++) {
if (authorizationScope[i] == systemResourceId) {
return BooleanTemplate.TRUE;
}
authorizationScopeLongArray[i] = authorizationScope[i];
}
authorizedResourceIdPredicate = permission.authorizedResourceId.in(authorizationScopeLongArray);
}
BooleanExpression actionPredicate = null;
if (actions.length == 1) {
actionPredicate = permission.action.eq(actions[0]);
} else {
actionPredicate = permission.action.in(actions);
}
return subQuery.from(permission)
.where(permission.targetResourceId.eq(targetResourceId).and(
actionPredicate.and(authorizedResourceIdPredicate)))
.exists();
}
35. SQLQuery query = new SQLQuery(connection, configuration);
QDocument document = new QDocument("d");
BooleanExpression permissionCheckPredicate = authorizationQdslUtil
.authorizationPredicate(userId, document.resourceId, actions);
List<Long> list = query.from(document).where(permissionCheckPredicate)
.list(document.documentId);
36. Business Component Business Component Business Component
Querydsl Querydsl Querydsl
Liquibase DataSource Component
(DataSource)
DBCP Component
(DataSource)
DSF Component
(XADataSource)
JDBC Driver
(DataSourceFactory)
QuerydslSupport
Querydsl
Configuration
Querydsl
SQLTemplates
38. Business Component Business Component Business Component
Querydsl Querydsl Querydsl
Liquibase DataSource Component
(DataSource)
DBCP Component
(DataSource)
DSF Component
(XADataSource)
JDBC Driver
(DataSourceFactory)
QuerydslSupport
Querydsl
Configuration
Querydsl
SQLTemplates
Transaction Helper
39. public long saveUser(String firstName, String lastName) {
Objects.requireNonNull(firstName);
Objects.requireNonNull(lastName);
return transactionHelper.required(() -> {
// Logic that should be implemented
return 0l;
});
}
40. Caching
● Available Cache modules: cache-api, cache-infinispan,
cache-noop
● Caching should be done in the persistent module
by the programmer, who knows the business logic
● Caching and table updates should be done within
the same component
● In case bulk update is done in another module,
cache must be cleared
49. Full Text Search
● Analize the different solutions
– H2 → Lucene
– MySQL → Sphinx
– PostgreSQL → TSearch2
– SQL Server →???
– Oracle → Oracle Text
● Create a common API for Querydsl based query
extension
● Create a module for each database engine