This is an automated email from the git hooks/post-receive script. New commit to branch site in repository topia. See http://git.nuiton.org/topia.git commit 8650f17f458f6d31e8568fbe0f5a9c055f30a720 Author: Arnaud Thimel <thimel@codelutin.com> Date: Mon Sep 29 17:12:24 2014 +0200 Create Jekyll site structure --- jekyll/.gitignore | 2 + jekyll/_config.yml | 20 ++ jekyll/_includes/footer.html | 61 ++++ jekyll/_includes/head.html | 20 ++ jekyll/_includes/header.html | 47 +++ jekyll/_layouts/default.html | 20 ++ jekyll/_layouts/page.html | 14 + jekyll/_layouts/post.html | 15 + jekyll/_posts/2014-09-12-topia_3.0-beta-13.md | 67 +++++ jekyll/_sass/_base.scss | 204 +++++++++++++ jekyll/_sass/_layout.scss | 236 +++++++++++++++ jekyll/_sass/_syntax-highlighting.scss | 67 +++++ jekyll/all_posts.html | 24 ++ jekyll/assets/AppTest.java | 94 ++++++ jekyll/assets/employeeAndCompany.png | Bin 0 -> 2125 bytes jekyll/assets/info.png | Bin 0 -> 819 bytes jekyll/assets/library-model.zargo | Bin 0 -> 3853 bytes jekyll/assets/library.png | Bin 0 -> 36833 bytes jekyll/assets/mandatory.png | Bin 0 -> 1987 bytes jekyll/assets/recommended.png | Bin 0 -> 1659 bytes jekyll/assets/topia_60_20.png | Bin 0 -> 2940 bytes jekyll/css/main.scss | 172 +++++++++++ jekyll/docs/model_generation.md | 75 +++++ jekyll/index.md | 112 +++++++ jekyll/tutos/from_scratch.md | 350 ++++++++++++++++++++++ jekyll/tutos/migrate_to_topia_3.md | 408 ++++++++++++++++++++++++++ 26 files changed, 2008 insertions(+) diff --git a/jekyll/.gitignore b/jekyll/.gitignore new file mode 100644 index 0000000..badbc02 --- /dev/null +++ b/jekyll/.gitignore @@ -0,0 +1,2 @@ +_site +.sass-cache diff --git a/jekyll/_config.yml b/jekyll/_config.yml new file mode 100644 index 0000000..f97b013 --- /dev/null +++ b/jekyll/_config.yml @@ -0,0 +1,20 @@ +# Site settings +title: “Tools for Portable and Independant Architecture” +email: topia-users at list.nuiton.org +description: > # this means to ignore newlines until "baseurl:" + ToPIA stands for 'Tools for Portable and Independant Architecture' +baseurl: "" # the subpath of your site, e.g. /blog/ +url: "doc.nuiton.org/topia" # the base hostname & protocol for your site + +topiaVersion: "3.0-alpha-beta-charlie" +eugeneVersion: "2.13" +junitVersion: "4.11" +h2Version: "1.4.181" + +headerCategories: ["tutos", "docs"] + +apidocs: "http://doc.nuiton.org/topia/master/topia-persistence/apidocs/index.html" + +# Build settings +markdown: kramdown + diff --git a/jekyll/_includes/footer.html b/jekyll/_includes/footer.html new file mode 100644 index 0000000..ebdee83 --- /dev/null +++ b/jekyll/_includes/footer.html @@ -0,0 +1,61 @@ +<footer class="site-footer"> + + <div class="wrapper"> + + <h2 class="footer-heading">{{ site.title }}</h2> + + <div class="footer-col-wrapper"> + <div class="footer-col footer-col-1"> + <ul class="contact-list"> + <li>{{ site.title }}</li> + <li><a href="mailto:{{ site.email }}">{{ site.email }}</a></li> + </ul> + </div> + + <div class="footer-col footer-col-2"> + <ul class="social-media-list"> + {% if site.github_username %} + <li> + <a href="https://github.com/{{ site.github_username }}"> + <span class="icon icon--github"> + <svg viewBox="0 0 16 16"> + <path fill="#828282" d="M7.999,0.431c-4.285,0-7.76,3.474-7.76,7.761 c0,3.428,2.223,6.337,5.307,7.363c0.388,0.071,0.53-0.168,0.53-0.374c0-0.184-0.007-0.672-0.01-1.32 c-2.159,0.469-2.614-1.04-2.614-1.04c-0.353-0.896-0.862-1.135-0.862-1.135c-0.705-0.481,0.053-0.472,0.053-0.472 c0.779,0.055,1.189,0.8,1.189,0.8c0.692,1.186,1.816,0.843,2.258,0.645c0.071-0.502,0.271-0.843,0.493-1.037 C4.86,11.425,3.049,10.76,3.049,7.786c0-0.847,0.302-1.54,0.799-2.082C3.768,5.507,3.501,4.718,3. [...] + </svg> + </span> + + <span class="username">{{ site.github_username }}</span> + </a> + </li> + {% endif %} + + {% if site.twitter_username %} + <li> + <a href="https://twitter.com/{{ site.twitter_username }}"> + <span class="icon icon--twitter"> + <svg viewBox="0 0 16 16"> + <path fill="#828282" d="M15.969,3.058c-0.586,0.26-1.217,0.436-1.878,0.515c0.675-0.405,1.194-1.045,1.438-1.809 + c-0.632,0.375-1.332,0.647-2.076,0.793c-0.596-0.636-1.446-1.033-2.387-1.033c-1.806,0-3.27,1.464-3.27,3.27 c0,0.256,0.029,0.506,0.085,0.745C5.163,5.404,2.753,4.102,1.14,2.124C0.859,2.607,0.698,3.168,0.698,3.767 c0,1.134,0.577,2.135,1.455,2.722C1.616,6.472,1.112,6.325,0.671,6.08c0,0.014,0,0.027,0,0.041c0,1.584,1.127,2.906,2.623,3.206 C3.02,9.402,2.731,9.442,2.433,9.442c-0.211,0-0.416-0.021-0.615-0.059c0.416,1.299,1.624,2.245,3.055,2.271 c-1.119,0.877-2.529,1.4-4.061,1.4c-0 [...] + </svg> + </span> + + <span class="username">{{ site.twitter_username }}</span> + </a> + </li> + {% endif %} + </ul> + </div> + + <div class="footer-col footer-col-3"> + <p class="text">{{ site.description }}</p> + </div> + </div> + + </div> + +<script> +$(function () { + $('.dropdown-toggle').dropdown(); +}); +</script> + +</footer> diff --git a/jekyll/_includes/head.html b/jekyll/_includes/head.html new file mode 100644 index 0000000..09eb346 --- /dev/null +++ b/jekyll/_includes/head.html @@ -0,0 +1,20 @@ +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width initial-scale=1" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + + <title>{% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}</title> + <meta name="description" content="{{ site.description }}"> + + <link rel="stylesheet" href="{{ "/css/main.css" | prepend: site.baseurl }}"> + <link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}"> + + <!-- Latest compiled and minified CSS --> + <!--link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"--> + <!--link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"--> + + <!-- Latest compiled and minified JavaScript --> + <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/js/bootstrap.min.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/js/dropdown.min.js"></script> +</head> diff --git a/jekyll/_includes/header.html b/jekyll/_includes/header.html new file mode 100644 index 0000000..8f3e654 --- /dev/null +++ b/jekyll/_includes/header.html @@ -0,0 +1,47 @@ +<header class="site-header"> + + <div class="wrapper"> + + <a class="site-title" href="{{ site.baseurl }}/">{{ site.title }}</a> + + <nav class="site-nav"> + <a href="#" class="menu-icon"> + <svg viewBox="0 0 18 15"> + <path fill="#424242" d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.031C17.335,0,18,0.665,18,1.484L18,1.484z"/> + <path fill="#424242" d="M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0c0-0.82,0.665-1.484,1.484-1.484 h15.031C17.335,6.031,18,6.696,18,7.516L18,7.516z"/> + <path fill="#424242" d="M18,13.516C18,14.335,17.335,15,16.516,15H1.484C0.665,15,0,14.335,0,13.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.031C17.335,12.031,18,12.696,18,13.516L18,13.516z"/> + </svg> + </a> + + <ul class="nav"> + {% for categ in site.headerCategories %} + <li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ categ }}<b class="caret"></b></a> + <ul class="dropdown-menu"> + {% for page in site.pages %} + {% if page.title %} + {% if page.category == categ %} + <li><a class="page-link" href="{{ page.url | prepend: site.baseurl }}">{{ page.title }}</a></li> + {% endif %} + {% endif %} + {% endfor %} + </ul> + </li> + {% endfor %} + + <li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown">Annonces<b class="caret"></b></a> + <ul class="dropdown-menu"> + {% for post in site.posts %} + <li><a class="page-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }} ({{ post.date | date: "%-d %b %Y" }})</a></li> + {% endfor %} + </ul> + </li> + </ul> + + + </nav> + + </div> + +</header> diff --git a/jekyll/_layouts/default.html b/jekyll/_layouts/default.html new file mode 100644 index 0000000..d784082 --- /dev/null +++ b/jekyll/_layouts/default.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> + + {% include head.html %} + + <body class="topbar-enabled"> + + {% include header.html %} + + <div class="page-content"> + <div class="wrapper"> + {{ content }} + </div> + </div> + + {% include footer.html %} + + </body> + +</html> diff --git a/jekyll/_layouts/page.html b/jekyll/_layouts/page.html new file mode 100644 index 0000000..74c1a11 --- /dev/null +++ b/jekyll/_layouts/page.html @@ -0,0 +1,14 @@ +--- +layout: default +--- +<div class="post"> + + <header class="post-header"> + <h1 class="post-title">{{ page.title }}</h1> + </header> + + <article class="post-content"> + {{ content }} + </article> + +</div> diff --git a/jekyll/_layouts/post.html b/jekyll/_layouts/post.html new file mode 100644 index 0000000..a2b4e52 --- /dev/null +++ b/jekyll/_layouts/post.html @@ -0,0 +1,15 @@ +--- +layout: default +--- +<div class="post"> + + <header class="post-header"> + <h1 class="post-title">{{ page.title }}</h1> + <p class="post-meta">{{ page.date | date: "%b %-d, %Y" }}{% if page.author %} • {{ page.author }}{% endif %}{% if page.meta %} • {{ page.meta }}{% endif %}</p> + </header> + + <article class="post-content"> + {{ content }} + </article> + +</div> diff --git a/jekyll/_posts/2014-09-12-topia_3.0-beta-13.md b/jekyll/_posts/2014-09-12-topia_3.0-beta-13.md new file mode 100644 index 0000000..5afddd4 --- /dev/null +++ b/jekyll/_posts/2014-09-12-topia_3.0-beta-13.md @@ -0,0 +1,67 @@ +--- +layout: post +title: "ToPIA 3.0-beta-13 released" +tags: releases +--- + +The ToPIA team is pleased to announce the topia-3.0-beta-13 release! + +Tools for Portable and Independent Architecture : + Framework de persistance et de distribution d'application. + +Documentation of the project can be found here: +<a href="https://doc.nuiton.org/topia">https://doc.nuiton.org/topia</a> + +Changes +------- + +Changes in this version include: + +New features: + + * Introduce TopiaListenableEntity contract to move out event related methods from TopiaEntity [Issue: 3484]. Thanks to Arnaud Thimel. Resolved by athimel. + * Introduce a short TopiaIdFactory [Issue: 3495]. Thanks to Arnaud Thimel. Resolved by athimel. + * Update TopiaMetaTransformer with most commonly used values [Issue: 3283]. Thanks to Arnaud Thimel. Resolved by athimel. + +Fixed Bugs: + + * Default value for "useEnumerationName" tag value should be "true" [Issue: 3475]. Thanks to Arnaud Thimel. Resolved by athimel. + * Prevent using 'object' as an HQL parameter [Issue: 3193]. Thanks to Éric Chatellier. Resolved by bleny. + * Add warning about 'user' as a reserved sql keyword [Issue: 3194]. Thanks to Éric Chatellier. Resolved by bleny. + * Do not generate DDL INDEX when target entity is an abstract class [Issue: 3494]. Thanks to Arnaud Thimel. Resolved by athimel. + * Non compilable code generated when using custom type with generics [Issue: 3453]. Thanks to Éric Chatellier. Resolved by echatellier. + +Changes: + + * Update to commons-collections4 [Issue: 2942]. Thanks to Éric Chatellier. Resolved by athimel. + + +Downloads +--------- + +No release file deployed. (all files are deployed in the maven repository) + +Maven artifacts +--------------- + +Artifacts are deployed in Maven Central Repository +http://repo1.maven.org/maven2 + +Find us at + + <a href="http://search.maven.org/#artifactdetails|org.nuiton|topia|3.0-beta-13|jar">http://search.maven.org/#artifactdetails|org.nuiton|topia|3.0-beta-13|jar</a> + +Have fun!<br/> +-ToPIA team + +[Issue: 3484]: http://nuiton.org/issues/3484 +[Issue: 3495]: http://nuiton.org/issues/3495 +[Issue: 3283]: http://nuiton.org/issues/3283 +[Issue: 3475]: http://nuiton.org/issues/3475 +[Issue: 3193]: http://nuiton.org/issues/3193 +[Issue: 3194]: http://nuiton.org/issues/3194 +[Issue: 3494]: http://nuiton.org/issues/3494 +[Issue: 3453]: http://nuiton.org/issues/3453 +[Issue: 2942]: http://nuiton.org/issues/2942 + + diff --git a/jekyll/_sass/_base.scss b/jekyll/_sass/_base.scss new file mode 100644 index 0000000..518bf2b --- /dev/null +++ b/jekyll/_sass/_base.scss @@ -0,0 +1,204 @@ +/** + * Reset some basic elements + */ +body, h1, h2, h3, h4, h5, h6, +p, blockquote, pre, hr, +dl, dd, ol, ul, figure { + margin: 0; + padding: 0; +} + + + +/** + * Basic styling + */ +body { + font-family: $base-font-family; + font-size: $base-font-size; + line-height: $base-line-height; + font-weight: 300; + color: $text-color; + background-color: $background-color; + -webkit-text-size-adjust: 100%; +} + + + +/** + * Set `margin-bottom` to maintain vertical rhythm + */ +h1, h2, h3, h4, h5, h6, +p, blockquote, pre, +ul, ol, dl, figure, +%vertical-rhythm { + margin-bottom: $spacing-unit / 2; +} + + + +/** + * Images + */ +img { + max-width: 100%; + vertical-align: middle; +} + + + +/** + * Figures + */ +figure > img { + display: block; +} + +figcaption { + font-size: $small-font-size; +} + + + +/** + * Lists + */ +ul, ol { + margin-left: $spacing-unit; +} + +li { + > ul, + > ol { + margin-bottom: 0; + } +} + + + +/** + * Headings + */ +h1, h2, h3, h4, h5, h6 { + font-weight: 300; +} + + + +/** + * Links + */ +a { + color: $brand-color; + text-decoration: none; + + &:visited { + color: darken($brand-color, 15%); + } + + &:hover { + color: $text-color; + text-decoration: underline; + } +} + + + +/** + * Blockquotes + */ +blockquote { + color: $grey-color; + border-left: 4px solid $grey-color-light; + padding-left: $spacing-unit / 2; + font-size: 18px; + letter-spacing: -1px; + font-style: italic; + + > :last-child { + margin-bottom: 0; + } +} + + + +/** + * Code formatting + */ +pre, +code { + font-size: 15px; + border: 1px solid $grey-color-light; + border-radius: 3px; + background-color: #eef; +} + +code { + padding: 1px 5px; +} + +pre { + padding: 8px 12px; + overflow-x: scroll; + + > code { + border: 0; + padding-right: 0; + padding-left: 0; + } +} + + + +/** + * Wrapper + */ +.wrapper { + max-width: -webkit-calc(800px - (#{$spacing-unit} * 2)); + max-width: calc(800px - (#{$spacing-unit} * 2)); + margin-right: auto; + margin-left: auto; + padding-right: $spacing-unit; + padding-left: $spacing-unit; + @extend %clearfix; + + @include media-query($on-laptop) { + max-width: -webkit-calc(800px - (#{$spacing-unit})); + max-width: calc(800px - (#{$spacing-unit})); + padding-right: $spacing-unit / 2; + padding-left: $spacing-unit / 2; + } +} + + + +/** + * Clearfix + */ +%clearfix { + + &:after { + content: ""; + display: table; + clear: both; + } +} + + + +/** + * Icons + */ +.icon { + + > svg { + display: inline-block; + width: 16px; + height: 16px; + vertical-align: middle; + + path { + fill: $grey-color; + } + } +} diff --git a/jekyll/_sass/_layout.scss b/jekyll/_sass/_layout.scss new file mode 100644 index 0000000..def56f8 --- /dev/null +++ b/jekyll/_sass/_layout.scss @@ -0,0 +1,236 @@ +/** + * Site header + */ +.site-header { + border-top: 5px solid $grey-color-dark; + border-bottom: 1px solid $grey-color-light; + min-height: 56px; + + // Positioning context for the mobile navigation icon + position: relative; +} + +.site-title { + font-size: 26px; + line-height: 56px; + letter-spacing: -1px; + margin-bottom: 0; + float: left; + + &, + &:visited { + color: $grey-color-dark; + } +} + +.site-nav { + float: right; + line-height: 56px; + + .menu-icon { + display: none; + } + + .page-link { + color: $text-color; + line-height: $base-line-height; + + // Gaps between nav items, but not on the first one + &:not(:first-child) { + margin-left: 20px; + } + } + + @include media-query($on-palm) { + position: absolute; + top: 9px; + right: 30px; + background-color: $background-color; + border: 1px solid $grey-color-light; + border-radius: 5px; + text-align: right; + + .menu-icon { + display: block; + float: right; + width: 36px; + height: 26px; + line-height: 0; + padding-top: 10px; + text-align: center; + + > svg { + width: 18px; + height: 15px; + + path { + fill: $grey-color-dark; + } + } + } + + .trigger { + clear: both; + display: none; + } + + &:hover .trigger { + display: block; + padding-bottom: 5px; + } + + .page-link { + display: block; + padding: 5px 10px; + } + } +} + + + +/** + * Site footer + */ +.site-footer { + border-top: 1px solid $grey-color-light; + padding: $spacing-unit 0; +} + +.footer-heading { + font-size: 18px; + margin-bottom: $spacing-unit / 2; +} + +.contact-list, +.social-media-list { + list-style: none; + margin-left: 0; +} + +.footer-col-wrapper { + font-size: 15px; + color: $grey-color; + margin-left: -$spacing-unit / 2; + @extend %clearfix; +} + +.footer-col { + float: left; + margin-bottom: $spacing-unit / 2; + padding-left: $spacing-unit / 2; +} + +.footer-col-1 { + width: -webkit-calc(35% - (#{$spacing-unit} / 2)); + width: calc(35% - (#{$spacing-unit} / 2)); +} + +.footer-col-2 { + width: -webkit-calc(20% - (#{$spacing-unit} / 2)); + width: calc(20% - (#{$spacing-unit} / 2)); +} + +.footer-col-3 { + width: -webkit-calc(45% - (#{$spacing-unit} / 2)); + width: calc(45% - (#{$spacing-unit} / 2)); +} + +@include media-query($on-laptop) { + .footer-col-1, + .footer-col-2 { + width: -webkit-calc(50% - (#{$spacing-unit} / 2)); + width: calc(50% - (#{$spacing-unit} / 2)); + } + + .footer-col-3 { + width: -webkit-calc(100% - (#{$spacing-unit} / 2)); + width: calc(100% - (#{$spacing-unit} / 2)); + } +} + +@include media-query($on-palm) { + .footer-col { + float: none; + width: -webkit-calc(100% - (#{$spacing-unit} / 2)); + width: calc(100% - (#{$spacing-unit} / 2)); + } +} + + + +/** + * Page content + */ +.page-content { + padding: $spacing-unit 0; +} + +.page-heading { + font-size: 20px; +} + +.post-list { + margin-left: 0; + list-style: none; + + > li { + margin-bottom: $spacing-unit; + } +} + +.post-meta { + font-size: $small-font-size; + color: $grey-color; +} + +.post-link { + display: block; + font-size: 24px; +} + + + +/** + * Posts + */ +.post-header { + margin-bottom: $spacing-unit; +} + +.post-title { + font-size: 42px; + letter-spacing: -1px; + line-height: 1; + + @include media-query($on-laptop) { + font-size: 36px; + } +} + +.post-content { + margin-bottom: $spacing-unit; + + h2 { + font-size: 32px; + + @include media-query($on-laptop) { + font-size: 28px; + } + } + + h3 { + font-size: 26px; + + @include media-query($on-laptop) { + font-size: 22px; + } + } + + h4 { + font-size: 20px; + + @include media-query($on-laptop) { + font-size: 18px; + } + } +} diff --git a/jekyll/_sass/_syntax-highlighting.scss b/jekyll/_sass/_syntax-highlighting.scss new file mode 100644 index 0000000..e36627d --- /dev/null +++ b/jekyll/_sass/_syntax-highlighting.scss @@ -0,0 +1,67 @@ +/** + * Syntax highlighting styles + */ +.highlight { + background: #fff; + @extend %vertical-rhythm; + + .c { color: #998; font-style: italic } // Comment + .err { color: #a61717; background-color: #e3d2d2 } // Error + .k { font-weight: bold } // Keyword + .o { font-weight: bold } // Operator + .cm { color: #998; font-style: italic } // Comment.Multiline + .cp { color: #999; font-weight: bold } // Comment.Preproc + .c1 { color: #998; font-style: italic } // Comment.Single + .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special + .gd { color: #000; background-color: #fdd } // Generic.Deleted + .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific + .ge { font-style: italic } // Generic.Emph + .gr { color: #a00 } // Generic.Error + .gh { color: #999 } // Generic.Heading + .gi { color: #000; background-color: #dfd } // Generic.Inserted + .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific + .go { color: #888 } // Generic.Output + .gp { color: #555 } // Generic.Prompt + .gs { font-weight: bold } // Generic.Strong + .gu { color: #aaa } // Generic.Subheading + .gt { color: #a00 } // Generic.Traceback + .kc { font-weight: bold } // Keyword.Constant + .kd { font-weight: bold } // Keyword.Declaration + .kp { font-weight: bold } // Keyword.Pseudo + .kr { font-weight: bold } // Keyword.Reserved + .kt { color: #458; font-weight: bold } // Keyword.Type + .m { color: #099 } // Literal.Number + .s { color: #d14 } // Literal.String + .na { color: #008080 } // Name.Attribute + .nb { color: #0086B3 } // Name.Builtin + .nc { color: #458; font-weight: bold } // Name.Class + .no { color: #008080 } // Name.Constant + .ni { color: #800080 } // Name.Entity + .ne { color: #900; font-weight: bold } // Name.Exception + .nf { color: #900; font-weight: bold } // Name.Function + .nn { color: #555 } // Name.Namespace + .nt { color: #000080 } // Name.Tag + .nv { color: #008080 } // Name.Variable + .ow { font-weight: bold } // Operator.Word + .w { color: #bbb } // Text.Whitespace + .mf { color: #099 } // Literal.Number.Float + .mh { color: #099 } // Literal.Number.Hex + .mi { color: #099 } // Literal.Number.Integer + .mo { color: #099 } // Literal.Number.Oct + .sb { color: #d14 } // Literal.String.Backtick + .sc { color: #d14 } // Literal.String.Char + .sd { color: #d14 } // Literal.String.Doc + .s2 { color: #d14 } // Literal.String.Double + .se { color: #d14 } // Literal.String.Escape + .sh { color: #d14 } // Literal.String.Heredoc + .si { color: #d14 } // Literal.String.Interpol + .sx { color: #d14 } // Literal.String.Other + .sr { color: #009926 } // Literal.String.Regex + .s1 { color: #d14 } // Literal.String.Single + .ss { color: #990073 } // Literal.String.Symbol + .bp { color: #999 } // Name.Builtin.Pseudo + .vc { color: #008080 } // Name.Variable.Class + .vg { color: #008080 } // Name.Variable.Global + .vi { color: #008080 } // Name.Variable.Instance + .il { color: #099 } // Literal.Number.Integer.Long +} diff --git a/jekyll/all_posts.html b/jekyll/all_posts.html new file mode 100644 index 0000000..0e10f3e --- /dev/null +++ b/jekyll/all_posts.html @@ -0,0 +1,24 @@ +--- +layout: default +--- + +<div class="home"> + + + <ul class="post-list"> + {% for post in site.posts %} + <li> + <span class="post-meta">{{ post.date | date: "%b %-d, %Y" }}</span> + + <h2> + <a href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a> + </h2> + </li> + {% endfor %} + </ul> + + <p class="rss-subscribe">subscribe <a href="{{ "/feed.xml" | prepend: site.baseurl }}">via RSS</a></p> + + +</div> + diff --git a/jekyll/assets/AppTest.java b/jekyll/assets/AppTest.java new file mode 100644 index 0000000..a58bbed --- /dev/null +++ b/jekyll/assets/AppTest.java @@ -0,0 +1,94 @@ +package com.company; + +/* + * #%L + * ToPIA + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2004 - 2014 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.nuiton.topia.persistence.TopiaConfigurationConstants; + +import com.company.app.MyLibraryTopiaApplicationContext; +import com.company.app.MyLibraryTopiaPersistenceContext; +import com.company.app.entities.Author; +import com.company.app.entities.AuthorTopiaDao; +import com.company.app.entities.Book; +import com.company.app.entities.BookTopiaDao; + +public class AppTest { + + @Test + public void testApp() { + // Declaration de la configuration + Map<String, String> config = new HashMap<String, String>(); + config.put(TopiaConfigurationConstants.CONFIG_DRIVER, "org.h2.Driver"); + config.put(TopiaConfigurationConstants.CONFIG_DIALECT, "org.hibernate.dialect.H2Dialect"); + config.put(TopiaConfigurationConstants.CONFIG_USER, "sa"); + config.put(TopiaConfigurationConstants.CONFIG_PASS, ""); + config.put(TopiaConfigurationConstants.CONFIG_URL, "jdbc:h2:file:/tmp/test-" + System.nanoTime()); + config.put(TopiaConfigurationConstants.CONFIG_PERSISTENCE_INIT_SCHEMA, "true"); + + // Creation de l'ApplicationContext (va initialiser la base et les services de ToPIA) + MyLibraryTopiaApplicationContext applicationContext = + new MyLibraryTopiaApplicationContext(config); + + // Démarre une transaction représentée par le PersistenceContext + MyLibraryTopiaPersistenceContext persistenceContext = + applicationContext.newPersistenceContext(); + + // On demande au PersistenceContext les instances des Dao + AuthorTopiaDao authorDao = persistenceContext.getAuthorDao(); + BookTopiaDao bookDao = persistenceContext.getBookDao(); + + Assert.assertEquals(0, authorDao.count()); + Assert.assertEquals(0, bookDao.count()); + + { // On créé un author et on demande au Dao de le persister + Author author = authorDao.newInstance(); + author.setName("Antoine de Saint-Exupéry"); + authorDao.create(author); + } + + Assert.assertEquals(1, authorDao.count()); + + { // On créé un livre en listant les propriétés qui le composent + Author author = authorDao + .forNameEquals("Antoine de Saint-Exupéry") + .findUnique(); + bookDao.create(Book.PROPERTY_NAME, "Le petit prince", + Book.PROPERTY_AUTHOR, author); + } + + Assert.assertEquals(1, bookDao.count()); + + // On commite la transaction + persistenceContext.commit(); + + // Fermeture des contextes + persistenceContext.close(); + applicationContext.close(); + } +} diff --git a/jekyll/assets/employeeAndCompany.png b/jekyll/assets/employeeAndCompany.png new file mode 100644 index 0000000..9263a45 Binary files /dev/null and b/jekyll/assets/employeeAndCompany.png differ diff --git a/jekyll/assets/info.png b/jekyll/assets/info.png new file mode 100644 index 0000000..05dbc53 Binary files /dev/null and b/jekyll/assets/info.png differ diff --git a/jekyll/assets/library-model.zargo b/jekyll/assets/library-model.zargo new file mode 100644 index 0000000..daae97c Binary files /dev/null and b/jekyll/assets/library-model.zargo differ diff --git a/jekyll/assets/library.png b/jekyll/assets/library.png new file mode 100644 index 0000000..8418a68 Binary files /dev/null and b/jekyll/assets/library.png differ diff --git a/jekyll/assets/mandatory.png b/jekyll/assets/mandatory.png new file mode 100644 index 0000000..c45f7ac Binary files /dev/null and b/jekyll/assets/mandatory.png differ diff --git a/jekyll/assets/recommended.png b/jekyll/assets/recommended.png new file mode 100644 index 0000000..986f1d8 Binary files /dev/null and b/jekyll/assets/recommended.png differ diff --git a/jekyll/assets/topia_60_20.png b/jekyll/assets/topia_60_20.png new file mode 100644 index 0000000..b80fa75 Binary files /dev/null and b/jekyll/assets/topia_60_20.png differ diff --git a/jekyll/css/main.scss b/jekyll/css/main.scss new file mode 100755 index 0000000..1eb3719 --- /dev/null +++ b/jekyll/css/main.scss @@ -0,0 +1,172 @@ +--- +# Only the main Sass file needs front matter (the dashes are enough) +--- +@charset "utf-8"; + + + +// Our variables +$base-font-family: Helvetica, Arial, sans-serif; +$base-font-size: 16px; +$small-font-size: $base-font-size * 0.875; +$base-line-height: 1.5; + +$spacing-unit: 30px; + +$text-color: #111; +$background-color: #fdfdfd; +$brand-color: #2a7ae2; + +$grey-color: #828282; +$grey-color-light: lighten($grey-color, 40%); +$grey-color-dark: darken($grey-color, 25%); + +$on-palm: 600px; +$on-laptop: 800px; + + + +// Using media queries with like this: +// @include media-query($palm) { +// .wrapper { +// padding-right: $spacing-unit / 2; +// padding-left: $spacing-unit / 2; +// } +// } +@mixin media-query($device) { + @media screen and (max-width: $device) { + @content; + } +} + + + +// Import partials from `sass_dir` (defaults to `_sass`) +@import + "base", + "layout", + "syntax-highlighting" +; + + +.site-title { + background: url('/assets/topia_60_20.png') no-repeat scroll 0px 20px transparent; + padding-left: 65px; + font-size: 20px; +} +body { + font-size: 14px; + color: #333 +} + +body.topbar-enabled { + padding-top: 65px; +} + +.site-header { + position: fixed; + top: 0px; + left: 0px; + width: 100%; + background: #eee; + height: 60px; +} + +.wrapper { + max-width: calc(960px - 30px * 2); +} + +.site-header .wrapper { + height: 60px; +} + +.site-header .site-title, +.site-header nav.site-nav { + height: 60px; +} + +.caret { + display: inline-block; + width: 0px; + height: 0px; + vertical-align: top; + border-top: 4px solid #000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; + margin-left: 4px; +} +.site-nav .nav { + position: relative; + left: 0px; + display: block; + float: left; + margin: 0px 10px 0px 0px; + height: 60px; +} +.site-nav .nav > li { + float: left; + height: 60px; +} +.dropdown { + position: relative; +} +.nav > li > a { + display: block; +} +.dropdown-menu li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333; + white-space: nowrap; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0px; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0px; + margin: 2px 0px 0px; + list-style: none outside none; + background-color: #FFF; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.2); + background-clip: padding-box; +} +.nav { + list-style: none outside none; +} +.site-nav .nav li.dropdown > a:hover { + color: #111; +} +.site-nav .nav li.dropdown > a:hover .caret { + border-top-color: #555; + border-bottom-color: #555; +} +.site-nav .nav .dropdown-toggle .caret { + margin-top: 28px; +} +.site-nav .nav > li > a { + float: none; + padding: 0px 10px; + color: #777; + text-decoration: none; + text-shadow: 0px 1px 0px #FFF; +} +.open > .dropdown-menu { + display: block; +} +.highlight pre { + line-height: 1.2; +} +code { + font-size: 14px; +} + diff --git a/jekyll/docs/model_generation.md b/jekyll/docs/model_generation.md new file mode 100644 index 0000000..460bf4c --- /dev/null +++ b/jekyll/docs/model_generation.md @@ -0,0 +1,75 @@ +--- +layout: page +title: "Génération des modèles" +category: docs +--- + + +Le module `topia-persistence` de ToPIA est capable de générer la persistence à partir d'un modèle UML. + +Nous allons détailler ici comme inclure la génération dans le cycle de compilation maven. + + +Architecture maven +------------------ + + * `src/main/xmi/mymodel.zargo` (exemple de modele UML avec argoUML) + * `src/main/xmi/mymodel.properties` (fichier de propriétés attaché au modele) + +Configuration du pom.xml +------------------------ + +Pour générer les sources dans la phase `generate-sources` de maven, et utiliser +les sources générées, et faut configurer le pom. + +### Plugin Eugene + + +{% highlight xml %} + <plugin> + <groupId>org.nuiton.eugene</groupId> + <artifactId>eugene-maven-plugin</artifactId> + <version>{{site.eugeneVersion}}</version> + <executions> + <execution> + <id>Generator</id> + <phase>generate-sources</phase> + <configuration> + <inputs>zargo</inputs> + <fullPackagePath>org.company.package</fullPackagePath> + <extractedPackages>org.company.package</extractedPackages> + <templates>org.nuiton.topia.generator.TopiaMetaGenerator</templates> + <defaultPackage>org.company.package</defaultPackage> + </configuration> + <goals> + <goal>generate</goal> + </goals> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.nuiton.topia</groupId> + <artifactId>topia-persistence</artifactId> + <version>{{site.topiaVersion}}</version> + </dependency> + </dependencies> + </plugin> +{% endhighlight %} + +Pour plus d'information à propos d'Eugene, merci de consulter le site : +http://doc.nuiton.org/eugene/ + +### Dépendances du projet + + +Il faut enfin ajouter "topia-persistence" en dépendance du projet : + + +{% highlight xml %} + <dependency> + <groupId>org.nuiton.topia</groupId> + <artifactId>topia-persistence</artifactId> + <version>{{site.topiaVersion}}</version> + </dependency> +{% endhighlight %} + diff --git a/jekyll/index.md b/jekyll/index.md new file mode 100644 index 0000000..1fa4dc0 --- /dev/null +++ b/jekyll/index.md @@ -0,0 +1,112 @@ +--- +layout: page +title: "ToPIA" +--- + +ToPIA est un framework d'abstraction des plateformes techniques. À l'heure actuelle ToPIA se focalise sur la persistence +des données. + +Lorsque vous utilisez ToPIA, vous définissez votre modèle UML, puis vous codez votre code métier sans vous +soucier de la persistence. C'est ToPIA qui va s'occuper de ce qui se passe entre ces 2 étapes. + + +Comment ça marche ? +------------------- + +Avant tout, vous devez créer un modèle UML qui représente vos objets métier. + +Ici, nous avons un modèle très simple dans lequel un employé est caractérisé par son nom, son genre et sa ville de +résidence. Une société est constituée d'un nom, d'un SIRET et d'une liste d'employés. + + + +En amont de la compilation, ToPIA va générer (grâce à [Eugene]) les fichiers nécessaires à son bon fonctionnement. Ces +fichiers générés ajoutés au code que vous avez écrit constituent les sources de l'application. Cela signifie que vous +bénéficiez de toute la robustesse d'une compilation Java, alliée à une sérieuse économie de lignes de code. Lorsque vous +packagez votre application, vous packagez donc des sources déjà générées, rien n'est généré ultérieurement. + +Les fichiers ainsi générés vous permettent de manipuler vos objets, de les charger depuis la base, les persister, +les supprimer ... Pour cela, vous disposez de plusieurs API de base qui donnent accès aux opérations les plus courantes, +mais également des classes générées qui vous évitent de devoir écrire 80% du code nécessaire à la manipulation de vos +objets. + +Par exemple, admettons que vous souhaitiez rechercher tous les emplyés qui habitent Nantes. Vous pouvez le faire en une +seule ligne sans vous soucier de comment charger des objets depuis la base : + +{% highlight java %} +List<Employee> employees = personDao.forCityEquals("Nantes").findAll(); +{% endhighlight %} + +À l'éxécution, ToPIA va traduire ces appels de méthodes en requêtes compréhensibles par le support de persistence. À +l'heure actuelle, ToPIa se base sur [Hibernate], mais le framework est pensé de manière à masquer autant que possible +ce choix technique afin de faciliter une éventuelle migration vers un autre framework de mapping objet-relationnel. + +<a href="#">Plus de détails sur les cycles en Y</a>. + + +Les services +------------ + +Autour de la persistence, ToPIA propose un certain nombre de services qui peuvent être activés ou non et qui vous +permettent de bénéficier d'autres fonctionnalités ou encore de rajouter des comportements auxquels nous n'aurions pas +pensé. + + - <a href="#">Service de gestion des mises à jour</a> : permet de gérer les migrations de base lorsque vous déployez une nouvelle + version de votre application ; + - <a href="#">Service de gestion des mises à jour (Flyway)</a> : permet également de gérer les migrations de base en se basant sur + [Flyway] ; + - <a href="#">Service de gestion des mises à jour (Liquibase)</a> : permet également de gérer les migrations de base en se basant sur + [Liquibase] ; + - <a href="#">Service de réplication</a> : permet de répliquer des données de base à base ; + - <a href="#">Service CSV</a> : service gérant les imports et expots au format CSV. + + +Avantages +--------- + + + - Principales méthodes générées pour le recherche/chargement des objets ; + - Pas de mapping ORM à écrire ; + - Génération de code intelligente (basé sur l'héritage Java, compilation, ...) ; + - En dépit de la génération de code, il est toujours possible de remplacer une classe générée ; + - Déjà utilisé dans des projets à forte volumétrie ; + - Quasi-indépendance du code métier par rapport à la solution de persistence ; + - Migrations facilitées lors des livraisons de nouvelles versions ; + - Intégration transparente à l'outil de construction du projet (Maven, ...) ; + - ... + + +Par où commencer ? +------------------ + +ToPIA est disponible sur Maven Central + +{% highlight xml %} +<dependency> + <groupId>org.nuiton</groupId> + <artifactId>topia-perssitence</artifactId> + <version>{{site.topiaVersion}}</version> +</dependency> +{% endhighlight %} + +Consultez les tutos pour créer votre projet à base de ToPIA en fonction de votre besoin : + + - [Créer un projet ToPIA en partant de rien] ; + - [Migrer de ToPIA 2.x vers ToPIA 3][migrate_to_topia_3] ; + - ... + + +Version 3.0 +----------- + + La version 3.0 de ToPIA est en cours de développement. Si vous utilisiez déjà la version 2, [consultez le guide de migration][migrate_to_topia_3]. + + +[Hibernate]: http://hibernate.org/ +[Eugene]: http://doc.nuiton.org/eugene/ +[Flyway]: http://flywaydb.org/ +[Liquibase]: http://www.liquibase.org/ + +[Créer un projet ToPIA en partant de rien]: {{site.baseurl}}/tutos/from_scratch.html +[migrate_to_topia_3]: {{site.baseurl}}/tutos/migrate_to_topia_3.html + diff --git a/jekyll/tutos/from_scratch.md b/jekyll/tutos/from_scratch.md new file mode 100644 index 0000000..a8259cf --- /dev/null +++ b/jekyll/tutos/from_scratch.md @@ -0,0 +1,350 @@ +--- +layout: page +title: "ToPIA from scratch" +category: tutos +--- + + +Ce tutoriel explique comment créer un projet from scratch. Il se base sur [Maven] mais si vous êtes plus à l'aise avec +un autre outil de construction de projet, ça ne devrait pas poser de problème. + + +Créer le projet +--------------- + +Pour commencer, il faut créer un projet Maven en respectant les conventions habituelles. Partons d'un projet Maven vide : + + +{% highlight bash %} +$ mvn archetype:generate -DgroupId=com.company -DartifactId=my-topia-app -Dversion=0.1-SNAPSHOT -DarchetypeArtifactId=maven-archetype-quickstart +{% endhighlight %} + +L'arborescence du projet ressemble alors à : + + +{% highlight bash %} + my-topia-app + ├── pom.xml + └── src + ├── main + │ └── java + │ └── com + │ └── company + │ └── App.java + └── test + └── java + └── com + └── company + └── AppTest.java +{% endhighlight %} + + +Ajoutez un dossier `src/main/xmi`, c'est ici que nous allons placer le modèle. + +{% highlight bash %} +$ cd my-topia-app +$ mkdir src/main/xmi +{% endhighlight %} + +Dans le pom, on ajoute ToPIA en dépendance, et on configure la génération : + +{% highlight xml %} +<properties> + <topiaVersion>{{site.topiaVersion}}</topiaVersion> + <eugeneVersion>{{site.eugeneVersion}}</eugeneVersion> +</properties> + +<dependencies> + <dependency> + <groupId>org.nuiton.topia</groupId> + <artifactId>topia-persistence</artifactId> + <version>${topiaVersion}</version> + </dependency> +</dependencies> + +<build> + <plugins> + <plugin> + <groupId>org.nuiton.eugene</groupId> + <artifactId>eugene-maven-plugin</artifactId> + <version>${eugeneVersion}</version> + <configuration> + <inputs>zargo</inputs> + <resolver>org.nuiton.util.FasterCachedResourceResolver</resolver> + </configuration> + <executions> + <execution> + <id>generate-entities</id> + <phase>generate-sources</phase> + <configuration> + <!-- Corresponding to extracted package from zargo file --> + <fullPackagePath>com.company.app.entities</fullPackagePath> + <!-- DefaultPackage used for Model classes generation (XxxEntityEnum, XxxTopiaXyz classes, ...) --> + <defaultPackage>com.company.app</defaultPackage> + <templates> + org.nuiton.eugene.java.JavaInterfaceTransformer, + org.nuiton.eugene.java.JavaBeanTransformer, + org.nuiton.eugene.java.JavaEnumerationTransformer, + org.nuiton.topia.templates.TopiaMetaTransformer + </templates> + </configuration> + <goals> + <goal>smart-generate</goal> + </goals> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.nuiton.topia</groupId> + <artifactId>topia-persistence</artifactId> + <version>${topiaVersion}</version> + </dependency> + <dependency> + <groupId>org.nuiton.topia</groupId> + <artifactId>topia-templates</artifactId> + <version>${topiaVersion}</version> + </dependency> + </dependencies> + </plugin> + </plugins> +</build> +{% endhighlight %} + + +Créer le modèle avec ArgoUML +---------------------------- + +Avec [ArgoUML], créez un nouveau modèle. Nous allons créer un modèle simplifié pour une application de gestion de +bibliothèque. + +Nous avons modélisé les entités `Book` et `Author` avec les champs appropriés. Faites attention à bien placer les +entités dans le bon package (`com.company.app.entities`), sinon elles ne seront pas générées. Pour que ToPIA sache que +ces classes décrivent des entités qui ont vocation à être sauvées en base, il faut leur ajouter le stéréotype `entity`. + +N'oubliez pas de donner un nom et une version au modèle. + +Enregistrez votre modèle dans `src/main/xmi` et nommez le `library-model.zargo`. + + + + +Note : le modèle utilisé pour ce tutoriel est [disponible ici][library-model.zargo]. + +C'est prêt ! +------------ + +Il suffit de construire l'application avec Maven. + +{% highlight bash %} +$ mvn clean install +{% endhighlight %} + +La compilation va provoquer la phase de génération. Si on examine le contenu du projet, on voit apparaître un dossier +`target/generated-sources/java` qui va regrouper le code généré : + + +{% highlight bash %} + my-topia-app + ├── pom.xml + ├── src + │ ├── main + │ │ ├── java + │ │ │ └── com + │ │ │ └── company + │ │ │ └── App.java + │ │ └── xmi + │ │ └── library-model.zargo + │ └── test + │ └── java + │ └── com + │ └── company + │ └── AppTest.java + └── target + ├── classes + │ └── ... + ├── generated-sources + │ ├── java + │ │ └── com + │ │ └── company + │ │ └── app + │ │ ├── AbstractMyLibraryTopiaApplicationContext.java + │ │ ├── AbstractMyLibraryTopiaDao.java + │ │ ├── AbstractMyLibraryTopiaPersistenceContext.java + │ │ ├── entities + │ │ │ ├── AbstractAuthorTopiaDao.java + │ │ │ ├── AbstractBookTopiaDao.java + │ │ │ ├── AuthorAbstract.java + │ │ │ ├── AuthorImpl.hbm.xml + │ │ │ ├── AuthorImpl.java + │ │ │ ├── Author.java + │ │ │ ├── AuthorTopiaDao.java + │ │ │ ├── BookAbstract.java + │ │ │ ├── BookImpl.hbm.xml + │ │ │ ├── BookImpl.java + │ │ │ ├── Book.java + │ │ │ ├── BookTopiaDao.java + │ │ │ ├── GeneratedAuthorTopiaDao.java + │ │ │ └── GeneratedBookTopiaDao.java + │ │ ├── MyLibraryEntityEnum.java + │ │ ├── MyLibraryTopiaApplicationContext.java + │ │ ├── MyLibraryTopiaDaoSupplier.java + │ │ └── MyLibraryTopiaPersistenceContext.java + │ ├── models + │ │ └── library-model.objectmodel + │ └── xmi + │ └── library-model.xmi + [...] + └── my-topia-app-0.1-SNAPSHOT.jar +{% endhighlight %} + + + +ToPIA a donc généré plusieurs fichiers, dont : + + * `MyLibraryTopiaApplicationContext.java` : représente le point d'entrée dans l'application. (cf [TopiaApplicationContext]) ; + * `MyLibraryTopiaPersistenceContext.java` : représente un transaction (cf [TopiaPersistenceContext]) ; + * `MyLibraryTopiaDaoSupplier.java` : permet d'obtenir une instance de n'importe quel Dao géré par ToPIA ; + * `MyLibraryEntityEnum.java` : liste les contrats et classes d'implémentation du modèle ; + * des classes abstraites pour le `MyLibraryTopiaApplicationContext` et `MyLibraryTopiaPersistenceContext`. + +Dans le package `com.company.app.entities`, on retrouve nos deux entités `Book` et `Author`. Chaque entité est représentée par plusieurs fichiers : + + * `Book.java` : une interface qui expose les informations publiques de l'entité Book ; + * `BookAbstract.java` : l'implémentation générée par ToPIA. Cette classe est abstraite ; + * `BookImpl.java` : la classe concrète implémentant la classe abstraite ; + * `BookImpl.hbm.xml` : le fichier de mapping Hibernate ; + * `GeneratedBookTopiaDao.java` : contient le code généré relatif aux entité Book : `forNameEquals(...)`, `forIsbnIn(...)`, `forAuthorEquals(...)` ; + * `AbstractBookTopiaDao.java` : implémentation du `GeneratedBookTopiaDao` retournant des entités héritant de Book ; + * `BookTopiaDao.java` : implémentation du `GeneratedBookTopiaDao` retournant des entités Book. + + +Parmi toutes ces classes relatives aux entités, celles que vous allez principalement utiliser sont `Book.java` et `BookTopiaDao.java`. + + +On teste ? +---------- + +L'archetype Maven a créé un projet compatible JUnit, ça tombe bien on va s'en servir ! Par contre, la version proposée +par défaut est un peu vieille, on va la mettre à jour dans le `pom.xml`. Il nous faut aussi une base pour faire les +tests, ajoutez `H2` : + + +{% highlight xml %} +<dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>{{site.junitVersion}}</version> + <scope>test</scope> +</dependency> +<dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>{{site.h2Version}}</version> + <scope>test</scope> +</dependency> +{% endhighlight %} + + + +Voilà un test qui initialise ToPIA et créé des entités : + +{% highlight java %} +package com.company; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.nuiton.topia.persistence.TopiaConfigurationConstants; + +import com.company.app.MyLibraryTopiaApplicationContext; +import com.company.app.MyLibraryTopiaPersistenceContext; +import com.company.app.entities.Author; +import com.company.app.entities.AuthorTopiaDao; +import com.company.app.entities.Book; +import com.company.app.entities.BookTopiaDao; + +public class AppTest { + + @Test + public void testApp() { + // Declaration de la configuration + Map<String, String> config = new HashMap<String, String>(); + config.put(TopiaConfigurationConstants.CONFIG_DRIVER, "org.h2.Driver"); + config.put(TopiaConfigurationConstants.CONFIG_DIALECT, "org.hibernate.dialect.H2Dialect"); + config.put(TopiaConfigurationConstants.CONFIG_USER, "sa"); + config.put(TopiaConfigurationConstants.CONFIG_PASS, ""); + config.put(TopiaConfigurationConstants.CONFIG_URL, "jdbc:h2:file:/tmp/test-" + System.nanoTime()); + config.put(TopiaConfigurationConstants.CONFIG_PERSISTENCE_INIT_SCHEMA, "true"); + + // Creation de l'ApplicationContext (va initialiser la base et les services de ToPIA) + MyLibraryTopiaApplicationContext applicationContext = + new MyLibraryTopiaApplicationContext(config); + + // Démarre une transaction représentée par le PersistenceContext + MyLibraryTopiaPersistenceContext persistenceContext = + applicationContext.newPersistenceContext(); + + // On demande au PersistenceContext les instances des Dao + AuthorTopiaDao authorDao = persistenceContext.getAuthorDao(); + BookTopiaDao bookDao = persistenceContext.getBookDao(); + + Assert.assertEquals(0, authorDao.count()); + Assert.assertEquals(0, bookDao.count()); + + { // On créé un author et on demande au Dao de le persister + Author author = authorDao.newInstance(); + author.setName("Antoine de Saint-Exupéry"); + authorDao.create(author); + } + + Assert.assertEquals(1, authorDao.count()); + + { // On créé un livre en listant les propriétés qui le composent + Author author = authorDao + .forNameEquals("Antoine de Saint-Exupéry") + .findUnique(); + bookDao.create(Book.PROPERTY_NAME, "Le petit prince", + Book.PROPERTY_AUTHOR, author); + } + + Assert.assertEquals(1, bookDao.count()); + + // On commite la transaction + persistenceContext.commit(); + + // Fermeture des contextes + persistenceContext.close(); + applicationContext.close(); + } +} +{% endhighlight %} + +Cette classe de test est [télécargeable ici][AppTest.java]. + + +Aller plus loin +--------------- + + * `Comment personnaliser la génération de code ?`_ + * `Comment intégrer ToPIA dans votre application ?`_ + * `Comment gérer les évolutions de schéma avec ToPIA ?`_ + * `Détails de l'intégration avec Maven`_ + + + +[Maven]: http://maven.apache.org/ +[ArgoUML]: http://argouml.tigris.org/ + +[AppTest.java]: {{site.baseurl}}/assets/AppTest.java +[library-model.zargo]: {{site.baseurl}}/assets/library-model.zargo + +[TopiaApplicationContext]: {{site.apidocs}}?org/nuiton/topia/persistence/TopiaApplicationContext.html +[TopiaPersistenceContext]: {{site.apidocs}}?org/nuiton/topia/persistence/TopiaPersistenceContext.html + +.. _Comment personnaliser la génération de code ?: ./howto_customize_generation.html +.. _Comment intégrer ToPIA dans votre application ?: ./howto_architecture_with_topia.html +.. _Comment gérer les évolutions de schéma avec ToPIA ?: ./howto_migration_service.html +.. _Détails de l'intégration avec Maven: ../docs/maven_integration.html + diff --git a/jekyll/tutos/migrate_to_topia_3.md b/jekyll/tutos/migrate_to_topia_3.md new file mode 100644 index 0000000..606200d --- /dev/null +++ b/jekyll/tutos/migrate_to_topia_3.md @@ -0,0 +1,408 @@ +--- +layout: page +title: "Migrate from ToPIA 2.x to ToPIA 3" +category: tutos +--- + + + +Gestion des dépendances +----------------------- + + + +ToPIA nécessite des versions minimum de Eugene et Hibernate. Vous devez utiliser les version suivantes : + + * Eugene >= 2.13 + * Hibernate >= 4.3.6.Final + + +Configuration du plugin Maven +----------------------------- + + + +Les templates sont contenus dans un modules à part, il faut désormais utiliser +cette dépendance dans le plugin eugene. + +{% highlight xml %} +<dependency> + <groupId>org.nuiton.topia</groupId> + <artifactId>topia-templates</artifactId> + <version>{{site.topiaVersion}}</version> +</dependency> +{% endhighlight %} + +De plus les templates ont changé de package, le nouveau package est le suivant : + + org.nuiton.topia.templates.* + + + +Génération des PropertyChangeSupport +------------------------------------ + + + +Nous nous sommes aperçus que l'impact des PropertyChangeSupport sur les performances peut ne pas être négligeable. C'est +pourquoi nous avons décidé de désactiver par défaut leur génération. Si vous souhaitez que les PropertyChangeSupport +soient générés, il faut ajouter à votre fichier de properties la tag-value suivante : + +{% highlight properties %} +model.tagValue.generatePropertyChangeSupport=true +{% endhighlight %} + +Au même titre, les méthodes permettant d'ajouter/supprimer des listener sur les PropertyChangeSupport ne sont plus sur +le contrat TopiaEntity, mais sur le contrat ListenableTopiaEntity. Si vous utilisiez ces méthodes sur votre entité +métier : pas de changement. En revanche si vous utilisiez ces méthodes sur TopiaEntity, vous devez maintenant caster +l'entité ou utiliser directement le bon contrat. + +{% highlight java %} +// Topia 2.x +TopiaEntity anEntity = ...; +anEntity.addPropertyChangeListener(listener); + +// Topia 3 (cast) +TopiaEntity anEntity = ...; +if (anEntity instanceof ListenableTopiaEntity) { + ((ListenableTopiaEntity)anEntity).addPostWriteListener(listener); +} + +// Topia 3 (direct) +ListenableTopiaEntity anEntity = ...; +anEntity.addPostWriteListener(listener); +{% endhighlight %} + +D'une manière générale, si toutes vos entités sont des ListenableTopiaEntity, nous vous encourageons à utiliser ce +contrat à la place de TopiaEntity. + +Ces méthodes ont également été renommées, voici les correspondances : + + `addVetoableListener` -> `addPreReadListener` + `removeVetoableListener` -> `removePreReadListener` + `addPropertyListener` -> `addPostReadListener` + `removePropertyListener` -> `removePostReadListener` + `addVetoableChangeListener` -> `addPreWriteListener` + `removeVetoableChangeListener` -> `removePreWriteListener` + `addPropertyChangeListener` -> `addPostWriteListener` + `removePropertyChangeListener` -> `removePostWriteListener` + +À noter que les méthodes suivantes existent toujours, mais sont dorénavant isolées sur un autre contrat (ListenableBean) : + + `addPropertyChangeListener` + `removePropertyChangeListener` + + +Refonte des indexed/ordered +--------------------------- + + + +Vous devez migrer votre modèle zargo depuis la beta-3 suite à une confusion entre ordered et indexed (stéréotypes +à placer sur une association-end d'un lien entre deux entités). + + * Le stéréotype "indexed" est déprécié, vous devez le remplacer par l'attribut "ordered" + * L'attribut (ou le stéréotype) "ordered" maintient l'ordre d'insertion en base, il faut donc vous assurer qu'une + colonne <champ>_idx est bien présente dans la base de donnée et au besoin écrire la migration nécessaire (voir + [le guide dédié][ordered_to_indexed_migration]) pour ajouter la colonne et fixer les indexes manquants (en commençant à 0). + * Les types des collections générées ont changé afin d'utiliser un contrat plus proche du modèle (selon la présence + des stéréotypes "unique" et/ou "ordered"). + +NB : La documentation contient des [examples de migration pour la refonte des indexed/ordered][ordered_to_indexed_migration]. + +Code déprécié +------------- + +La migration vers ToPIA 3.0 voit un certain nombre de classes et attributs dépréciés. + +Gérer les impacts n'est pas *nécessaire* pour passer à ToPIA 3.0, mais c'est fortement recommandé. En effet, ce code +deviendra incompatible avec ToPIA 3.1, gérer les impacts au plus tôt permettra une migration en douceur. + +Pas vrai, à partir de la 3.0-alpha-6, on casse la rétro-compatibilité car sinon +c'est trop compliqué à gérer. + +### Propriétés TOPIA_* + + + + +Les constantes suivantes sont à remplacer par leurs homologues avec le prefix *PROPERTY_* : + + * `TopiaEntity#TOPIA_ID` devient `TopiaEntity#PROPERTY_TOPIA_ID` + * `TopiaEntity#TOPIA_CREATE_DATE` devient `TopiaEntity#PROPERTY_TOPIA_CREATE_DATE` + * `TopiaEntity#TOPIA_VERSION` devient `TopiaEntity#PROPERTY_TOPIA_VERSION` + * `TopiaEntityContextable#TOPIA_CONTEXT` devient `TopiaEntityContextable#PROPERTY_TOPIA_CONTEXT` + * `TopiaEntity#COMPOSITE` devient `TopiaEntityContextable#PROPERTY_COMPOSITE` + * `TopiaEntity#AGGREGATE` devient `TopiaEntityContextable#PROPERTY_AGGREGATE` + + +### TopiaId + + + +La classe sera supprimée. Pour manipuler les topiaId, il faut utiliser le **TopiaIdFactory**. + +La forme des topiaIds générés à changé. Si vous souhaitez conserver l'ancienne forme parce que vous +souhaitez conserver l'uniformité avec une base de données existante ou si vous utilisez +topia-service-security, vous devez explicitement le spécifier à Topia 3.0 via la configuration : + +{% highlight properties %} +topia.persistence.topiaIdFactoryClassName=org.nuiton.topia.persistence.internal.LegacyTopiaIdFactory +{% endhighlight %} + + +### TopiaContextImplementor est supprimé + +Cette classe joue un rôle central dans ToPIA 2. Elle n'existe plus dans ToPIA 3. + +TODO Expliquer par quoi remplacer. + +### TopiaEntity modifié + + +Les méthodes (`getComposite()`, `getAggregate()`) ont été déplacées vers le contrat [TopiaEntityContextable]. + + +### TopiaService#preInit(...) et TopiaService#postInit(...) + + + + +Les services implémentant **TopiaService** doivent changer leur code. +Les méthodes `preInit(TopiaContextImplementor)` et `postInit(TopiaContextImplementor)` doivent être remplacées par +`preInit(TopiaContext)` et `postInit(TopiaContext)` + +### Service de migration + + + + +Toute référence à **TopiaContextImplementor** a été supprimé et remplacée par +**TopiaContext**, cela change donc les signatures et rend le code incompatible, +il faut donc bien effectuer le remplacement dans les callbacks que vous avez +écrits. + + +### Gestion des exceptions + + + +**TopiaRuntimeException** est dépréciée. Il faut désormais déclarer **TopiaException** dans la clause catch. +**TopiaException** devient Runtime. Il n'est plus nécessaire de l'intercepter. + +### Généricité + + + +Les methodes suivantes sont désormais génériques : + + * `TopiaContext#find(...)` + * `TopiaContext#findAll(...)` + * `TopiaContext#findUnique(...)` + +Si le code précédent réalisait un cast, il faut le supprimer car cela peut causer maintenant une erreur de compilation. + + +### TopiaContextListener + + + + +L'API **TopiaContextListener** contenant des opérations de manipulation du schéma de base de données a été déprécié. +L'interface est remplacée par **TopiaSchemaListener**. Les méthodes présentes sur le **TopiaContext** qui servaient à +ajouter/supprimer un **TopiaContextListener** sont elles aussi dépréciées au profit de méthodes manipulant des +**TopiaSchemaListener**. + + +### Transformer pour la génération des Dao + + + + +Si vous utilisiez explicitement le Transformer de DAO dans la configuration de votre plugin Eugene, il faut maintenant +changer le nouveau Transformer : org.nuiton.topia.templates.EntityDaoTransformer + +Exemple de configuration : + +{% highlight xml %} +<plugin> + <groupId>org.nuiton.eugene</groupId> + <artifactId>eugene-maven-plugin</artifactId> + <executions> + <execution> + <id>generate-entities</id> + <phase>generate-sources</phase> + <configuration> + <inputs>classpath:model:/:myProject.objectmodel</inputs> + <defaultPackage>org.project.entities</defaultPackage> + <templates> + org.nuiton.topia.templates.EntityDaoTransformer + </templates> + </configuration> + <goals> + <goal>generate</goal> + </goals> + </execution> + </executions> +</plugin> +{% endhighlight %} + + + + + +Si vous aviez surchargé certains des DAO générés, vous devrez probablement les renommer et changer leur signature. +Surveillez les logs de génération des DAO à la recherche des messages tels que : + +{% highlight bash %} + WARN [main] (EntityDaoTransformer.java:384) warnOnLegacyClassDetected - Legacy DAO detected ! + - You should consider renaming 'org.project.entities.ZoneDAOImpl' to 'org.project.entities.AbstractZoneTopiaDao' + - Expected class declaration is : public class AbstractZoneTopiaDao<E extends Zone> extends GeneratedZoneTopiaDao<E> { +{% endhighlight %} + +Pour l'entité Zone, vous devez supprimer votre ZoneDAO et votre ZoneDAOImpl et déplacer les méthodes +* dans ZoneTopiaDao si la méthode ne peut être utilisée seulement pour l'entité Zone (et pas les sous-classes de Zone) +* dans AbstractZoneTopiaDao si la méthode peut être utilisée pour Zone ET les entités qui héritent de Zone + + +### Méthodes findAll, find et findUnique sur TopiaContext + + + + +Si vous utilisiez ces méthodes, il est désormais recommandé d'utiliser les méthodes sur le DAO associé à votre éntité +ou par l'intermédiare du **TopiaJpaSupport**. + +#### Depuis un DAO surchargé + +Pour faciliter la migration, ces méthodes ont été portées sur l'interface deprecated **TopiaDAO**. Donc si dans votre +DAO vous faisiez : + +{% highlight java %} +List<Zone> zones = context.find("FROM Zone WHERE name=:name" , startIndex, endIndex, "name", "Principale"); +{% endhighlight %} + +Il vous suffit de retirer le "context." : + +{% highlight java %} +List<Zone> zones = find("FROM Zone WHERE name=:name" , startIndex, endIndex, "name", "Principale"); +{% endhighlight %} + +#### Dans tous les cas + +Dans tous les cas, ces méthodes étant dépréciées, vous devriez consulter leur Javadoc pour savoir par quels appels de +méthodes les remplacer. S'il n'y pas de documentation, il faut remplacer le code appellant par le corps de la méthode dépréciée +(fonctionnalité « inline » dans l'IDE). + +### Amélioration du code sql + +Voir [TopiaSqlQuery], [TopiaSqlWork] et [TopiaSqlSupport]. + + +Refactoring des packages +------------------------ + + + +Un grand nombre de classes ont été déplacées. Voici les principaux renommages : + + org.nuiton.topia.TopiaException -> org.nuiton.topia.persistence.TopiaException + org.nuiton.topia.TopiaDaoSupplier -> org.nuiton.topia.persistence.TopiaDaoSupplier + org.nuiton.topia.TopiaJpaSupport -> org.nuiton.topia.persistence.support.TopiaJpaSupport + org.nuiton.topia.TopiaPersistenceContext -> org.nuiton.topia.persistence.TopiaPersistenceContext + org.nuiton.topia.TopiaNotFoundException -> org.nuiton.topia.persistence.TopiaNotFoundException + org.nuiton.topia.TopiaApplicationContextCache -> org.nuiton.topia.persistence.TopiaApplicationContextCache + org.nuiton.topia.TopiaTransaction -> org.nuiton.topia.persistence.TopiaTransaction + org.nuiton.topia.persistence.TopiaHibernateSessionRegistry -> org.nuiton.topia.persistence.internal.TopiaHibernateSessionRegistry + org.nuiton.topia.TopiaListenableSupport -> org.nuiton.topia.persistence.support.TopiaListenableSupport + org.nuiton.topia.persistence.HibernateProvider -> org.nuiton.topia.persistence.internal.HibernateProvider + org.nuiton.topia.TopiaContextFactory -> org.nuiton.topia.persistence.TopiaConfigurationConstants + + +Le refactoring peut s'effectuer facilement en appliquant les commandes suivantes : + +{% highlight bash %} +$ grep -m 1 -nr 'org.nuiton.topia.TopiaException' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaException/org.nuiton.topia.persistence.TopiaException/g' +$ grep -m 1 -nr 'org.nuiton.topia.TopiaDaoSupplier' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaDaoSupplier/org.nuiton.topia.persistence.TopiaDaoSupplier/g' +$ grep -m 1 -nr 'org.nuiton.topia.TopiaJpaSupport' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaJpaSupport/org.nuiton.topia.persistence.support.TopiaJpaSupport/g' +$ grep -m 1 -nr 'org.nuiton.topia.TopiaPersistenceContext' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaPersistenceContext/org.nuiton.topia.persistence.TopiaPersistenceContext/g' +$ grep -m 1 -nr 'org.nuiton.topia.TopiaNotFoundException' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaNotFoundException/org.nuiton.topia.persistence.TopiaNotFoundException/g' +$ grep -m 1 -nr 'org.nuiton.topia.TopiaApplicationContextCache' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaApplicationContextCache/org.nuiton.topia.persistence.TopiaApplicationContextCache/g' +$ grep -m 1 -nr 'org.nuiton.topia.TopiaTransaction' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaTransaction/org.nuiton.topia.persistence.TopiaTransaction/g' +$ grep -m 1 -nr 'org.nuiton.topia.persistence.TopiaHibernateSessionRegistry' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.persistence.TopiaHibernateSessionRegistry/org.nuiton.topia.persistence.internal.TopiaHibernateSessionRegistry/g' +$ grep -m 1 -nr 'org.nuiton.topia.TopiaListenableSupport' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaListenableSupport/org.nuiton.topia.persistence.support.TopiaListenableSupport/g' +$ grep -m 1 -nr 'org.nuiton.topia.persistence.HibernateProvider' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.persistence.HibernateProvider/org.nuiton.topia.persistence.internal.HibernateProvider/g' +$ grep -m 1 -nr 'org.nuiton.topia.TopiaContextFactory' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/org.nuiton.topia.TopiaContextFactory/org.nuiton.topia.persistence.TopiaConfigurationConstants/g' +$ grep -m 1 -nr 'TopiaContextFactory.CONFIG_' . | awk -F ':' '{print $1}' | xargs sed -i -e 's/TopiaContextFactory.CONFIG_/TopiaConfigurationConstants.CONFIG_/g' +{% endhighlight %} + +FAQ +--- + +Voici quelques appels faisables en ToPIA 2.x et leur équivalent dans ToPIA 3 + +### Démarrage d'une nouvelle transaction + +{% highlight java %} +// ToPIA 2.x : rootTx étant le TopiaContext root +TopiaContext transaction = rootTx.beginTransaction(); + +// ToPIA 3 : rootTx étant le MyModelTopiaApplicationContext +MyModelTopiaPersistenceContext transaction = rootTx.newPersistenceContext(); +// Note : MyModelTopiaPersistenceContext implémente le contrat TopiaTransaction +{% endhighlight %} + + +### Accès à un Dao depuis un autre Dao + +{% highlight java %} +// ToPIA 2.x +SpeciesDAO speciesDAO = MyModelDAOHelper.getSpeciesDAO(getContext()); + +// ToPIA 3 +SpeciesTopiaDao speciesDAO = topiaDaoSupplier.getDao(Species.class, SpeciesTopiaDao.class); +{% endhighlight %} + + + +### Accès à la session Hibernate + +{% highlight java %} +// ToPIA 2.x : tx étant le TopiaContext +((MyModelTopiaPersistenceContextImplementor) tx).getHibernate().flush(); + +// ToPIA 3 : tx étant le MyModelTopiaPersistenceContext +tx.getHibernateSupport().getHibernateSession().flush(); +{% endhighlight %} + + + +### Liste des classes d'implémentation (ou des contrats) + +{% highlight java %} +// ToPIA 2.x +MyModelDAOHelper.getContractClasses(); +MyModelDAOHelper.getImplementationClasses(); + +// ToPIA 3 +MyModelEntityEnum.getContractClasses(); +MyModelEntityEnum.getImplementationClasses(); +{% endhighlight %} + + + +### TopiaPersistenceHelper renommé + +Le contrat **TopiaPersistenceHelper** est renommé en [TopiaEntityEnumProvider]. À noter que le **MyModelTopiaApplicationContext** +implémente ce contrat. + + +[Créer un projet ToPIA en partant de rien]: {{site.baseurl}}/tutos/from_scratch.html +[migrate_to_topia_3]: {{site.baseurl}}/tutos/migrate_to_topia_3.html +[ordered_to_indexed_migration]: {{site.baseurl}}/tutos/ordered_to_indexed_migration.html +[TopiaSqlQuery]: {{site.apidocs}}?org/nuiton/topia/persistence/support/TopiaSqlQuery.html +[TopiaSqlWork]: {{site.apidocs}}?org/nuiton/topia/persistence/support/TopiaSqlWork.html +[TopiaSqlSupport]: {{site.apidocs}}?org/nuiton/topia/persistence/support/TopiaSqlSupport.html +[TopiaEntityEnumProvider]: {{site.apidocs}}?org/nuiton/topia/persistence/TopiaEntityEnumProvider.html +[TopiaEntityContextable]: {{site.apidocs}}?org/nuiton/topia/persistence/TopiaEntityContextable.html + -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.