modularized persistence - b zsoldos

50
Balázs Zsoldos Modularized Persistence

Upload: mfrancis

Post on 04-Jul-2015

159 views

Category:

Technology


1 download

DESCRIPTION

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.

TRANSCRIPT

Page 1: Modularized Persistence - B Zsoldos

Balázs Zsoldos

Modularized Persistence

Page 2: Modularized Persistence - B Zsoldos

History of NoSQL by Mark Madsen, Picture published by Edd Dumbill

Page 3: Modularized Persistence - B Zsoldos

Blueprint+

JPA+

JSF

DeclarativeServices

+ModularizedPersistence

+JSF

ECM+

ModularizedPersistence

+JSF

ECM+

ModularizedPersistence

+Modularized

Web

DeclarativeServices

+JPA

+JSF

Page 4: Modularized Persistence - B Zsoldos

Stefan Seifert – Apache Sling & Friends Tech Meetup, Berlin 2012

Page 5: Modularized Persistence - B Zsoldos

JDBC Driver(DataSourceFactory)

Page 6: Modularized Persistence - B Zsoldos

JDBC Driver(DataSourceFactory)

DSF Component(XADataSource)

Page 7: Modularized Persistence - B Zsoldos
Page 8: Modularized Persistence - B Zsoldos

JDBC Driver(DataSourceFactory)

DSF Component(XADataSource)

DBCP Component(DataSource)

Page 9: Modularized Persistence - B Zsoldos
Page 10: Modularized Persistence - B Zsoldos

JDBC Driver(DataSourceFactory)

DSF Component(XADataSource)

DBCP Component(DataSource)

???

Page 11: Modularized Persistence - B Zsoldos

JDBC Driver(DataSourceFactory)

DSF Component(XADataSource)

DBCP Component(DataSource)

Liquibase DataSource Component(DataSource)

Page 12: Modularized Persistence - B Zsoldos
Page 13: Modularized Persistence - B Zsoldos

<databaseChangeLog objectQuotingStrategy="QUOTE_ALL_OBJECTS" logicalFilePath="org.everit.osgi.resource.ri.schema" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">

<changeSet id="1.0.0" author="everit">

<createTable tableName="res_resource"> <column name="resource_id" type="bigint" autoIncrement="true"> <constraints primaryKeyName="pk_res_resource" primaryKey="true" nullable="false" /> </column> </createTable> </changeSet>

</databaseChangeLog>

Page 14: Modularized Persistence - B Zsoldos

Provide-Capability: liquibase.schema; name="org.everit.osgi.resource.ri"; resource="/META-INF/liquibase/resource.ri.liquibase.xml";

Provide-Capability: liquibase.schema;name="org.everit.osgi.resource.ri"; resource="/META-INF/liquibase/resource.ri.liquibase.xml"

Page 15: Modularized Persistence - B Zsoldos

JDBC Driver(DataSourceFactory)

DSF Component(XADataSource)

DBCP Component(DataSource)

Liquibase DataSource Component(DataSource)

Business Component Business Component Business ComponentQuerydsl Querydsl Querydsl

Page 16: Modularized Persistence - B Zsoldos

Examples from http://querydsl.com

Page 17: Modularized Persistence - B Zsoldos

Write Liquibase changelog

Write LQMG file

Add LQMG to the Capability

Add inclusions

Generate Querydsl Metadata

Page 18: Modularized Persistence - B Zsoldos

<lqmg xmlns="http://everit.org/lqmg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" defaultPackage="org.everit.osgi.resource.ri.schema.qdsl"> <namingRules> <classNameRule> <entity>res_resource</entity> <class>Resource</class> <propertyMappings> <primaryKey> <name>pk_res_resource</name> <property>resourcePk</property> </primaryKey> </propertyMappings> </classNameRule> </namingRules></lqmg>

Page 19: Modularized Persistence - B Zsoldos

Write Liquibase changelog

Write LQMG file

Add LQMG to the Capability

Add inclusions

Generate Querydsl Metadata

Page 20: Modularized Persistence - B Zsoldos

Provide-Capability: liquibase.schema; name="org.everit.osgi.resource.ri"; resource="/META-INF/liquibase/resource.ri.liquibase.xml";

Provide-Capability: liquibase.schema;name="org.everit.osgi.resource.ri"; resource="/META-INF/liquibase/resource.ri.liquibase.xml"

Page 21: Modularized Persistence - B Zsoldos

Provide-Capability: liquibase.schema; name="org.everit.osgi.resource.ri"; resource="/META-INF/liquibase/resource.ri.liquibase.xml"; lqmg.config.resource="/META-INF/liquibase/resource.ri.lqmg.xml"

Provide-Capability: liquibase.schema;name="org.everit.osgi.resource.ri"; resource="/META-INF/liquibase/resource.ri.liquibase.xml";lqmg.config.re source="/META-INF/liquibase/resource.ri.lqmg.xml"

Page 22: Modularized Persistence - B Zsoldos

Write Liquibase changelog

Write LQMG file

Add LQMG to the Capability

Add inclusions

Generate Querydsl Metadata

Page 23: Modularized Persistence - B Zsoldos

<databaseChangeLog objectQuotingStrategy="QUOTE_ALL_OBJECTS" logicalFilePath="org.everit.osgi.authorization.ri.schema" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

<include file="eosgi:org.everit.osgi.resource.ri" /> <include file="eosgi:org.everit.osgi.props.ri" />

<changeSet id="1.0.0" author="everit">

<createTable tableName="authr_permission"> <column name="authorized_resource_id" type="bigint"> <constraints nullable="false" foreignKeyName="fk_res_r_authr_p_a" referencedTableName="res_resource" referencedColumnNames="resource_id" /> </column> <column name="target_resource_id" type="bigint"> <constraints nullable="false" foreignKeyName="fk_res_r_authr_p_t" referencedTableName="res_resource" referencedColumnNames="resource_id" /> </column> <column name="action_" type="varchar(255)"> <constraints nullable="false" /> </column> </createTable> <addPrimaryKey constraintName="pk_authr_perm" tableName="authr_permission" columnNames="authorized_resource_id,target_resource_id,action_" />

<createTable tableName="authr_permission_inheritance"> <column name="parent_resource_id" type="bigint"> <constraints nullable="false" foreignKeyName="fk_res_r_authr_pi_p" referencedTableName="res_resource" referencedColumnNames="resource_id" /> </column> <column name="child_resource_id" type="bigint"> <constraints nullable="false" foreignKeyName="fk_res_r_authr_pi_c" referencedTableName="res_resource" referencedColumnNames="resource_id" /> </column> </createTable> <addPrimaryKey constraintName="pk_authr_perm_inheritance" tableName="authr_permission_inheritance" columnNames="parent_resource_id,child_resource_id" /> </changeSet>

</databaseChangeLog>

<include file="eosgi:org.everit.osgi.resource.ri" /> <include file="eosgi:org.everit.osgi.props.ri" />

Page 24: Modularized Persistence - B Zsoldos

Resource

Authorization

Provide-Capability: liquibase.schema; name="org.everit.osgi.resource.ri"; ...

Require-Capability: liquibase.schema; filter:=(name=org.everit.osgi.resource.ri)

<databaseChangeLog ...>

<include file="eosgi:org.everit.osgi.resource.ri" />

...

</databaseChangeLog>

Page 25: Modularized Persistence - B Zsoldos

Write Liquibase changelog

Write LQMG file

Add LQMG to the Capability

Add inclusions

Generate Querydsl Metadata

Page 26: Modularized Persistence - B Zsoldos

Start embeddedOSGi container

Deploy modules

Start embeddedH2 database

Initialize databaseschema

Generate QuerydslMetadata

LQMG

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.

Page 27: Modularized Persistence - B Zsoldos

Use-cases???

Page 28: Modularized Persistence - B Zsoldos

Monoholitic

Authorization

Authentication

User

Documents

Articles

SiteMap

Blog

Portal(v5.1.2)

Modularized

Portal

Authorization (v1.1.0)

Authentication (v2.0.0)

User (v1.3.2)

Documents (v1.0.1)

SiteMap (v1.0.3)

Articles (v3.0.14)

Blog (v2.11.0)

Page 29: Modularized Persistence - B Zsoldos

User

User Address

User Address Country

User Address Country

Company

Page 30: Modularized Persistence - B Zsoldos

REAL PROJECT!!!

Page 31: Modularized Persistence - B Zsoldos

Authorization

Page 32: Modularized Persistence - B Zsoldos

Permission

● authorized_resource_id● action● target_resource_id

Resource

● resource_id

Permission Inheritance

● parent_resource_id● child_resource_id

Page 33: Modularized Persistence - B Zsoldos

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;

Page 34: Modularized Persistence - B Zsoldos

@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(); }

Page 35: Modularized Persistence - B Zsoldos

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);

Page 36: Modularized Persistence - B Zsoldos

JDBC Driver(DataSourceFactory)

DSF Component(XADataSource)

DBCP Component(DataSource)

Liquibase DataSource Component(DataSource)

Business Component Business Component Business Component

QuerydslSupport

QuerydslConfiguration

QuerydslSQLTemplates

Querydsl Querydsl Querydsl

Page 37: Modularized Persistence - B Zsoldos

public List<Long> listDocumentIds() {

return qdsl.execute((connection, configuration) -> {

SQLQuery query = new SQLQuery(connection, configuration); QDocument document = new QDocument("d");

BooleanExpression permissionCheckPredicate = authorizationQdslUtil .authorizationPredicate(a1, document.resourceId, actions);

List<Long> list = query.from(document).where(permissionCheckPredicate) .list(document.documentId); }}

@Reference(name = "querydslSupport", bind = "setQdsl")private QuerydslSupport qdsl;

public void setQdsl(QuerydslSupport qdsl) { this.qdsl = qdsl;}

Page 38: Modularized Persistence - B Zsoldos

JDBC Driver(DataSourceFactory)

DSF Component(XADataSource)

DBCP Component(DataSource)

Liquibase DataSource Component(DataSource)

Business Component Business Component Business Component

QuerydslSupport

QuerydslConfiguration

QuerydslSQLTemplates

Querydsl Querydsl Querydsl

Transaction Helper

Page 39: Modularized Persistence - B Zsoldos

public long saveUser(String firstName, String lastName) { Objects.requireNonNull(firstName); Objects.requireNonNull(lastName);

return transactionHelper.required(() -> { // Logic that should be implemented return 0l; }); }

Page 40: Modularized Persistence - B Zsoldos

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

Page 41: Modularized Persistence - B Zsoldos

OpenSource modules

● Resource● Authorization● Authentication● Property Manager● Blobstore (Before review)● Audit (Before review)

Page 42: Modularized Persistence - B Zsoldos

Roadmap

Page 43: Modularized Persistence - B Zsoldos

HTML Output

LQMG / Maven

H2

Liquibase schema(Bundle-Capability)

HTML

Page 44: Modularized Persistence - B Zsoldos
Page 45: Modularized Persistence - B Zsoldos

LQMG / Maven

Database

Liquibase schema(Bundle-Capability)

Generate Schema

Manual Schema update

Page 46: Modularized Persistence - B Zsoldos

Webconsole plugin

DataSource(OSGi service)

Liquibase schema(Bundle-Capability)

Generate SchemaCustom User / Password

Manual Schema generation

Page 47: Modularized Persistence - B Zsoldos

Dump SQL file

Webconsole plugin

DataSource(OSGi service)

Liquibase schema(Bundle-Capability)

SQL

Page 48: Modularized Persistence - B Zsoldos

LQMG extension in changelog.xml

<databaseChangeLog objectQuotingStrategy="QUOTE_ALL_OBJECTS" logicalFilePath="org.everit.osgi.resource.ri.schema" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:lqmg="http://everit.org/xml/ns/lqmg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">

<changeSet id="1.0.0" author="everit">

<createTable tableName="res_resource" lqmg:class="QResource"> <column name="resource_id" type="bigint" autoIncrement="true" lqmg:property="resourceId"> <constraints primaryKeyName="pk_res_resource" primaryKey="true" nullable="false" /> </column> </createTable> </changeSet>

</databaseChangeLog>

Page 49: Modularized Persistence - B Zsoldos

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

Page 50: Modularized Persistence - B Zsoldos

Querydsl: http://www.querydsl.com/

Liquibase: http://www.liquibase.org/

Liquibase OSGi Bundle: https://github.com/everit-org/osgi-liquibase-bundle

LQMG: https://github.com/everit-org/osgi-lqmg

LQMG Maven Plugin: http://www.everit.org/lqmg-maven-plugin/

Liquibase DataSource: https://github.com/everit-org/osgi-liquibase-datasource

Querydsl SQLTemplates Component: https://github.com/everit-org/osgi-querydsl-templates

Querydsl Configuration Component: https://github.com/everit-org/osgi-querydsl-configuration

Querydsl Support Component: https://github.com/everit-org/osgi-querydsl-support

Cookbook chapter: http://cookbook.everit.org/persistence/index.html

Download from Maven central

Resource: https://github.com/everit-org/resource-ri

Authorization: https://github.com/everit-org/authorization-ri

Authentication: https://github.com/everit-org/authentication-simple

Property Manager: https://github.com/everit-org/property-manager-ri

Twitter: @EveritOrg