+ )
+}
+```
+
+#### Notes on Page Components:
+- Use the `locale` parameter to render different content for EN/DE
+- Use `notFound()` if a locale isn't supported: `if (locale !== 'de') { notFound() }`
+- Import and use shared components from `src/components/`
+- Follow existing pages for styling patterns (Tailwind CSS)
+
+### 5. Adding Images
+
+#### Image Storage Locations
+
+Store images in appropriate subdirectories under `public/`:
+
+```
+public/
+ images/ # General site images (logos, team photos, etc.)
+ illustrations/ # Illustrations and graphics
+ posts/ # Blog post images
+ your-page-name/ # Page-specific images (create new folder)
+```
+
+#### Recommended Structure for Page-Specific Images
+
+For a page like `dlt-lecture`, create:
+
+```
+public/
+ dlt-lecture/
+ hero-image.jpg
+ diagram-1.png
+ photo-classroom.jpg
+```
+
+#### Referencing Images in Markdown
+
+##### Hugo Shortcodes (in content markdown):
+
+```markdown
+{{< centered-image src="/illustrations/my-image.svg" alt="Description" width="80%" >}}
+
+{{< centered-image src="/your-page-name/specific-image.png" showCaption="true" alt="Image caption" width="60%" >}}
+```
+
+**Note:** Image paths are relative to the `public/` folder. Do NOT include `public/` in the path.
+
+##### Next.js Image Component (in page.tsx):
+
+```tsx
+import Image from 'next/image'
+
+
+
+{/* For full-width background images */}
+
+
+
+```
+
+#### Image Best Practices
+
+1. **Naming**: Use lowercase, hyphenated names: `team-photo.jpg`, `process-diagram.svg`
+2. **Formats**:
+ - Use `.svg` for logos and simple graphics
+ - Use `.webp` or `.jpg` for photos
+ - Use `.png` for images requiring transparency
+3. **Optimization**: Compress images before adding them (use tools like TinyPNG)
+4. **Alt Text**: Always provide descriptive alt text for accessibility
+5. **Dimensions**: Specify width/height to prevent layout shift
+
+### 6. Linking Between Pages
+
+#### In Markdown Files:
+
+```markdown
+[Link to another page](/about)
+[Link to German page](/de/contact)
+[External link](https://example.com)
+```
+
+#### In Next.js Components:
+
+```tsx
+import Link from 'next/link'
+
+
+ About Us
+
+
+
+ Contact
+
+```
+
+### 7. Using Hugo Shortcodes in Markdown
+
+The content markdown files support Hugo shortcodes:
+
+```markdown
+{{< centered-image src="/path/to/image.png" alt="Description" width="80%" >}}
+
+{{< quote id="person-name">}}
+```
+
+See existing content files for more shortcode examples.
+
+### 8. Testing Your New Page
+
+1. **Start the development server:**
+ ```bash
+ pnpm run dev
+ ```
+
+2. **Navigate to your page:**
+ - English: `http://localhost:3000/your-page-name`
+ - German: `http://localhost:3000/de/your-page-name`
+
+3. **Test both language versions**
+
+4. **Check responsive design** on mobile and desktop
+
+5. **Verify images load correctly**
+
+6. **Test navigation** to and from your page
+
+### 9. Checklist Before Publishing
+
+- [ ] Both `index.md` and `index.de.md` created with correct frontmatter
+- [ ] Next.js `page.tsx` component created with locale support
+- [ ] All images added to `public/` with appropriate naming
+- [ ] Image paths are correct (relative to `public/` folder)
+- [ ] All links work correctly
+- [ ] SEO metadata (title, description, keywords) filled out
+- [ ] Both EN and DE versions display correctly
+- [ ] Page is responsive on mobile and desktop
+- [ ] Accessibility: alt text on all images
+- [ ] No console errors when viewing the page
+
+## Common Patterns and Examples
+
+### Example 1: Simple Article Page
+
+**Content structure:**
+```
+content/my-article/
+ index.md
+ index.de.md
+
+public/my-article/
+ hero.jpg
+ diagram.svg
+```
+
+**Markdown frontmatter:**
+```yaml
+---
+title: "My Article Title"
+description: "Article description"
+layout: "article"
+url: "/my-article"
+---
+```
+
+### Example 2: Multi-language Landing Page
+
+```
+content/support-program/
+ index.md # English version
+ index.de.md # German version
+
+src/app/[locale]/support-program/
+ page.tsx # Handles both locales
+
+public/support-program/
+ logo.svg
+ screenshot.png
+```
+
+### Example 3: Page with Multiple Sections
+
+```markdown
+---
+title: "Complex Page"
+description: "A page with multiple sections"
+layout: "single"
+url: "/complex-page"
+---
+
+## Section 1
+
+Content for section 1...
+
+{{< centered-image src="/complex-page/section1-image.jpg" alt="Section 1" width="100%" >}}
+
+## Section 2
+
+Content for section 2...
+
+### Subsection 2.1
+
+More detailed content...
+```
+
+## Troubleshooting
+
+### Page not found (404)
+- Check that the URL in frontmatter matches the folder structure
+- Verify the Next.js component is in the correct location
+- Ensure the locale routing is set up correctly
+
+### Images not displaying
+- Verify the image path is relative to `public/` without including "public" in the path
+- Check that the image file exists in the correct location
+- Verify file name capitalization matches exactly
+
+### Content not updating
+- Restart the development server: `pnpm run dev`
+- Clear Next.js cache: `rm -rf .next` then restart
+- Check for typos in frontmatter YAML
+
+### Layout not working as expected
+- Verify the layout value matches one of the available layouts
+- Check if the layout requires specific frontmatter fields
+- Look at similar pages for reference
+
+## Further Resources
+
+- **Next.js Documentation**: https://nextjs.org/docs
+- **Tailwind CSS**: https://tailwindcss.com/docs
+- **Markdown Guide**: https://www.markdownguide.org/
+- **Project README**: See [README.md](README.md) for development setup
+
+## Need Help?
+
+If you encounter issues not covered in this guide:
+1. Check existing pages in `content/` and `src/app/[locale]/` for reference
+2. Review the project [README.md](README.md)
+3. Ask the development team for guidance
diff --git a/README.md b/README.md
index 83373343..5e34b478 100644
--- a/README.md
+++ b/README.md
@@ -1,90 +1,97 @@
# Open Elements Website
-This repo contains the website of Open Elements.
-The website is still work in progress.
-In future the website will be available at https://www.open-elements.de and https://www.open-elements.com.
+This repository contains the Open Elements website built with Next.js and Tailwind CSS, with legacy Hugo content kept for migration and historical content.
-Netlify status of English page:
+## Architecture (2026)
-[](https://app.netlify.com/sites/open-elements-en/deploys)
+The project is a Next.js application using App Router, Tailwind CSS, and `next-intl` for i18n. Legacy Hugo content and templates are kept in the repo for migration and historical content.
-Netlify status of German page:
+### Runtime layers
-[](https://app.netlify.com/sites/open-elements-de/deploys)
+- **Next.js App (primary)**
+ - App Router pages and layouts in `src/app`.
+ - UI components in `src/components`.
+ - Shared utilities in `src/lib`, data in `src/data`, types in `src/types`.
+ - Styling via Tailwind CSS and `src/app/globals.css`.
+- **Internationalization**
+ - `next-intl` routing and helpers in `src/i18n`.
+ - Translation messages in `locales`.
-## Building the website
+- **Markdown content**
+ - Markdown content in `content/`.
+ - Built static artifacts live in `public` (do not edit manually).
-Since the page is based on Hugo and React we use `npm-run-all` to execute several dev executions in parallel.
-Therefore you need to install `npm-run-all` as a dev dependency:
-
-```
-npm install --save-dev npm-run-all
-```
+- **Web components**
+ - Custom elements live in `react-src` and are bundled via `react-src/build.mjs` into `public/js`.
+- **E2E tests**
+ - Playwright specs in `tests/e2e`.
-The project is based on [Hugo](https://gohugo.io/) and you need to [install Hugo](https://gohugo.io/installation/) to build the website.
-Once Hugo is installed you can host the website on localhost by executing to following command from the root folder of the repository:
+## Development
-```
-hugo serve
-```
+### Requirements
-While the process is running the English (default) version of the website can be reached at http://localhost:1313/ and the German can be reached at http://localhost:1314/.
+- Node.js 22
+- pnpm 10
-## Adding Tailwind CSS
+### Install dependencies
-### 1-Install Tailwind CSS
+```
+pnpm install
+```
-Install tailwindcss via npm, and create your tailwind.config.js file in the root folder.
+### Run locally
```
-npm install -D tailwindcss
-npx tailwindcss init
+pnpm run dev
```
-### 2-Configure your template paths
+The app is available at http://localhost:3000.
-Add the paths to all of your template files in your tailwind.config.js file.
+### Build & start
```
-content: [
- "content/**/*.md", "layouts/**/*.html"
-],
+pnpm run build
+pnpm run start
```
-### 3-Add the Tailwind directives to your CSS
-Create 'input.css' file in the root folder and add the @tailwind directives for each of Tailwind’s layers to your input CSS file.
+### Lint
```
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+pnpm run lint
```
-### 4-Code snippet for Package.json
-
-Add the following code in 'Package.json'
+### E2E tests
```
- "scripts": {
- "dev:css": "npx tailwindcss -i input.css -o assets/css/style.css -w",
- "dev:hugo": "hugo server",
- "dev": "run-p dev:*",
- "build:css": "NODE_ENV=production npx tailwindcss -i input.css -o assets/css/style.css -m",
- "build:hugo": "hugo",
- "build": "run-s build:*"
- },
+pnpm run test:e2e
```
-### 5-Dev environment
-For development run the following command in terminal.
-```
-npm run dev
-```
+## Repo structure
-### 6-Production
-For production ready css, run the following command in terminal.
```
-npm run build
+src/app Next.js App Router pages & layouts
+src/components UI components
+src/i18n next-intl routing/messages helpers
+locales Translation JSON files
+content Markdown content
+public Static assets and generated artifacts
+react-src Web components source (bundled to public/js)
+tests/e2e Playwright specs
```
+
+## Web components build
+
+Custom elements in `react-src` are bundled with esbuild via `react-src/build.mjs` into `public/js`. This output is treated as generated code.
+
+## Deployment
+
+Netlify builds run `pnpm install` and `pnpm run build` (see `netlify.toml`).
+
+## Documentation
+
+- **[Docs Hub](docs/README.md)** - First stop for contributors (repository architecture, content workflows, quality checks)
+- **[Adding Blog Posts](docs/04-adding-blog-post.md)** - Post-specific workflow for `content/posts/`, front matter, and `/posts/...` linking conventions
+- **[Adding New Pages Guide](ADDING_PAGES.md)** - Legacy page-creation guide with EN/DE examples and image/layout notes
+
diff --git a/assets/css/style.css b/assets/css/style.css
deleted file mode 100644
index a402aba9..00000000
--- a/assets/css/style.css
+++ /dev/null
@@ -1,3 +0,0 @@
-@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700;800;900&display=swap");*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }
-
-/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Montserrat,ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}*{scrollbar-color:auto;scrollbar-width:auto}[x-cloak]{display:none!important}html{font-family:Montserrat,ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--tw-text-opacity:1;color:rgb(2 1 68/var(--tw-text-opacity,1))}.nav-link{font-size:1.125rem;line-height:1.75rem;font-weight:500;--tw-text-opacity:1;color:rgb(248 248 248/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.nav-link:focus{outline:2px solid transparent;outline-offset:2px}.nav-link:hover{--tw-text-opacity:1;color:rgb(93 185 245/var(--tw-text-opacity,1))}.nav-icon{font-size:1.5rem;line-height:2rem;line-height:1;--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.nav-icon:hover{--tw-text-opacity:1;color:rgb(92 186 158/var(--tw-text-opacity,1))}.h1{font-size:32px;font-weight:700;line-height:1.375}@media (min-width:640px){.h1{font-size:2.25rem;line-height:2.5rem;line-height:1.375}}@media (min-width:1024px){.h1{font-size:52px;line-height:1.375}}.h2{font-size:28px;font-weight:700;line-height:2.5rem}@media (min-width:640px){.h2{font-size:44px}}.h3{font-size:32px;font-weight:700;line-height:2.5rem}.h4,.h4-card{font-size:1.5rem;font-weight:700;line-height:2.5rem}@media (min-width:640px){.h4-card{font-size:1.25rem;line-height:1.75rem}}@media (min-width:1280px){.h4-card{font-size:1.5rem;line-height:2rem}}.badge-purple{flex-shrink:0;border-radius:9999px;border-width:1px;--tw-border-opacity:1;border-color:rgb(148 146 253/var(--tw-border-opacity,1));--tw-bg-opacity:1;background-color:rgb(212 212 254/var(--tw-bg-opacity,1));padding:.25rem .625rem;text-align:center;font-weight:600;--tw-text-opacity:1;color:rgb(148 146 253/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.badge-purple:hover{--tw-bg-opacity:1;background-color:rgb(117 115 255/var(--tw-bg-opacity,1));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1));--tw-shadow:2px 4px 22px rgba(117,115,255,.64);--tw-shadow-colored:2px 4px 22px var(--tw-shadow-color)}.badge-purple:active,.badge-purple:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.badge-purple:active{--tw-bg-opacity:1;background-color:rgb(148 146 253/var(--tw-bg-opacity,1));--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000}.link-rose{font-weight:500;--tw-text-opacity:1;color:rgb(230 50 119/var(--tw-text-opacity,1));transition-property:all;transition-duration:.1s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.link-rose:focus{outline:2px solid transparent;outline-offset:2px}.link-rose:hover{text-decoration-line:underline}.link-rose:active{font-weight:500}.link-purple{font-weight:500;--tw-text-opacity:1;color:rgb(148 146 253/var(--tw-text-opacity,1));transition-property:all;transition-duration:.1s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.link-purple:focus{outline:2px solid transparent;outline-offset:2px}.link-purple:hover{text-decoration-line:underline}.link-purple:active{font-weight:500}.link-green{font-weight:500;--tw-text-opacity:1;color:rgb(92 186 158/var(--tw-text-opacity,1));transition-property:all;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.link-green:focus{outline:2px solid transparent;outline-offset:2px}.link-green:hover{text-decoration-line:underline}.link-green:active{font-weight:500}.footer-link{font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.group:hover .footer-link{--tw-text-opacity:1;color:rgb(93 185 245/var(--tw-text-opacity,1))}.footer-link-icon{flex-shrink:0;font-size:1.25rem;line-height:1.75rem;--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.group:hover .footer-link-icon{--tw-text-opacity:1;color:rgb(93 185 245/var(--tw-text-opacity,1))}.container{width:100%;margin-right:auto;margin-left:auto;padding-right:1.5rem;padding-left:1.5rem}@media (min-width:640px){.container{max-width:640px;padding-right:2rem;padding-left:2rem}}@media (min-width:768px){.container{max-width:768px;padding-right:3rem;padding-left:3rem}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px;padding-right:4rem;padding-left:4rem}}.aspect-h-9{--tw-aspect-h:9}.aspect-w-16{position:relative;padding-bottom:calc(var(--tw-aspect-h)/var(--tw-aspect-w)*100%);--tw-aspect-w:16}.aspect-w-16>*{position:absolute;height:100%;width:100%;top:0;right:0;bottom:0;left:0}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{left:0;right:0}.inset-x-1\/2{left:50%;right:50%}.-bottom-12{bottom:-3rem}.-bottom-16{bottom:-4rem}.-bottom-2{bottom:-.5rem}.-bottom-2\.5{bottom:-.625rem}.-bottom-24{bottom:-6rem}.-bottom-3{bottom:-.75rem}.-bottom-4{bottom:-1rem}.-bottom-48{bottom:-12rem}.-bottom-5{bottom:-1.25rem}.-bottom-6{bottom:-1.5rem}.-bottom-64{bottom:-16rem}.-bottom-8{bottom:-2rem}.-bottom-\[30\%\]{bottom:-30%}.-left-1\/3{left:-33.333333%}.-left-14{left:-3.5rem}.-left-2{left:-.5rem}.-left-24{left:-6rem}.-left-40{left:-10rem}.-left-6{left:-1.5rem}.-left-\[10\%\]{left:-10%}.-right-11{right:-2.75rem}.-right-12{right:-3rem}.-right-16{right:-4rem}.-right-2{right:-.5rem}.-right-4{right:-1rem}.-right-40{right:-10rem}.-right-5{right:-1.25rem}.-right-6{right:-1.5rem}.-right-8{right:-2rem}.-right-\[15\%\]{right:-15%}.-right-\[18\%\]{right:-18%}.-top-10{top:-2.5rem}.-top-12{top:-3rem}.-top-16{top:-4rem}.-top-20{top:-5rem}.-top-24{top:-6rem}.-top-3{top:-.75rem}.-top-full{top:-100%}.bottom-0{bottom:0}.bottom-1\/2{bottom:50%}.bottom-5{bottom:1.25rem}.bottom-\[-390\%\]{bottom:-390%}.left-0{left:0}.left-1\.5{left:.375rem}.left-1\/2{left:50%}.left-12{left:3rem}.left-2\.5{left:.625rem}.left-4{left:1rem}.left-52{left:13rem}.right-0{right:0}.right-12{right:3rem}.right-2\.5{right:.625rem}.right-5{right:1.25rem}.right-\[11\%\]{right:11%}.right-\[20\%\]{right:20%}.right-\[7\%\]{right:7%}.right-\[8\%\]{right:8%}.top-0{top:0}.top-1\/2{top:50%}.top-12{top:3rem}.top-16{top:4rem}.top-20{top:5rem}.top-24{top:6rem}.top-28{top:7rem}.top-36{top:9rem}.top-4{top:1rem}.top-48{top:12rem}.top-52{top:13rem}.top-6{top:1.5rem}.top-9{top:2.25rem}.top-\[103\%\]{top:103%}.top-\[110\%\]{top:110%}.top-\[110px\]{top:110px}.top-\[17\%\]{top:17%}.top-\[20\%\]{top:20%}.top-\[32\%\]{top:32%}.top-\[39\%\]{top:39%}.top-\[440px\]{top:440px}.top-\[500px\]{top:500px}.top-\[55\%\]{top:55%}.top-\[65\%\]{top:65%}.isolate{isolation:isolate}.-z-0,.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.order-1{order:1}.order-2{order:2}.order-3{order:3}.col-span-2{grid-column:span 2/span 2}.float-left{float:left}.m-0{margin:0}.-mx-4{margin-left:-1rem;margin-right:-1rem}.-mx-8{margin-left:-2rem;margin-right:-2rem}.-my-2{margin-top:-.5rem;margin-bottom:-.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-7{margin-top:1.75rem;margin-bottom:1.75rem}.-ml-0\.5{margin-left:-.125rem}.-ml-1{margin-left:-.25rem}.-ml-10{margin-left:-2.5rem}.-ml-12{margin-left:-3rem}.-ml-2\.5{margin-left:-.625rem}.-ml-20{margin-left:-5rem}.-ml-3{margin-left:-.75rem}.-ml-4{margin-left:-1rem}.-ml-5{margin-left:-1.25rem}.-ml-6{margin-left:-1.5rem}.-ml-8{margin-left:-2rem}.-mr-1{margin-right:-.25rem}.-mr-16{margin-right:-4rem}.-mr-2{margin-right:-.5rem}.-mr-20{margin-right:-5rem}.-mr-28{margin-right:-7rem}.-mr-5{margin-right:-1.25rem}.-mr-6{margin-right:-1.5rem}.-mt-1{margin-top:-.25rem}.-mt-16{margin-top:-4rem}.-mt-36{margin-top:-9rem}.-mt-4{margin-top:-1rem}.-mt-8{margin-top:-2rem}.-mt-\[10px\]{margin-top:-10px}.-mt-\[14\%\]{margin-top:-14%}.-mt-\[30px\]{margin-top:-30px}.-mt-px{margin-top:-1px}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-20{margin-bottom:5rem}.mb-28{margin-bottom:7rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-7{margin-bottom:1.75rem}.mb-8{margin-bottom:2rem}.ml-0{margin-left:0}.ml-1{margin-left:.25rem}.ml-10{margin-left:2.5rem}.ml-12{margin-left:3rem}.ml-2{margin-left:.5rem}.ml-\[18px\]{margin-left:18px}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-12{margin-top:3rem}.mt-14{margin-top:3.5rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-20{margin-top:5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-7{margin-top:1.75rem}.mt-8{margin-top:2rem}.line-clamp-2{-webkit-line-clamp:2}.line-clamp-2,.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical}.line-clamp-3{-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.flow-root{display:flow-root}.grid{display:grid}.contents{display:contents}.hidden{display:none}.size-20{width:5rem;height:5rem}.size-4{width:1rem;height:1rem}.size-40{width:10rem;height:10rem}.size-44{width:11rem;height:11rem}.size-48{width:12rem;height:12rem}.size-5{width:1.25rem;height:1.25rem}.size-56{width:14rem;height:14rem}.size-6{width:1.5rem;height:1.5rem}.size-72{width:18rem;height:18rem}.size-8{width:2rem;height:2rem}.size-full{width:100%;height:100%}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-20{height:5rem}.h-28{height:7rem}.h-32{height:8rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-52{height:13rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-72{height:18rem}.h-8{height:2rem}.h-80{height:20rem}.h-\[179\.5px\]{height:179.5px}.h-\[195px\]{height:195px}.h-\[244px\]{height:244px}.h-\[274px\]{height:274px}.h-\[595px\]{height:595px}.h-\[calc\(100vh-70px\)\]{height:calc(100vh - 70px)}.h-full{height:100%}.h-screen{height:100vh}.w-1\/2{width:50%}.w-1\/4{width:25%}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-40{width:10rem}.w-44{width:11rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-80{width:20rem}.w-96{width:24rem}.w-\[195px\]{width:195px}.w-auto{width:auto}.w-full{width:100%}.w-screen{width:100vw}.min-w-0{min-width:0}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-7xl{max-width:80rem}.max-w-\[1080px\]{max-width:1080px}.max-w-\[450px\]{max-width:450px}.max-w-\[700px\]{max-width:700px}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-max{max-width:-moz-max-content;max-width:max-content}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-auto{flex:1 1 auto}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-separate{border-collapse:separate}.border-spacing-3{--tw-border-spacing-x:0.75rem;--tw-border-spacing-y:0.75rem}.border-spacing-3,.border-spacing-x-8{border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.border-spacing-x-8{--tw-border-spacing-x:2rem}.border-spacing-y-2{--tw-border-spacing-y:0.5rem;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.-rotate-45{--tw-rotate:-45deg}.-rotate-45,.rotate-45{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-45{--tw-rotate:45deg}.rotate-\[-126deg\]{--tw-rotate:-126deg}.rotate-\[-126deg\],.skew-x-\[16deg\]{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.skew-x-\[16deg\]{--tw-skew-x:16deg}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-100,.scale-95{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x:.95;--tw-scale-y:.95}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.resize{resize:both}.scroll-mt-10{scroll-margin-top:2.5rem}.scroll-mt-24{scroll-margin-top:6rem}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-10{gap:2.5rem}.gap-11{gap:2.75rem}.gap-12{gap:3rem}.gap-16{gap:4rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-20{gap:5rem}.gap-24{gap:6rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-7{gap:1.75rem}.gap-8{gap:2rem}.gap-9{gap:2.25rem}.gap-x-5{-moz-column-gap:1.25rem;column-gap:1.25rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.gap-y-10{row-gap:2.5rem}.gap-y-5{row-gap:1.25rem}.gap-y-6{row-gap:1.5rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-20>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.place-self-end{place-self:end}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-x-scroll{overflow-x:scroll}.scroll-smooth{scroll-behavior:smooth}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-3xl{border-radius:1.5rem}.rounded-\[24px\]{border-radius:24px}.rounded-\[28px\]{border-radius:28px}.rounded-\[30px\]{border-radius:30px}.rounded-\[32px\]{border-radius:32px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.rounded-b-\[32px\]{border-bottom-right-radius:32px;border-bottom-left-radius:32px}.rounded-b-none{border-bottom-right-radius:0;border-bottom-left-radius:0}.rounded-l-3xl{border-top-left-radius:1.5rem;border-bottom-left-radius:1.5rem}.rounded-t-\[32px\]{border-top-left-radius:32px;border-top-right-radius:32px}.rounded-t-none{border-top-left-radius:0;border-top-right-radius:0}.rounded-bl-\[32px\]{border-bottom-left-radius:32px}.rounded-br-\[32px\]{border-bottom-right-radius:32px}.rounded-tl-\[32px\]{border-top-left-radius:32px}.rounded-tr-\[32px\]{border-top-right-radius:32px}.border{border-width:1px}.border-2{border-width:2px}.border-\[3px\]{border-width:3px}.border-l-0{border-left-width:0}.border-t-0{border-top-width:0}.border-t-2{border-top-width:2px}.border-dashed{border-style:dashed}.border-green{--tw-border-opacity:1;border-color:rgb(92 186 158/var(--tw-border-opacity,1))}.border-green\/40{border-color:rgba(92,186,158,.4)}.border-green\/45{border-color:rgba(92,186,158,.45)}.border-purple{--tw-border-opacity:1;border-color:rgb(148 146 253/var(--tw-border-opacity,1))}.border-purple-700{--tw-border-opacity:1;border-color:rgb(117 115 255/var(--tw-border-opacity,1))}.border-rose{--tw-border-opacity:1;border-color:rgb(230 50 119/var(--tw-border-opacity,1))}.border-sky{--tw-border-opacity:1;border-color:rgb(93 185 245/var(--tw-border-opacity,1))}.border-sky\/45{border-color:rgba(93,185,245,.45)}.border-transparent{border-color:transparent}.border-yellow-200\/45{border-color:rgba(205,193,59,.45)}.bg-\[\#DFF1FD\]{--tw-bg-opacity:1;background-color:rgb(223 241 253/var(--tw-bg-opacity,1))}.bg-\[\#E7F9F3\]{--tw-bg-opacity:1;background-color:rgb(231 249 243/var(--tw-bg-opacity,1))}.bg-blue{--tw-bg-opacity:1;background-color:rgb(2 1 68/var(--tw-bg-opacity,1))}.bg-blue\/5{background-color:rgba(2,1,68,.05)}.bg-blue\/\[0\.02\]{background-color:rgba(2,1,68,.02)}.bg-blue\/\[0\.03\]{background-color:rgba(2,1,68,.03)}.bg-gray{--tw-bg-opacity:1;background-color:rgb(248 248 248/var(--tw-bg-opacity,1))}.bg-green{--tw-bg-opacity:1;background-color:rgb(92 186 158/var(--tw-bg-opacity,1))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(222 241 236/var(--tw-bg-opacity,1))}.bg-green-50{background-color:#5cba9e1f}.bg-green\/20{background-color:rgba(92,186,158,.2)}.bg-purple{--tw-bg-opacity:1;background-color:rgb(148 146 253/var(--tw-bg-opacity,1))}.bg-purple-100{--tw-bg-opacity:1;background-color:rgb(212 212 254/var(--tw-bg-opacity,1))}.bg-purple-200{--tw-bg-opacity:1;background-color:rgb(241 241 255/var(--tw-bg-opacity,1))}.bg-purple-700{--tw-bg-opacity:1;background-color:rgb(117 115 255/var(--tw-bg-opacity,1))}.bg-purple\/10{background-color:rgba(148,146,253,.1)}.bg-rose{--tw-bg-opacity:1;background-color:rgb(230 50 119/var(--tw-bg-opacity,1))}.bg-rose-100{--tw-bg-opacity:1;background-color:rgb(250 214 228/var(--tw-bg-opacity,1))}.bg-sky{--tw-bg-opacity:1;background-color:rgb(93 185 245/var(--tw-bg-opacity,1))}.bg-sky-100{--tw-bg-opacity:1;background-color:rgb(223 241 253/var(--tw-bg-opacity,1))}.bg-slate{--tw-bg-opacity:1;background-color:rgb(235 235 238/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/40{background-color:hsla(0,0%,100%,.4)}.bg-yellow-300{--tw-bg-opacity:1;background-color:rgb(230 215 61/var(--tw-bg-opacity,1))}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(252 249 219/var(--tw-bg-opacity,1))}.stroke-2{stroke-width:2}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.object-center{-o-object-position:center;object-position:center}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-0{padding-left:0;padding-right:0}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-12{padding-left:3rem;padding-right:3rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-20{padding-left:5rem;padding-right:5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-7{padding-left:1.75rem;padding-right:1.75rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-36{padding-top:9rem;padding-bottom:9rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[3px\]{padding-top:3px;padding-bottom:3px}.pb-10{padding-bottom:2.5rem}.pb-12{padding-bottom:3rem}.pb-14{padding-bottom:3.5rem}.pb-16{padding-bottom:4rem}.pb-2{padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pb-28{padding-bottom:7rem}.pb-3{padding-bottom:.75rem}.pb-36{padding-bottom:9rem}.pb-4{padding-bottom:1rem}.pb-40{padding-bottom:10rem}.pb-5{padding-bottom:1.25rem}.pb-9{padding-bottom:2.25rem}.pl-1{padding-left:.25rem}.pl-16{padding-left:4rem}.pl-5{padding-left:1.25rem}.pl-6{padding-left:1.5rem}.pr-2{padding-right:.5rem}.pr-20{padding-right:5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pr-5{padding-right:1.25rem}.pr-6{padding-right:1.5rem}.pt-0{padding-top:0}.pt-10{padding-top:2.5rem}.pt-16{padding-top:4rem}.pt-20{padding-top:5rem}.pt-24{padding-top:6rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.pt-60{padding-top:15rem}.pt-7{padding-top:1.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-6xl{font-size:3.75rem;line-height:1}.text-\[14px\]{font-size:14px}.text-\[22px\]{font-size:22px}.text-\[48px\]{font-size:48px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-sm\/6{font-size:.875rem;line-height:1.5rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-10{line-height:2.5rem}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-8{line-height:2rem}.leading-\[22px\]{line-height:22px}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.text-blue{--tw-text-opacity:1;color:rgb(2 1 68/var(--tw-text-opacity,1))}.text-blue\/30{color:rgba(2,1,68,.3)}.text-blue\/60{color:rgba(2,1,68,.6)}.text-green{--tw-text-opacity:1;color:rgb(92 186 158/var(--tw-text-opacity,1))}.text-lightgray{--tw-text-opacity:1;color:rgb(211 211 211/var(--tw-text-opacity,1))}.text-purple{--tw-text-opacity:1;color:rgb(148 146 253/var(--tw-text-opacity,1))}.text-purple-100{--tw-text-opacity:1;color:rgb(212 212 254/var(--tw-text-opacity,1))}.text-purple-700{--tw-text-opacity:1;color:rgb(117 115 255/var(--tw-text-opacity,1))}.text-rose{--tw-text-opacity:1;color:rgb(230 50 119/var(--tw-text-opacity,1))}.text-sky{--tw-text-opacity:1;color:rgb(93 185 245/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-yellow-200{--tw-text-opacity:1;color:rgb(205 193 59/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-20{opacity:.2}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-3{--tw-shadow:2px 4px 22px rgba(117,115,255,.64);--tw-shadow-colored:2px 4px 22px var(--tw-shadow-color)}.shadow-3,.shadow-4{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-4{--tw-shadow:0px 0px 24px rgba(190,227,216,.6);--tw-shadow-colored:0px 0px 24px var(--tw-shadow-color)}.shadow-5{--tw-shadow:0px 4px 20px 0px rgba(117,115,255,.22);--tw-shadow-colored:0px 4px 20px 0px var(--tw-shadow-color)}.shadow-5,.shadow-9{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-9{--tw-shadow:2px 4px 12px 0px rgba(92,186,158,.7);--tw-shadow-colored:2px 4px 12px 0px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-green{--tw-shadow-color:#5cba9e;--tw-shadow:var(--tw-shadow-colored)}.shadow-green\/20{--tw-shadow-color:rgba(92,186,158,.2);--tw-shadow:var(--tw-shadow-colored)}.shadow-sky\/20{--tw-shadow-color:rgba(93,185,245,.2);--tw-shadow:var(--tw-shadow-colored)}.shadow-yellow-200\/20{--tw-shadow-color:rgba(205,193,59,.2);--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.blur{--tw-blur:blur(8px)}.blur,.drop-shadow-card{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow-card{--tw-drop-shadow:drop-shadow(0px 0px 24px rgba(190,227,216,.6))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-2xl{--tw-backdrop-blur:blur(40px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.will-change-scroll{will-change:scroll-position}.scrollbar{--scrollbar-track:initial;--scrollbar-thumb:initial;--scrollbar-corner:initial;--scrollbar-track-hover:var(--scrollbar-track);--scrollbar-thumb-hover:var(--scrollbar-thumb);--scrollbar-corner-hover:var(--scrollbar-corner);--scrollbar-track-active:var(--scrollbar-track-hover);--scrollbar-thumb-active:var(--scrollbar-thumb-hover);--scrollbar-corner-active:var(--scrollbar-corner-hover);scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);overflow:overlay}.scrollbar.overflow-x-hidden{overflow-x:hidden}.scrollbar.overflow-y-hidden{overflow-y:hidden}.scrollbar::-webkit-scrollbar-track{background-color:var(--scrollbar-track)}.scrollbar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb)}.scrollbar::-webkit-scrollbar-corner{background-color:var(--scrollbar-corner)}.scrollbar::-webkit-scrollbar-track:hover{background-color:var(--scrollbar-track-hover)}.scrollbar::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover)}.scrollbar::-webkit-scrollbar-corner:hover{background-color:var(--scrollbar-corner-hover)}.scrollbar::-webkit-scrollbar-track:active{background-color:var(--scrollbar-track-active)}.scrollbar::-webkit-scrollbar-thumb:active{background-color:var(--scrollbar-thumb-active)}.scrollbar::-webkit-scrollbar-corner:active{background-color:var(--scrollbar-corner-active)}.scrollbar{scrollbar-width:auto}.scrollbar::-webkit-scrollbar{width:16px;height:16px}.scrollbar-thin{--scrollbar-track:initial;--scrollbar-thumb:initial;--scrollbar-corner:initial;--scrollbar-track-hover:var(--scrollbar-track);--scrollbar-thumb-hover:var(--scrollbar-thumb);--scrollbar-corner-hover:var(--scrollbar-corner);--scrollbar-track-active:var(--scrollbar-track-hover);--scrollbar-thumb-active:var(--scrollbar-thumb-hover);--scrollbar-corner-active:var(--scrollbar-corner-hover);scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);overflow:overlay}.scrollbar-thin.overflow-x-hidden{overflow-x:hidden}.scrollbar-thin.overflow-y-hidden{overflow-y:hidden}.scrollbar-thin::-webkit-scrollbar-track{background-color:var(--scrollbar-track)}.scrollbar-thin::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb)}.scrollbar-thin::-webkit-scrollbar-corner{background-color:var(--scrollbar-corner)}.scrollbar-thin::-webkit-scrollbar-track:hover{background-color:var(--scrollbar-track-hover)}.scrollbar-thin::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover)}.scrollbar-thin::-webkit-scrollbar-corner:hover{background-color:var(--scrollbar-corner-hover)}.scrollbar-thin::-webkit-scrollbar-track:active{background-color:var(--scrollbar-track-active)}.scrollbar-thin::-webkit-scrollbar-thumb:active{background-color:var(--scrollbar-thumb-active)}.scrollbar-thin::-webkit-scrollbar-corner:active{background-color:var(--scrollbar-corner-active)}.scrollbar-thin{scrollbar-width:thin}.scrollbar-thin::-webkit-scrollbar{width:8px;height:8px}.scrollbar-none{scrollbar-width:none}.scrollbar-none::-webkit-scrollbar{display:none}.scrollbar-thumb-blue{--scrollbar-thumb:#020144!important}.no-list-style-type{list-style-type:none;margin:.5em;padding-inline-start:0}p{padding-top:.8em}@media (min-width:640px){.sm\:h3{font-size:32px;font-weight:700;line-height:2.5rem}.sm\:container{width:100%;margin-right:auto;margin-left:auto;padding-right:1.5rem;padding-left:1.5rem}@media (min-width:640px){.sm\:container{max-width:640px;padding-right:2rem;padding-left:2rem}}@media (min-width:768px){.sm\:container{max-width:768px;padding-right:3rem;padding-left:3rem}}@media (min-width:1024px){.sm\:container{max-width:1024px}}@media (min-width:1280px){.sm\:container{max-width:1280px;padding-right:4rem;padding-left:4rem}}}@media (min-width:1024px){.lg\:container{width:100%;margin-right:auto;margin-left:auto;padding-right:1.5rem;padding-left:1.5rem}@media (min-width:640px){.lg\:container{max-width:640px;padding-right:2rem;padding-left:2rem}}@media (min-width:768px){.lg\:container{max-width:768px;padding-right:3rem;padding-left:3rem}}@media (min-width:1024px){.lg\:container{max-width:1024px}}@media (min-width:1280px){.lg\:container{max-width:1280px;padding-right:4rem;padding-left:4rem}}}@media (min-width:1280px){.xl\:container{width:100%;margin-right:auto;margin-left:auto;padding-right:1.5rem;padding-left:1.5rem}@media (min-width:640px){.xl\:container{max-width:640px;padding-right:2rem;padding-left:2rem}}@media (min-width:768px){.xl\:container{max-width:768px;padding-right:3rem;padding-left:3rem}}@media (min-width:1024px){.xl\:container{max-width:1024px}}@media (min-width:1280px){.xl\:container{max-width:1280px;padding-right:4rem;padding-left:4rem}}}.placeholder\:text-center::-moz-placeholder{text-align:center}.placeholder\:text-center::placeholder{text-align:center}.placeholder\:font-medium::-moz-placeholder{font-weight:500}.placeholder\:font-medium::placeholder{font-weight:500}.placeholder\:text-blue::-moz-placeholder{--tw-text-opacity:1;color:rgb(2 1 68/var(--tw-text-opacity,1))}.placeholder\:text-blue::placeholder{--tw-text-opacity:1;color:rgb(2 1 68/var(--tw-text-opacity,1))}.placeholder\:text-opacity-60::-moz-placeholder{--tw-text-opacity:0.6}.placeholder\:text-opacity-60::placeholder{--tw-text-opacity:0.6}.before\:block:before{content:var(--tw-content);display:block}.first\:pt-3:first-child{padding-top:.75rem}.last\:pb-3:last-child{padding-bottom:.75rem}.even\:mt-5:nth-child(2n),.odd\:mt-5:nth-child(odd){margin-top:1.25rem}.focus\:border-green:focus{--tw-border-opacity:1;border-color:rgb(92 186 158/var(--tw-border-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.group:hover .group-hover\:flex{display:flex}.group:hover .group-hover\:text-blue{--tw-text-opacity:1;color:rgb(2 1 68/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-purple-700{--tw-text-opacity:1;color:rgb(117 115 255/var(--tw-text-opacity,1))}.aria-disabled\:bg-purple-100[aria-disabled=true]{--tw-bg-opacity:1;background-color:rgb(212 212 254/var(--tw-bg-opacity,1))}.prose-headings\:font-bold :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose],[class~=not-prose] *))){font-weight:700}.prose-h4\:mb-6 :is(:where(h4):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:1.5rem}.prose-h4\:text-2xl :is(:where(h4):not(:where([class~=not-prose],[class~=not-prose] *))){font-size:1.5rem;line-height:2rem}.prose-h5\:mt-4 :is(:where(h5):not(:where([class~=not-prose],[class~=not-prose] *))){margin-top:1rem}.prose-h5\:text-lg :is(:where(h5):not(:where([class~=not-prose],[class~=not-prose] *))){font-size:1.125rem;line-height:1.75rem}.prose-p\:mt-3 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){margin-top:.75rem}.prose-p\:text-base :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){font-size:1rem;line-height:1.5rem}.prose-p\:leading-7 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){line-height:1.75rem}.prose-a\:block :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){display:block}.prose-a\:font-bold :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){font-weight:700}.prose-a\:text-purple-700 :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){--tw-text-opacity:1;color:rgb(117 115 255/var(--tw-text-opacity,1))}.prose-a\:no-underline :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){text-decoration-line:none}.prose-blockquote\:rounded-3xl :is(:where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))){border-radius:1.5rem}.prose-blockquote\:border-l-0 :is(:where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))){border-left-width:0}.prose-blockquote\:bg-green-100 :is(:where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))){--tw-bg-opacity:1;background-color:rgb(222 241 236/var(--tw-bg-opacity,1))}.prose-blockquote\:px-8 :is(:where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))){padding-left:2rem;padding-right:2rem}.prose-blockquote\:py-3 :is(:where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))){padding-top:.75rem;padding-bottom:.75rem}.prose-blockquote\:not-italic :is(:where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))){font-style:normal}.prose-code\:bg-yellow :is(:where(code):not(:where([class~=not-prose],[class~=not-prose] *))){--tw-bg-opacity:1;background-color:rgb(241 227 75/var(--tw-bg-opacity,1))}.prose-pre\:my-0 :is(:where(pre):not(:where([class~=not-prose],[class~=not-prose] *))){margin-top:0;margin-bottom:0}.prose-pre\:rounded-none :is(:where(pre):not(:where([class~=not-prose],[class~=not-prose] *))){border-radius:0}.prose-pre\:bg-\[\#010027\]\/80 :is(:where(pre):not(:where([class~=not-prose],[class~=not-prose] *))){background-color:rgba(1,0,39,.8)}.prose-ul\:-ml-2\.5 :is(:where(ul):not(:where([class~=not-prose],[class~=not-prose] *))){margin-left:-.625rem}.prose-li\:marker\:text-purple-700 * :is(:where(li):not(:where([class~=not-prose],[class~=not-prose] *)))::marker{color:#7573ff}.prose-li\:marker\:text-purple-700 :is(:where(li):not(:where([class~=not-prose],[class~=not-prose] *)))::marker{color:#7573ff}.hover\:-translate-y-6:hover{--tw-translate-y:-1.5rem}.hover\:-translate-y-6:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:border-purple-700:hover{--tw-border-opacity:1;border-color:rgb(117 115 255/var(--tw-border-opacity,1))}.hover\:border-sky-200:hover{--tw-border-opacity:1;border-color:rgb(84 167 221/var(--tw-border-opacity,1))}.hover\:bg-green:hover{--tw-bg-opacity:1;background-color:rgb(92 186 158/var(--tw-bg-opacity,1))}.hover\:bg-green-200:hover{--tw-bg-opacity:1;background-color:rgb(190 227 216/var(--tw-bg-opacity,1))}.hover\:bg-green-300:hover{--tw-bg-opacity:1;background-color:rgb(83 167 142/var(--tw-bg-opacity,1))}.hover\:bg-purple-100\/70:hover{background-color:rgba(212,212,254,.7)}.hover\:bg-purple-700:hover{--tw-bg-opacity:1;background-color:rgb(117 115 255/var(--tw-bg-opacity,1))}.hover\:bg-sky-200:hover{--tw-bg-opacity:1;background-color:rgb(84 167 221/var(--tw-bg-opacity,1))}.hover\:bg-white\/20:hover{background-color:hsla(0,0%,100%,.2)}.hover\:bg-yellow-400:hover{--tw-bg-opacity:1;background-color:rgb(207 194 55/var(--tw-bg-opacity,1))}.hover\:text-blue:hover{--tw-text-opacity:1;color:rgb(2 1 68/var(--tw-text-opacity,1))}.hover\:text-green:hover{--tw-text-opacity:1;color:rgb(92 186 158/var(--tw-text-opacity,1))}.hover\:text-purple-700:hover{--tw-text-opacity:1;color:rgb(117 115 255/var(--tw-text-opacity,1))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.hover\:shadow-3:hover{--tw-shadow:2px 4px 22px rgba(117,115,255,.64);--tw-shadow-colored:2px 4px 22px var(--tw-shadow-color)}.hover\:shadow-3:hover,.hover\:shadow-5:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-5:hover{--tw-shadow:0px 4px 20px 0px rgba(117,115,255,.22);--tw-shadow-colored:0px 4px 20px 0px var(--tw-shadow-color)}.hover\:shadow-6:hover{--tw-shadow:2px 4px 22px 0px rgba(205,193,59,.6);--tw-shadow-colored:2px 4px 22px 0px var(--tw-shadow-color)}.hover\:shadow-6:hover,.hover\:shadow-7:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-7:hover{--tw-shadow:2px 4px 22px 0px rgba(92,186,158,.6);--tw-shadow-colored:2px 4px 22px 0px var(--tw-shadow-color)}.hover\:shadow-8:hover{--tw-shadow:2px 4px 22px 0px rgba(93,185,245,.6);--tw-shadow-colored:2px 4px 22px 0px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.active\:bg-green:active{--tw-bg-opacity:1;background-color:rgb(92 186 158/var(--tw-bg-opacity,1))}.active\:bg-purple:active{--tw-bg-opacity:1;background-color:rgb(148 146 253/var(--tw-bg-opacity,1))}.active\:bg-rose:active{--tw-bg-opacity:1;background-color:rgb(230 50 119/var(--tw-bg-opacity,1))}.active\:text-rose-100:active{--tw-text-opacity:1;color:rgb(250 214 228/var(--tw-text-opacity,1))}.active\:text-white:active{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.active\:shadow-none:active{--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}@media (min-width:640px){.sm\:absolute{position:absolute}.sm\:inset-y-1\/2{top:50%;bottom:50%}.sm\:-bottom-32{bottom:-8rem}.sm\:-bottom-36{bottom:-9rem}.sm\:-bottom-8{bottom:-2rem}.sm\:-bottom-\[70\%\]{bottom:-70%}.sm\:-left-2\.5{left:-.625rem}.sm\:-left-24{left:-6rem}.sm\:-right-24{right:-6rem}.sm\:-right-8{right:-2rem}.sm\:-top-20{top:-5rem}.sm\:-top-24{top:-6rem}.sm\:bottom-2{bottom:.5rem}.sm\:bottom-auto{bottom:auto}.sm\:left-16{left:4rem}.sm\:right-1\/3{right:33.333333%}.sm\:right-28{right:7rem}.sm\:right-\[12\%\]{right:12%}.sm\:right-\[15\%\]{right:15%}.sm\:right-\[9\%\]{right:9%}.sm\:top-0{top:0}.sm\:top-28{top:7rem}.sm\:top-32{top:8rem}.sm\:top-36{top:9rem}.sm\:top-8{top:2rem}.sm\:top-\[110\%\]{top:110%}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:-ml-16{margin-left:-4rem}.sm\:-mr-16{margin-right:-4rem}.sm\:-mr-24{margin-right:-6rem}.sm\:-mr-32{margin-right:-8rem}.sm\:-mt-2\.5{margin-top:-.625rem}.sm\:-mt-\[4\%\]{margin-top:-4%}.sm\:-mt-\[5\%\]{margin-top:-5%}.sm\:mb-0{margin-bottom:0}.sm\:mb-12{margin-bottom:3rem}.sm\:mb-14{margin-bottom:3.5rem}.sm\:mb-5{margin-bottom:1.25rem}.sm\:mb-6{margin-bottom:1.5rem}.sm\:ml-0{margin-left:0}.sm\:ml-2{margin-left:.5rem}.sm\:ml-8{margin-left:2rem}.sm\:ml-auto{margin-left:auto}.sm\:mr-auto{margin-right:auto}.sm\:mt-10{margin-top:2.5rem}.sm\:mt-12{margin-top:3rem}.sm\:mt-16{margin-top:4rem}.sm\:mt-2{margin-top:.5rem}.sm\:mt-3{margin-top:.75rem}.sm\:mt-4{margin-top:1rem}.sm\:mt-5{margin-top:1.25rem}.sm\:mt-7{margin-top:1.75rem}.sm\:mt-8{margin-top:2rem}.sm\:line-clamp-none{overflow:visible;display:block;-webkit-box-orient:horizontal;-webkit-line-clamp:none}.sm\:block{display:block}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:hidden{display:none}.sm\:h-14{height:3.5rem}.sm\:h-16{height:4rem}.sm\:h-20{height:5rem}.sm\:h-24{height:6rem}.sm\:h-40{height:10rem}.sm\:h-6{height:1.5rem}.sm\:h-7{height:1.75rem}.sm\:h-\[310px\]{height:310px}.sm\:h-auto{height:auto}.sm\:w-12{width:3rem}.sm\:w-14{width:3.5rem}.sm\:w-16{width:4rem}.sm\:w-20{width:5rem}.sm\:w-24{width:6rem}.sm\:w-28{width:7rem}.sm\:w-32{width:8rem}.sm\:w-40{width:10rem}.sm\:w-48{width:12rem}.sm\:w-52{width:13rem}.sm\:w-6{width:1.5rem}.sm\:w-64{width:16rem}.sm\:w-7{width:1.75rem}.sm\:w-72{width:18rem}.sm\:w-8{width:2rem}.sm\:w-96{width:24rem}.sm\:w-\[310px\]{width:310px}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:max-w-full{max-width:100%}.sm\:max-w-md{max-width:28rem}.sm\:max-w-xl{max-width:36rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:flex-col{flex-direction:column}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:justify-start{justify-content:flex-start}.sm\:gap-0{gap:0}.sm\:gap-12{gap:3rem}.sm\:gap-2{gap:.5rem}.sm\:gap-24{gap:6rem}.sm\:gap-5{gap:1.25rem}.sm\:gap-6{gap:1.5rem}.sm\:gap-y-4{row-gap:1rem}.sm\:space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.sm\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.sm\:rounded-3xl{border-radius:1.5rem}.sm\:border-l{border-left-width:1px}.sm\:border-r-0{border-right-width:0}.sm\:p-10{padding:2.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-12{padding-left:3rem;padding-right:3rem}.sm\:px-16{padding-left:4rem;padding-right:4rem}.sm\:px-24{padding-left:6rem;padding-right:6rem}.sm\:px-3{padding-left:.75rem;padding-right:.75rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:px-8{padding-left:2rem;padding-right:2rem}.sm\:py-16{padding-top:4rem;padding-bottom:4rem}.sm\:py-24{padding-top:6rem;padding-bottom:6rem}.sm\:py-3{padding-top:.75rem;padding-bottom:.75rem}.sm\:py-6{padding-top:1.5rem;padding-bottom:1.5rem}.sm\:py-7{padding-top:1.75rem;padding-bottom:1.75rem}.sm\:py-8{padding-top:2rem;padding-bottom:2rem}.sm\:pb-0{padding-bottom:0}.sm\:pb-12{padding-bottom:3rem}.sm\:pb-16{padding-bottom:4rem}.sm\:pb-32{padding-bottom:8rem}.sm\:pb-36{padding-bottom:9rem}.sm\:pb-44{padding-bottom:11rem}.sm\:pl-0{padding-left:0}.sm\:pl-16{padding-left:4rem}.sm\:pl-5{padding-left:1.25rem}.sm\:pr-20{padding-right:5rem}.sm\:pr-36{padding-right:9rem}.sm\:pt-12{padding-top:3rem}.sm\:pt-24{padding-top:6rem}.sm\:pt-28{padding-top:7rem}.sm\:pt-36{padding-top:9rem}.sm\:pt-5{padding-top:1.25rem}.sm\:pt-64{padding-top:16rem}.sm\:text-left{text-align:left}.sm\:text-center{text-align:center}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}.sm\:text-7xl{font-size:4.5rem;line-height:1}.sm\:text-lg{font-size:1.125rem;line-height:1.75rem}.sm\:leading-8{line-height:2rem}.sm\:placeholder\:text-left::-moz-placeholder{text-align:left}.sm\:placeholder\:text-left::placeholder{text-align:left}}@media (min-width:768px){.md\:-left-40{left:-10rem}.md\:-right-40{right:-10rem}.md\:-top-28{top:-7rem}.md\:right-\[10\%\]{right:10%}.md\:right-\[20\%\]{right:20%}.md\:top-40{top:10rem}.md\:float-none{float:none}.md\:-ml-16{margin-left:-4rem}.md\:mt-12{margin-top:3rem}.md\:mt-16{margin-top:4rem}.md\:flex{display:flex}.md\:h-auto{height:auto}.md\:w-16{width:4rem}.md\:w-24{width:6rem}.md\:w-28{width:7rem}.md\:w-36{width:9rem}.md\:w-48{width:12rem}.md\:max-w-2xl{max-width:42rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:px-12{padding-left:3rem;padding-right:3rem}.md\:py-28{padding-top:7rem;padding-bottom:7rem}.md\:pb-40{padding-bottom:10rem}.md\:pt-28{padding-top:7rem}}@media (min-width:1024px){.lg\:absolute{position:absolute}.lg\:-bottom-10{bottom:-2.5rem}.lg\:-bottom-48{bottom:-12rem}.lg\:-left-12{left:-3rem}.lg\:-left-24{left:-6rem}.lg\:-left-44{left:-11rem}.lg\:-left-\[11px\]{left:-11px}.lg\:-right-20{right:-5rem}.lg\:-right-32{right:-8rem}.lg\:-top-1\/2{top:-50%}.lg\:-top-12{top:-3rem}.lg\:bottom-auto{bottom:auto}.lg\:left-1\/2{left:50%}.lg\:left-32{left:8rem}.lg\:left-auto{left:auto}.lg\:right-80{right:20rem}.lg\:right-\[10\.5\%\]{right:10.5%}.lg\:right-\[15\%\]{right:15%}.lg\:right-\[31\%\]{right:31%}.lg\:right-auto{right:auto}.lg\:top-0{top:0}.lg\:top-12{top:3rem}.lg\:top-14{top:3.5rem}.lg\:top-16{top:4rem}.lg\:top-24{top:6rem}.lg\:top-36{top:9rem}.lg\:top-7{top:1.75rem}.lg\:top-\[25\%\]{top:25%}.lg\:order-1{order:1}.lg\:order-2{order:2}.lg\:order-3{order:3}.lg\:-mx-8{margin-left:-2rem;margin-right:-2rem}.lg\:mx-0{margin-left:0;margin-right:0}.lg\:-mr-5{margin-right:-1.25rem}.lg\:-mt-16{margin-top:-4rem}.lg\:mb-16{margin-bottom:4rem}.lg\:ml-0{margin-left:0}.lg\:ml-\[19\%\]{margin-left:19%}.lg\:ml-\[25\%\]{margin-left:25%}.lg\:mr-\[5\%\]{margin-right:5%}.lg\:mt-0{margin-top:0}.lg\:mt-12{margin-top:3rem}.lg\:mt-20{margin-top:5rem}.lg\:mt-40{margin-top:10rem}.lg\:mt-5{margin-top:1.25rem}.lg\:mt-6{margin-top:1.5rem}.lg\:mt-8{margin-top:2rem}.lg\:mt-\[-12\%\]{margin-top:-12%}.lg\:block{display:block}.lg\:inline-block{display:inline-block}.lg\:inline{display:inline}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:h-40{height:10rem}.lg\:h-\[265px\]{height:265px}.lg\:w-1\/2{width:50%}.lg\:w-1\/3{width:33.333333%}.lg\:w-2\/3{width:66.666667%}.lg\:w-24{width:6rem}.lg\:w-32{width:8rem}.lg\:w-36{width:9rem}.lg\:w-40{width:10rem}.lg\:w-48{width:12rem}.lg\:w-56{width:14rem}.lg\:w-64{width:16rem}.lg\:w-72{width:18rem}.lg\:w-80{width:20rem}.lg\:w-\[265px\]{width:265px}.lg\:w-\[380px\]{width:380px}.lg\:w-\[450px\]{width:450px}.lg\:w-full{width:100%}.lg\:max-w-5xl{max-width:64rem}.lg\:max-w-7xl{max-width:80rem}.lg\:max-w-full{max-width:100%}.lg\:max-w-md{max-width:28rem}.lg\:max-w-xl{max-width:36rem}.lg\:rotate-\[143deg\]{--tw-rotate:143deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:flex-col{flex-direction:column}.lg\:items-start{align-items:flex-start}.lg\:items-center{align-items:center}.lg\:justify-start{justify-content:flex-start}.lg\:justify-end{justify-content:flex-end}.lg\:gap-16{gap:4rem}.lg\:gap-20{gap:5rem}.lg\:gap-32{gap:8rem}.lg\:gap-5{gap:1.25rem}.lg\:gap-6{gap:1.5rem}.lg\:px-0{padding-left:0;padding-right:0}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-20{padding-top:5rem;padding-bottom:5rem}.lg\:py-36{padding-top:9rem;padding-bottom:9rem}.lg\:pb-48{padding-bottom:12rem}.lg\:pb-52{padding-bottom:13rem}.lg\:pb-56{padding-bottom:14rem}.lg\:pr-11{padding-right:2.75rem}.lg\:pt-24{padding-top:6rem}.lg\:pt-36{padding-top:9rem}.lg\:pt-72{padding-top:18rem}.lg\:text-left{text-align:left}.lg\:text-center{text-align:center}.lg\:text-5xl{font-size:3rem;line-height:1}.lg\:text-\[100px\]{font-size:100px}.lg\:text-\[28px\]{font-size:28px}.lg\:text-base{font-size:1rem;line-height:1.5rem}}@media (min-width:1280px){.xl\:absolute{position:absolute}.xl\:-bottom-56{bottom:-14rem}.xl\:-bottom-64{bottom:-16rem}.xl\:-bottom-\[80\%\]{bottom:-80%}.xl\:-left-12{left:-3rem}.xl\:-left-8{left:-2rem}.xl\:-right-\[25\%\]{right:-25%}.xl\:left-9{left:2.25rem}.xl\:right-\[10\%\]{right:10%}.xl\:right-auto{right:auto}.xl\:top-0{top:0}.xl\:top-56{top:14rem}.xl\:top-\[120\%\]{top:120%}.xl\:col-span-2{grid-column:span 2/span 2}.xl\:float-left{float:left}.xl\:-mt-32{margin-top:-8rem}.xl\:mr-6{margin-right:1.5rem}.xl\:mt-0{margin-top:0}.xl\:mt-16{margin-top:4rem}.xl\:mt-5{margin-top:1.25rem}.xl\:block{display:block}.xl\:flex{display:flex}.xl\:hidden{display:none}.xl\:h-\[310px\]{height:310px}.xl\:w-32{width:8rem}.xl\:w-44{width:11rem}.xl\:w-56{width:14rem}.xl\:w-60{width:15rem}.xl\:w-64{width:16rem}.xl\:w-\[310px\]{width:310px}.xl\:w-auto{width:auto}.xl\:w-full{width:100%}.xl\:max-w-6xl{max-width:72rem}.xl\:max-w-7xl{max-width:80rem}.xl\:max-w-\[800px\]{max-width:800px}.xl\:max-w-md{max-width:28rem}.xl\:max-w-prose{max-width:65ch}.xl\:max-w-sm{max-width:24rem}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:flex-row{flex-direction:row}.xl\:items-center{align-items:center}.xl\:justify-center{justify-content:center}.xl\:gap-12{gap:3rem}.xl\:gap-16{gap:4rem}.xl\:gap-28{gap:7rem}.xl\:gap-4{gap:1rem}.xl\:gap-8{gap:2rem}.xl\:place-self-end{place-self:end}.xl\:rounded-\[40px\]{border-radius:40px}.xl\:p-5{padding:1.25rem}.xl\:px-6{padding-left:1.5rem;padding-right:1.5rem}.xl\:py-28{padding-top:7rem;padding-bottom:7rem}.xl\:py-56{padding-top:14rem;padding-bottom:14rem}.xl\:pb-28{padding-bottom:7rem}.xl\:pb-36{padding-bottom:9rem}.xl\:pb-72{padding-bottom:18rem}.xl\:text-\[32px\]{font-size:32px}.xl\:text-lg{font-size:1.125rem;line-height:1.75rem}.xl\:leading-10{line-height:2.5rem}.\32xl\:-bottom-72{bottom:-18rem}.\32xl\:-right-24{right:-6rem}.\32xl\:bottom-14{bottom:3.5rem}.\32xl\:left-32{left:8rem}.\32xl\:right-20{right:5rem}.\32xl\:right-\[9\%\]{right:9%}.\32xl\:-ml-32{margin-left:-8rem}.\32xl\:-mt-2{margin-top:-.5rem}.\32xl\:block{display:block}.\32xl\:hidden{display:none}.\32xl\:w-1\/3{width:33.333333%}.\32xl\:w-52{width:13rem}.\32xl\:w-96{width:24rem}.\32xl\:w-\[325px\]{width:325px}.\32xl\:max-w-3xl{max-width:48rem}.\32xl\:max-w-md{max-width:28rem}.\32xl\:shrink-0{flex-shrink:0}.\32xl\:flex-row{flex-direction:row}.\32xl\:gap-20{gap:5rem}.\32xl\:gap-28{gap:7rem}.\32xl\:gap-40{gap:10rem}.\32xl\:pb-56{padding-bottom:14rem}.\32xl\:text-lg{font-size:1.125rem;line-height:1.75rem}}
\ No newline at end of file
diff --git a/config.toml b/config.toml
deleted file mode 100644
index e36c23b2..00000000
--- a/config.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-defaultContentLanguage = "en"
-title = "Open Elements"
-baseURL = "https://open-elements.com"
-
-enableRobotsTXT = true
-log = true
-logFile = "hugo-build.log"
-enableGitInfo = true
-
-[languages.en]
-weight = 1
-languageCode = "en-us"
-languageName = "EN"
-[languages.en.params]
-description = "Open Source made right - Open Elements is a modern company with a clear focus on Open Source and Java"
-
-[languages.de]
-weight = 2
-languageCode = "de"
-languageName = "DE"
-[languages.de.params]
-description = "Open Source, aber richtig - Open Elements ist ein modernes Unternehmen mit einem Fokus auf Open Source und Java"
-
-[markup.goldmark.renderer]
-unsafe = true
-
-[permalinks.page]
-posts = '/posts/:year/:month/:day/:slug/'
-[permalinks.section]
-posts = '/posts'
diff --git a/content/posts/2011-08-04-preview-multitouch-gestures-in-swing.md b/content/posts/2011-08-04-preview-multitouch-gestures-in-swing.md
index d5367882..322755d8 100644
--- a/content/posts/2011-08-04-preview-multitouch-gestures-in-swing.md
+++ b/content/posts/2011-08-04-preview-multitouch-gestures-in-swing.md
@@ -1,31 +1,27 @@
----
-outdated: true
-showInBlog: false
-title: 'Preview: Multitouch gestures in swing'
-date: "2011-08-04"
-author: hendrik
-categories: [General]
-excerpt: 'Apple added a listener based API for multitouch gestures to their eawt package. With this wrapper API you can easily integrate it in any app.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In my last [post]({{< ref "/posts/2011-07-28-fun-with-gestures" >}}) I described Apples gestures API. Up to date I´m developing a wrapper API. With this API you can add multitouch-listeners to any swing component. On any OS unlike Mac OS a `GesturesNotSupportedException` is thrown if you try to register a listener. So you can use the API in every application. If the Applications runs on a Mac it supports gestures.
-
-Here is how:
-
-{{< highlight java >}}
-try {
- GestureUtilities.add(panel, gestureRotationListener);
-} catch (GesturesNotSupportedException e) {
- System.out.println("Gestures-API not Supported!");
-}
-{{< / highlight >}}
-
-Or you can just check if the Apple API is supported:
-
-{{< highlight java >}}
-if(!GestureUtilities.isSupported()) {
- System.out.println("Gestures-API not Supported!");
-}
-{{< / highlight >}}
-
-I will add javadoc to the source and update the gestures demo next week. You can check out the source @ [https://code.google.com/p/gestures-wrapper/](https://code.google.com/p/gestures-wrapper/).
+---
+outdated: true
+showInBlog: false
+title: 'Preview: Multitouch gestures in swing'
+date: "2011-08-04"
+author: hendrik
+categories: [General]
+excerpt: 'Apple added a listener based API for multitouch gestures to their eawt package. With this wrapper API you can easily integrate it in any app.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In my last [post](/posts/2011-07-28-fun-with-gestures) I described Apples gestures API. Up to date I´m developing a wrapper API. With this API you can add multitouch-listeners to any swing component. On any OS unlike Mac OS a `GesturesNotSupportedException` is thrown if you try to register a listener. So you can use the API in every application. If the Applications runs on a Mac it supports gestures.
+
+Here is how:
+
+```javatry {
+ GestureUtilities.add(panel, gestureRotationListener);
+} catch (GesturesNotSupportedException e) {
+ System.out.println("Gestures-API not Supported!");
+}
```
+
+Or you can just check if the Apple API is supported:
+
+```javaif(!GestureUtilities.isSupported()) {
+ System.out.println("Gestures-API not Supported!");
+}
```
+
+I will add javadoc to the source and update the gestures demo next week. You can check out the source @ [https://code.google.com/p/gestures-wrapper/](https://code.google.com/p/gestures-wrapper/).
diff --git a/content/posts/2011-09-01-gesture-wrapper-0-1-released.md b/content/posts/2011-09-01-gesture-wrapper-0-1-released.md
index 353e088a..5896c163 100644
--- a/content/posts/2011-09-01-gesture-wrapper-0-1-released.md
+++ b/content/posts/2011-09-01-gesture-wrapper-0-1-released.md
@@ -12,4 +12,4 @@ The Gesture Wrapper API is a wrapper around the Apple multitouch gestures API. I
You can download the jar and documentation [here]({{ site.baseurl }}{% link pages/projects/gesture-wrapper.md %}).
-I posted a short [tutorial]({{< ref "/posts/2011-08-04-preview-multitouch-gestures-in-swing" >}}).
+I posted a short [tutorial](/posts/2011-08-04-preview-multitouch-gestures-in-swing).
diff --git a/content/posts/2011-09-12-garagetunes-demo.md b/content/posts/2011-09-12-garagetunes-demo.md
index 358f7f85..fa2984d4 100644
--- a/content/posts/2011-09-12-garagetunes-demo.md
+++ b/content/posts/2011-09-12-garagetunes-demo.md
@@ -10,4 +10,4 @@ preview_image: "/posts/preview-images/software-development-green.svg"
---
I created a new demo for my JGrid talk this week in Münster, Germany. I will release the code, a webstart link & my presentation later this week.
-{{< youtube 3aCDywUeTw4 >}}
+
diff --git a/content/posts/2011-09-14-jgrid-tutorial-1.md b/content/posts/2011-09-14-jgrid-tutorial-1.md
index c94c8521..12a5a974 100644
--- a/content/posts/2011-09-14-jgrid-tutorial-1.md
+++ b/content/posts/2011-09-14-jgrid-tutorial-1.md
@@ -1,41 +1,35 @@
----
-outdated: true
-showInBlog: false
-title: 'JGrid Tutorial #1'
-date: "2011-09-14"
-author: hendrik
-categories: [Swing]
-excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the first out of five tutorials.'
-slug: jgrid-tutorial-1
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-At the moment all JGrid demonstrations are very complex and use a lot of Java2D code, web services an so on. So many people asked me to create some simple demos. For this reason I started some bottom-up tutorials for the JGrid.
-
-Here is the first one:
-You can integrate a JGrid in every swing application. Just add it to a container:
-
-{{< highlight java >}}
-JGrid grid = new JGrid();
-getContentPane().add(new JScrollPane(grid));
-{{< / highlight >}}
-
-Normally you want to visualize some data in the grid. All data must wrapped in a ListModel:
-
-{{< highlight java >}}
-DefaultListModel model = new DefaultListModel();
-for(int i=0; i < 100; i++) {
- model.addElement(new Integer(i));
-}
-{{< / highlight >}}
-
-In a final step you must set the model for the grid:
-
-{{< highlight java >}}
-grid.setModel(model);
-{{< / highlight >}}
-
-With this few lines of code you can add a JGrid to your code. Because the default renderer of the grid uses a label and renders the `toString()`-result of the data to the grid you will see all Integers in a grid:
-
-
-
-You can download the [source file for the tutorial](/assets/downloads/jgrid/tutorial1.java). To run the program you need the jgrid.jar in your classpath.
+---
+outdated: true
+showInBlog: false
+title: 'JGrid Tutorial #1'
+date: "2011-09-14"
+author: hendrik
+categories: [Swing]
+excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the first out of five tutorials.'
+slug: jgrid-tutorial-1
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+At the moment all JGrid demonstrations are very complex and use a lot of Java2D code, web services an so on. So many people asked me to create some simple demos. For this reason I started some bottom-up tutorials for the JGrid.
+
+Here is the first one:
+You can integrate a JGrid in every swing application. Just add it to a container:
+
+```javaJGrid grid = new JGrid();
+getContentPane().add(new JScrollPane(grid));
```
+
+Normally you want to visualize some data in the grid. All data must wrapped in a ListModel:
+
+```javaDefaultListModel model = new DefaultListModel();
+for(int i=0; i < 100; i++) {
+ model.addElement(new Integer(i));
+}
```
+
+In a final step you must set the model for the grid:
+
+```javagrid.setModel(model);
```
+
+With this few lines of code you can add a JGrid to your code. Because the default renderer of the grid uses a label and renders the `toString()`-result of the data to the grid you will see all Integers in a grid:
+
+
+
+You can download the [source file for the tutorial](/assets/downloads/jgrid/tutorial1.java). To run the program you need the jgrid.jar in your classpath.
diff --git a/content/posts/2011-09-16-jgrid-tutorial-2.md b/content/posts/2011-09-16-jgrid-tutorial-2.md
index f52526eb..a2c5983e 100644
--- a/content/posts/2011-09-16-jgrid-tutorial-2.md
+++ b/content/posts/2011-09-16-jgrid-tutorial-2.md
@@ -1,32 +1,30 @@
----
-outdated: true
-showInBlog: false
-title: 'JGrid Tutorial #2'
-date: "2011-09-16"
-author: hendrik
-categories: [Swing]
-excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the second out of five tutorials.'
-slug: jgrid-tutorial-2
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-After we created a simple JGrid (see [tutorial #1]({{< ref "/posts/2011-09-14-jgrid-tutorial-1" >}}) we want to modify the look now. The JGrid has a lot of getter/setter to change the visualization of the grid. Read the JavaDoc for a complete overview of all properties.
-
-Here is an example of changing colors and dimensions:
-
-{{< highlight java >}}
-grid.setFont(grid.getFont().deriveFont(40.0f));
-grid.setFixedCellDimension(56);
-grid.setHorizonztalMargin(4);
-grid.setVerticalMargin(4);
-grid.setHorizontalAlignment(SwingConstants.LEFT);
-grid.setBackground(Color.WHITE);
-grid.setSelectionBorderColor(Color.BLUE);
-grid.setSelectionBackground(Color.CYAN);
-grid.setCellBackground(Color.LIGHT_GRAY);
-{{< / highlight >}}
-
-After setting all properties the grid looks like this:
-
-
-
-You can download the sources for the tutorial [here](/assets/downloads/jgrid/tutorial2.java).
+---
+outdated: true
+showInBlog: false
+title: 'JGrid Tutorial #2'
+date: "2011-09-16"
+author: hendrik
+categories: [Swing]
+excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the second out of five tutorials.'
+slug: jgrid-tutorial-2
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+After we created a simple JGrid (see [tutorial #1](/posts/2011-09-14-jgrid-tutorial-1) we want to modify the look now. The JGrid has a lot of getter/setter to change the visualization of the grid. Read the JavaDoc for a complete overview of all properties.
+
+Here is an example of changing colors and dimensions:
+
+```javagrid.setFont(grid.getFont().deriveFont(40.0f));
+grid.setFixedCellDimension(56);
+grid.setHorizonztalMargin(4);
+grid.setVerticalMargin(4);
+grid.setHorizontalAlignment(SwingConstants.LEFT);
+grid.setBackground(Color.WHITE);
+grid.setSelectionBorderColor(Color.BLUE);
+grid.setSelectionBackground(Color.CYAN);
+grid.setCellBackground(Color.LIGHT_GRAY);
```
+
+After setting all properties the grid looks like this:
+
+
+
+You can download the sources for the tutorial [here](/assets/downloads/jgrid/tutorial2.java).
diff --git a/content/posts/2011-09-17-jgrid-tutorial-3.md b/content/posts/2011-09-17-jgrid-tutorial-3.md
index 09b9c412..49eeefa7 100644
--- a/content/posts/2011-09-17-jgrid-tutorial-3.md
+++ b/content/posts/2011-09-17-jgrid-tutorial-3.md
@@ -1,58 +1,52 @@
----
-outdated: true
-showInBlog: false
-title: 'JGrid Tutorial #3'
-date: "2011-09-17"
-author: hendrik
-categories: [Swing]
-excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the third out of five tutorials.'
-slug: jgrid-tutorial-3
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this tutorial I will show you how to visualize more complex data with renderers. First we have to create a data model. For this tutorial we will work with the `java.awt.Color` class and create a ListModel with some colors in it:
-
-{{< highlight java >}}
-DefaultListModel model = new DefaultListModel();
-Random random = new Random();
-for(int i=0; i <= 100; i++) {
-model.addElement(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
-}
-grid.setModel(model);
-{{< / highlight >}}
-
-After assigning this model to the JGrid the result will look like this:
-
-
-
-The JGrid uses a default renderer to visualize data. This renderer based on a JLabel and displays the toString() results from the given data. Therefore you see these "java.awt.Color..." strings in the grid cells.
-
-To visualize the colors inside the grid we need a new renderer. All renderers for the JGrid must implement the interface GridCellRenderer. Here is the code for a simple renderer for colors:
-
-{{< highlight java >}}
-public class GridColorCellRenderer extends JPanel implements GridCellRenderer {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public Component getGridCellRendererComponent(JGrid grid, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- if(value != null && value instanceof Color) {
- this.setBackground((Color) value);
- }
- return this;
- }
-}
-{{< / highlight >}}
-
-Now we have to assign the renderer to the JGrid. Here is a different to the default JList or JTable behavior. The renderer for JGrid are stored in a special handler. You can refer to this handler by `grid.getCellRendererManager()` / `grid.setCellRendererManager()`. By using this handlers you can manage the same renderers for different grids (On a later JGrid release I will add SPI support to the handlers).
-
-To add the custom renderer to your grid you have to add it to the handler:
-
-{{< highlight java >}}
-grid.getCellRendererManager().setDefaultRenderer(new GridColorCellRenderer());
-{{< / highlight >}}
-
-Now our application shows the right colors inside the grid cells:
-
-
-
-You can download the source file for this tutorial [here](/assets/downloads/jgrid/tutorial3.java).
+---
+outdated: true
+showInBlog: false
+title: 'JGrid Tutorial #3'
+date: "2011-09-17"
+author: hendrik
+categories: [Swing]
+excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the third out of five tutorials.'
+slug: jgrid-tutorial-3
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this tutorial I will show you how to visualize more complex data with renderers. First we have to create a data model. For this tutorial we will work with the `java.awt.Color` class and create a ListModel with some colors in it:
+
+```javaDefaultListModel model = new DefaultListModel();
+Random random = new Random();
+for(int i=0; i <= 100; i++) {
+model.addElement(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
+}
+grid.setModel(model);
```
+
+After assigning this model to the JGrid the result will look like this:
+
+
+
+The JGrid uses a default renderer to visualize data. This renderer based on a JLabel and displays the toString() results from the given data. Therefore you see these "java.awt.Color..." strings in the grid cells.
+
+To visualize the colors inside the grid we need a new renderer. All renderers for the JGrid must implement the interface GridCellRenderer. Here is the code for a simple renderer for colors:
+
+```javapublic class GridColorCellRenderer extends JPanel implements GridCellRenderer {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Component getGridCellRendererComponent(JGrid grid, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ if(value != null && value instanceof Color) {
+ this.setBackground((Color) value);
+ }
+ return this;
+ }
+}
```
+
+Now we have to assign the renderer to the JGrid. Here is a different to the default JList or JTable behavior. The renderer for JGrid are stored in a special handler. You can refer to this handler by `grid.getCellRendererManager()` / `grid.setCellRendererManager()`. By using this handlers you can manage the same renderers for different grids (On a later JGrid release I will add SPI support to the handlers).
+
+To add the custom renderer to your grid you have to add it to the handler:
+
+```javagrid.getCellRendererManager().setDefaultRenderer(new GridColorCellRenderer());
```
+
+Now our application shows the right colors inside the grid cells:
+
+
+
+You can download the source file for this tutorial [here](/assets/downloads/jgrid/tutorial3.java).
diff --git a/content/posts/2011-09-18-jgrid-tutorial-4.md b/content/posts/2011-09-18-jgrid-tutorial-4.md
index 9b4979fc..cd2f6980 100644
--- a/content/posts/2011-09-18-jgrid-tutorial-4.md
+++ b/content/posts/2011-09-18-jgrid-tutorial-4.md
@@ -1,37 +1,35 @@
----
-outdated: true
-showInBlog: false
-title: 'JGrid Tutorial #4'
-date: "2011-09-18"
-author: hendrik
-categories: [Swing]
-excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the fourth out of five tutorials.'
-slug: jgrid-tutorial-4
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this tutorial we want to add zoom functionality to the JGrid. You can set the dimension of the grid cells be the property `fixedCellDimension`. Here is a example for two different dimensions:
-
-
-
-
-
-To add a zoom functionality to the grid you can set the dimension by using a JSlider. Here is the code:
-
-{{< highlight java >}}
-final JSlider slider = new JSlider(32, 256);
-slider.setValue(grid.getFixedCellDimension());
-
-slider.addChangeListener(new ChangeListener() {
- @Override
- public void stateChanged(ChangeEvent arg0) {
- grid.setFixedCellDimension(slider.getValue());
- }
-});
-{{< / highlight >}}
-
-Now you can edit the dimension dynamically. Here is the result:
-
-{{< youtube Zyqf-P2ftFs >}}
-
-
-You can download the source file [here](/assets/downloads/jgrid/tutorial4.java).
+---
+outdated: true
+showInBlog: false
+title: 'JGrid Tutorial #4'
+date: "2011-09-18"
+author: hendrik
+categories: [Swing]
+excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the fourth out of five tutorials.'
+slug: jgrid-tutorial-4
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this tutorial we want to add zoom functionality to the JGrid. You can set the dimension of the grid cells be the property `fixedCellDimension`. Here is a example for two different dimensions:
+
+
+
+
+
+To add a zoom functionality to the grid you can set the dimension by using a JSlider. Here is the code:
+
+```javafinal JSlider slider = new JSlider(32, 256);
+slider.setValue(grid.getFixedCellDimension());
+
+slider.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent arg0) {
+ grid.setFixedCellDimension(slider.getValue());
+ }
+});
```
+
+Now you can edit the dimension dynamically. Here is the result:
+
+
+
+
+You can download the source file [here](/assets/downloads/jgrid/tutorial4.java).
diff --git a/content/posts/2011-09-25-jgrid-tutorial-5.md b/content/posts/2011-09-25-jgrid-tutorial-5.md
index a4f992ca..f37e9926 100644
--- a/content/posts/2011-09-25-jgrid-tutorial-5.md
+++ b/content/posts/2011-09-25-jgrid-tutorial-5.md
@@ -1,78 +1,72 @@
----
-outdated: true
-showInBlog: false
-title: 'JGrid Tutorial #5'
-date: "2011-09-25"
-author: hendrik
-categories: [Swing]
-excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the fifth out of five tutorials.'
-slug: jgrid-tutorial-5
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this tutorial we want to take a deeper look at cell rendering. In the last tutorials we already implemented GridCellRenderer and set them as default renderer to the JGrid. This is exactly the same behavior as renderer in a JList. But if you have different data types in a grid only one renderer won´t fulfill the requirements. For this purpose you can add different GridCellRenderer to the JGrid. Like in a JTable you can add renderers for different data classes to the JGrid.
-
-Let´s say we have colors and percentages in our model:
-
-{{< highlight java >}}
-DefaultListModel model = new DefaultListModel();
-Random random = new Random();
-
-for(int i=0; i if(random.nextBoolean()) {
- model.addElement(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
-} else {
- model.addElement(new Float(random.nextFloat()));
-}
-
-grid.setModel(model);
-{{< / highlight >}}
-
-To visualize the color values we can use the renderer from the previous tutorial. For the new percentage values we need a different renderer:
-
-{{< highlight java >}}
-public class GridPercentCellRenderer extends JLabel implements GridCellRenderer {
-
- private static final long serialVersionUID = 1L;
-
- private float f = 0.0f;
-
- public GridPercentCellRenderer() {
- setHorizontalAlignment(SwingConstants.CENTER);
- setBackground(Color.white);
- setForeground(Color.black);
- }
-
- @Override
- public Component getGridCellRendererComponent(JGrid grid, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- if(value != null && value instanceof Float) {
- this.f = ((Float) value).floatValue();
- setText(NumberFormat.getPercentInstance().format(f));
- }
- return this;
- }
-
- @Override
- protected void paintComponent(Graphics g) {
- g.setColor(getBackground());
- g.fillRect(0, 0, getWidth(), getHeight());
- g.setColor(Color.LIGHT_GRAY);
- int height = (int)((float)getHeight() * f);
- g.fillRect(0, getHeight() - height, getWidth(), height);
- super.paintComponent(g);
- }
-}
-{{< / highlight >}}
-
-Until now all tutorials used the `setDefaultRenderer(...)` methode to set a special design to the grid. Just now we have a problem using this practice: we need renderers for different data types. In the JGrid this is as simple as in the JTable.
-
-Here we go:
-
-{{< highlight java >}}
-grid.getCellRendererManager().addRendererMapping(Color.class, new GridColorCellRenderer());
-grid.getCellRendererManager().addRendererMapping(Float.class, new GridPercentCellRenderer());
-{{< / highlight >}}
-
-Here you can see the effect:
-
-
-
-You can download the source file [here](/assets/downloads/jgrid/tutorial5.java).
+---
+outdated: true
+showInBlog: false
+title: 'JGrid Tutorial #5'
+date: "2011-09-25"
+author: hendrik
+categories: [Swing]
+excerpt: 'I created a series of tutorials to get familiar with JGrid. This is the fifth out of five tutorials.'
+slug: jgrid-tutorial-5
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this tutorial we want to take a deeper look at cell rendering. In the last tutorials we already implemented GridCellRenderer and set them as default renderer to the JGrid. This is exactly the same behavior as renderer in a JList. But if you have different data types in a grid only one renderer won´t fulfill the requirements. For this purpose you can add different GridCellRenderer to the JGrid. Like in a JTable you can add renderers for different data classes to the JGrid.
+
+Let´s say we have colors and percentages in our model:
+
+```javaDefaultListModel model = new DefaultListModel();
+Random random = new Random();
+
+for(int i=0; i if(random.nextBoolean()) {
+ model.addElement(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
+} else {
+ model.addElement(new Float(random.nextFloat()));
+}
+
+grid.setModel(model);
```
+
+To visualize the color values we can use the renderer from the previous tutorial. For the new percentage values we need a different renderer:
+
+```javapublic class GridPercentCellRenderer extends JLabel implements GridCellRenderer {
+
+ private static final long serialVersionUID = 1L;
+
+ private float f = 0.0f;
+
+ public GridPercentCellRenderer() {
+ setHorizontalAlignment(SwingConstants.CENTER);
+ setBackground(Color.white);
+ setForeground(Color.black);
+ }
+
+ @Override
+ public Component getGridCellRendererComponent(JGrid grid, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ if(value != null && value instanceof Float) {
+ this.f = ((Float) value).floatValue();
+ setText(NumberFormat.getPercentInstance().format(f));
+ }
+ return this;
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, getWidth(), getHeight());
+ g.setColor(Color.LIGHT_GRAY);
+ int height = (int)((float)getHeight() * f);
+ g.fillRect(0, getHeight() - height, getWidth(), height);
+ super.paintComponent(g);
+ }
+}
```
+
+Until now all tutorials used the `setDefaultRenderer(...)` methode to set a special design to the grid. Just now we have a problem using this practice: we need renderers for different data types. In the JGrid this is as simple as in the JTable.
+
+Here we go:
+
+```javagrid.getCellRendererManager().addRendererMapping(Color.class, new GridColorCellRenderer());
+grid.getCellRendererManager().addRendererMapping(Float.class, new GridPercentCellRenderer());
```
+
+Here you can see the effect:
+
+
+
+You can download the source file [here](/assets/downloads/jgrid/tutorial5.java).
diff --git a/content/posts/2012-10-13-building-javafx-applications-with-maven.md b/content/posts/2012-10-13-building-javafx-applications-with-maven.md
index 6ca01899..0a950e6e 100644
--- a/content/posts/2012-10-13-building-javafx-applications-with-maven.md
+++ b/content/posts/2012-10-13-building-javafx-applications-with-maven.md
@@ -1,27 +1,25 @@
----
-outdated: true
-showInBlog: false
-title: 'Building JavaFX Applications with Maven'
-date: "2012-10-13"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'With the preview of JavaFX 2 that is part of Java 6 and 7 you can already build custom JavaFX applications by using Maven'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-There are already a lot of posts out there that describe a workflow for integrating JavaFX in Maven. Here is one example by Adam Bien: [http://www.adam-bien.com/roller/abien/entry/how_to_compile_java_fx](http://www.adam-bien.com/roller/abien/entry/how_to_compile_java_fx)
-
-For all this solutions you have to specify your system-specific path to the JavaFX installation. You can set the property inside your Maven pom. This is ok for a single user environment but counterproductive when developing in a team. Another way is to set the property on OS Level. But then every developer have to do this on every workstation.
-
-Since Java 7 update 6 JavaFX 2.2 is bundled in the JRE. You can find JavaFX at `JAVAHOME/lib/jfxrt.jar`. Since Maven 3 you can access the `JAVAHOME` path with the `${java.home}` property. With this informations you are able to create a system independent pom-file:
-
-{{< highlight xml >}}
-
- com.oracle
- javafx
- 2.2
- ${java.home}/lib/jfxrt.jar
- system
-
-{{< / highlight >}}
-
-The solution is working since __Java 7u6__. If you have different JDKs / JREs installed on your system you have to start Maven with the right JDK. The pom also works in Eclipse with m2eclipse-plugin. Here you must ensure that Eclipse is started with Java 7u6+.
+---
+outdated: true
+showInBlog: false
+title: 'Building JavaFX Applications with Maven'
+date: "2012-10-13"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'With the preview of JavaFX 2 that is part of Java 6 and 7 you can already build custom JavaFX applications by using Maven'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+There are already a lot of posts out there that describe a workflow for integrating JavaFX in Maven. Here is one example by Adam Bien: [http://www.adam-bien.com/roller/abien/entry/how_to_compile_java_fx](http://www.adam-bien.com/roller/abien/entry/how_to_compile_java_fx)
+
+For all this solutions you have to specify your system-specific path to the JavaFX installation. You can set the property inside your Maven pom. This is ok for a single user environment but counterproductive when developing in a team. Another way is to set the property on OS Level. But then every developer have to do this on every workstation.
+
+Since Java 7 update 6 JavaFX 2.2 is bundled in the JRE. You can find JavaFX at `JAVAHOME/lib/jfxrt.jar`. Since Maven 3 you can access the `JAVAHOME` path with the `${java.home}` property. With this informations you are able to create a system independent pom-file:
+
+```xml
+ com.oracle
+ javafx
+ 2.2
+ ${java.home}/lib/jfxrt.jar
+ system
+
```
+
+The solution is working since __Java 7u6__. If you have different JDKs / JREs installed on your system you have to start Maven with the right JDK. The pom also works in Eclipse with m2eclipse-plugin. Here you must ensure that Eclipse is started with Java 7u6+.
diff --git a/content/posts/2012-11-01-introducing-vagrant-binding.md b/content/posts/2012-11-01-introducing-vagrant-binding.md
index 0c1732b2..82dae11f 100644
--- a/content/posts/2012-11-01-introducing-vagrant-binding.md
+++ b/content/posts/2012-11-01-introducing-vagrant-binding.md
@@ -1,212 +1,192 @@
----
-outdated: true
-showInBlog: false
-title: 'Introducing Vagrant-Binding'
-date: "2012-11-01"
-author: hendrik
-categories: [General, Vagrant-Binding]
-excerpt: ' With the Vagrant-Binding you can put the automation in Java on the next level. The library is a wrapper around Vagrant that let you easily manage virtual machines from Java code at runtime.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Today I want to introduce the [Vagrant-Binding Java API](https://github.com/guigarage/vagrant-binding). The API is build on top of the OpenSource Tool [Vagrant](http://vagrantup.com). Vagrant is a ruby based tool for virtual machine automation. With Vagrant you can set up complex virtual systems in only a few minutes. Every vm that is created with Vagrant based on a config-file that describes the configuration of the virtual machine and all installed software on it. You can configure a Ubuntu 64 bit vm with a running MySql server for example. With the Java API "Vagrant-Binding" you can put the automation on the next level.
-
-Vagrant-Binding is OpenSource and available at [github](https://github.com/guigarage/vagrant-binding). It offers some nice builder APIs so that you can programmatically set up your vm. In addition to this Vagrant-Bindings gives you the opportunity to sync the lifecycle of your virtual machines with your JUnit Unit Tests. All you need is a [VirtualBox](https://www.virtualbox.org) installation on your system.
-
-## Getting started
-
-The simplest way to start building your virtual machines in Java is the Builder-API. With a few Builder-Classes you can set up a complete environment of different virtual machines at runtime. To run all the example you need a VirtualBox installation on your system. I suggest you to use version 4.1.16 because this is the version I am currently using. I Don't know if every version is working fine with Vagrant. The actual "Vagrant-Binding" snapshot bundles Vagrant version 1.0.5. So you don't need a additional Vagrant installation on your system.
-
-Here is a short example that creates an Ubuntu 32bit vm:
-
-{{< highlight java >}}
-VagrantVmConfig vmConfig = VagrantVmConfigBuilder
-.create()
-.withLucid32Box()
-.withName("myVM")
-.build();
-
-VagrantEnvironmentConfig environmentConfig = VagrantEnvironmentConfigBuilder
-.create()
-.withVagrantVmConfig(vmConfig)
-.build();
-
-Vagrant vagrant = new Vagrant(true);
-
-VagrantEnvironment environment = vagrant
-.createEnvironment(new File("my/locale/path"), environmentConfig);
-
-environment.up();
-{{< / highlight >}}
-
-You can configure your vm by using a static ip and some port forwarding for example:
-
-{{< highlight java >}}
-VagrantPortForwarding portForwarding = new VagrantPortForwarding("custom", 7777, 1399);
-
-VagrantVmConfig vmConfig = VagrantVmConfigBuilder
-.create()
-.withLucid32Box()
-.withName("myVM").
-.withHostOnlyIp("192.168.50.4")
-.withVagrantPortForwarding(portForwarding).build();
-{{< / highlight >}}
-
-The code creates a VmConfig with some special features. This VmConfig is put into a VagrantEnvironment. One Environment can capsulate as many virtual machines as you want. You can start the whole environment by calling `environment.up()`. This creates and starts up every virtual machine that is defined in the environment within a fe minutes. If you want you can access every machine and start or stop it manually:
-
-{{< highlight java >}}
-for(VagrantVm vm : environment.getAllVms()) {
- vm.destroy();
-}
-{{< / highlight >}}
-
-Each vm has a lifecycle. You can change the state of the lifecycle easily:
-
-{{< highlight java >}}
-vm.start();
-vm.suspend();
-vm.resume();
-vm.halt();
-vm.destroy();
-{{< / highlight >}}
-
-To configure the software, which will be installed on the virtual machine you need a Puppet configuration script. [Puppet](http://puppetlabs.com) is a tool that automates the installation and administration of software. Each virtual machine that is created by Vagrant runs Puppet by default. So you only need a configuration script. Here is a simple example that edits the welcome message of a virtual machine:
-
-{{< highlight java >}}
-group { "puppet":
-ensure => "present",
-}
-
-File { owner => 0, group => 0, mode => 0644 }
-
-file { '/etc/motd':
-content => "Welcome to your Vagrant-built virtual machine!
-Managed by Puppet.\n"
-}
-{{< / highlight >}}
-
-You can easily use your puppet scripts with Vagrant-Binding:
-
-{{< highlight java >}}
-PuppetProvisionerConfig puppetConfig = PuppetProvisionerConfigBuilder
-.create()
-.withManifestPath("path/to/puppetscript")
-.withManifestFile("config.pp")
-.build();
-
-VagrantVmConfig vmConfig = VagrantVmConfigBuilder
-.create()
-.withLucid32Box()
-.withPuppetProvisionerConfig(puppetConfig)
-.build();
-{{< / highlight >}}
-
-After starting your virtual machine you can use SHH to connect on the machine. "Vagrant-Binding" provides a class for file upload and process execution over ssh. You can start your jobs on the virtual machine by simple using a code like this:
-
-{{< highlight java >}}
-VagrantSSHConnection connection = vm.createConnection();
-connection.execute("touch /path/to/any/file", true);
-{{< / highlight >}}
-
-## Using Vagrant-Binding for real sandbox testing
-
-Vagrant-Binding offers a special [@Rule for JUnit](http://www.junit.org/node/580). By using this Rule you can capsule each of your tests with a fully vm lifecycle. Let us assume we have the following Unit Test:
-
-{{< highlight java >}}
-@Test
-public void testJdbc() {
- System.out.println("Test starts");
- try {
- Class.forName("com.mysql.jdbc.Driver");
- Connection connection = DriverManager.getConnection("jdbc:mysql://192.168.50.4/testapp?user=dbuser&password=dbuser");
-
- Statement statement = connection.createStatement();
- String table = "CREATE TABLE mytable (data_entry VARCHAR(254))";
- statement.executeUpdate(table);
- statement.close();
-
- for(int i=0; i < 100; i++) {
- statement = connection.createStatement();
- statement.executeUpdate("INSERT INTO mytable VALUES(\"" + UUID.randomUUID().toString() + "\")");
- statement.close();
- }
-
- statement = connection.createStatement();
- ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) FROM mytable");
- resultSet.next();
- Assert.assertEquals(100, resultSet.getInt(1));
- statement.close();
- connection.close();
- } catch (Exception e) {
- e.printStackTrace();
- Assert.fail();
- }
-}
-{{< / highlight >}}
-
-The test creates the table "mytable", adds 100 rows into it and checks the rowcount. To run this test successfully you need a machine with the hard ip "192.168.50.4" and a MySQL Server. You need a database "testapp" on the server too. On this database there must not be a table called "mytable". So you can only run this Unit Test one time because it doesn't drop the table "mytable" at the end. You can expand the test and drop the table at the end but what will happen in case of an error? Every time the test starts automatically you do not know the state of the server, database and table. Another problem is that you can't run the test parallel.
-
-With Vagrant-Binding you can create your database server as a vm on the fly. All you need to do is adding a `VagrantTestRule` to your test class:
-
-{{< highlight java >}}
-public VagrantTestRule testRule = new VagrantTestRule(createConfig());
-{{< / highlight >}}
-
-The Rule needs a configuration that is easily created:
-
-{{< highlight java >}}
-public static VagrantConfiguration createConfig() {
- PuppetProvisionerConfig puppetConfig = PuppetProvisionerConfigBuilder
- .create()
- .withManifestPath("/path/to/manifests")
- .withManifestFile("dbserver.pp")
- .withDebug(true)
- .build();
-
- VagrantVmConfig vmConfig = VagrantVmConfigBuilder
- .create()
- .withName("mysqlvm")
- .withHostOnlyIp("192.168.50.4")
- .withBoxName("lucid32")
- .withPuppetProvisionerConfig(puppetConfig)
- .build();
-
- VagrantEnvironmentConfig environmentConfig = VagrantEnvironmentConfigBuilder
- .create()
- .withVagrantVmConfig(vmConfig)
- .build();
-
- VagrantFileTemplateConfiguration fileTemplateConfiguration = VagrantFileTemplateConfigurationBuilder
- .create()
- .withLocalFile(new File("/path/to/my.cnf"))
- .withPathInVagrantFolder("files/my.cnf")
- .build();
-
- VagrantConfiguration configuration = VagrantConfigurationBuilder
- .create()
- .withVagrantEnvironmentConfig(environmentConfig)
- .withVagrantFileTemplateConfiguration(fileTemplateConfiguration)
- .build();
-
- return configuration;
-}
-{{< / highlight >}}
-
-The "VagrantTestRule" syncs every single test with the livecycle of the Vagrant environment. Each vm that is defined in the environments starts before the UnitTests runs and stops after the test:
-
-
-
-You can access the environment and execute commands on the virtual machines by SSH for example while the test is running by calling "testRule.getEnvironment()".
-
-I'm using a Puppet script that I found on [github](https://github.com/moolsan/vagrant-puppet-demo) to configure the database server vm with Puppet.
-
-I will host a project with some demos and tutorials within the next days on github. You need to download and install the Vagrant-Binding project as maven dependency because it is not available at Maven Central Repository at the moment.
-
-## Current state of the project and some limitations
-
-The API is in a very early state. I haven't even tried everything until today and there are only a few Unit Tests. There is currently no existing javadoc and only some simple examples. So please do not use this API in production - at the moment :)
-
-There is a [jruby bug](https://github.com/jarib/childprocess/issues/26) on windows 64 bit so that Vagrant-Binding is actually not working there.
-
-## Further reading
-
-Vagrant has a very good [quickstart](http://vagrantup.com/v1/docs/getting-started/index.html) and [documentation](http://vagrantup.com/v1/docs/index.html). All of the features I implemented until today are strongly adopted from Vagrant. There are are lot of [good](http://www.javacodegeeks.com/2012/08/introduction-to-puppet-for-vagrant-users.html) [Puppet](https://github.com/moolsan/vagrant-puppet-demo) [examples](http://www.tomcatexpert.com/blog/2010/04/29/deploying-tomcat-applications-puppet) [out](http://www.javacodegeeks.com/2012/06/serving-files-with-puppet-standalone-in.html) [there](http://blog.codecentric.de/en/2012/02/automated-virtual-test-environments-with-vagrant-and-puppet/). I read ["Pulling Strings With Puppet"](http://www.amazon.de/Pulling-Strings-With-Puppet-Configuration/dp/1590599780/ref=sr_1_7?ie=UTF8&qid=1351633216&sr=8-7) that helped me a lot.
+---
+outdated: true
+showInBlog: false
+title: 'Introducing Vagrant-Binding'
+date: "2012-11-01"
+author: hendrik
+categories: [General, Vagrant-Binding]
+excerpt: ' With the Vagrant-Binding you can put the automation in Java on the next level. The library is a wrapper around Vagrant that let you easily manage virtual machines from Java code at runtime.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Today I want to introduce the [Vagrant-Binding Java API](https://github.com/guigarage/vagrant-binding). The API is build on top of the OpenSource Tool [Vagrant](http://vagrantup.com). Vagrant is a ruby based tool for virtual machine automation. With Vagrant you can set up complex virtual systems in only a few minutes. Every vm that is created with Vagrant based on a config-file that describes the configuration of the virtual machine and all installed software on it. You can configure a Ubuntu 64 bit vm with a running MySql server for example. With the Java API "Vagrant-Binding" you can put the automation on the next level.
+
+Vagrant-Binding is OpenSource and available at [github](https://github.com/guigarage/vagrant-binding). It offers some nice builder APIs so that you can programmatically set up your vm. In addition to this Vagrant-Bindings gives you the opportunity to sync the lifecycle of your virtual machines with your JUnit Unit Tests. All you need is a [VirtualBox](https://www.virtualbox.org) installation on your system.
+
+## Getting started
+
+The simplest way to start building your virtual machines in Java is the Builder-API. With a few Builder-Classes you can set up a complete environment of different virtual machines at runtime. To run all the example you need a VirtualBox installation on your system. I suggest you to use version 4.1.16 because this is the version I am currently using. I Don't know if every version is working fine with Vagrant. The actual "Vagrant-Binding" snapshot bundles Vagrant version 1.0.5. So you don't need a additional Vagrant installation on your system.
+
+Here is a short example that creates an Ubuntu 32bit vm:
+
+```javaVagrantVmConfig vmConfig = VagrantVmConfigBuilder
+.create()
+.withLucid32Box()
+.withName("myVM")
+.build();
+
+VagrantEnvironmentConfig environmentConfig = VagrantEnvironmentConfigBuilder
+.create()
+.withVagrantVmConfig(vmConfig)
+.build();
+
+Vagrant vagrant = new Vagrant(true);
+
+VagrantEnvironment environment = vagrant
+.createEnvironment(new File("my/locale/path"), environmentConfig);
+
+environment.up();
```
+
+You can configure your vm by using a static ip and some port forwarding for example:
+
+```javaVagrantPortForwarding portForwarding = new VagrantPortForwarding("custom", 7777, 1399);
+
+VagrantVmConfig vmConfig = VagrantVmConfigBuilder
+.create()
+.withLucid32Box()
+.withName("myVM").
+.withHostOnlyIp("192.168.50.4")
+.withVagrantPortForwarding(portForwarding).build();
```
+
+The code creates a VmConfig with some special features. This VmConfig is put into a VagrantEnvironment. One Environment can capsulate as many virtual machines as you want. You can start the whole environment by calling `environment.up()`. This creates and starts up every virtual machine that is defined in the environment within a fe minutes. If you want you can access every machine and start or stop it manually:
+
+```javafor(VagrantVm vm : environment.getAllVms()) {
+ vm.destroy();
+}
```
+
+Each vm has a lifecycle. You can change the state of the lifecycle easily:
+
+```javavm.start();
+vm.suspend();
+vm.resume();
+vm.halt();
+vm.destroy();
```
+
+To configure the software, which will be installed on the virtual machine you need a Puppet configuration script. [Puppet](http://puppetlabs.com) is a tool that automates the installation and administration of software. Each virtual machine that is created by Vagrant runs Puppet by default. So you only need a configuration script. Here is a simple example that edits the welcome message of a virtual machine:
+
+```javagroup { "puppet":
+ensure => "present",
+}
+
+File { owner => 0, group => 0, mode => 0644 }
+
+file { '/etc/motd':
+content => "Welcome to your Vagrant-built virtual machine!
+Managed by Puppet.\n"
+}
```
+
+You can easily use your puppet scripts with Vagrant-Binding:
+
+```javaPuppetProvisionerConfig puppetConfig = PuppetProvisionerConfigBuilder
+.create()
+.withManifestPath("path/to/puppetscript")
+.withManifestFile("config.pp")
+.build();
+
+VagrantVmConfig vmConfig = VagrantVmConfigBuilder
+.create()
+.withLucid32Box()
+.withPuppetProvisionerConfig(puppetConfig)
+.build();
```
+
+After starting your virtual machine you can use SHH to connect on the machine. "Vagrant-Binding" provides a class for file upload and process execution over ssh. You can start your jobs on the virtual machine by simple using a code like this:
+
+```javaVagrantSSHConnection connection = vm.createConnection();
+connection.execute("touch /path/to/any/file", true);
```
+
+## Using Vagrant-Binding for real sandbox testing
+
+Vagrant-Binding offers a special [@Rule for JUnit](http://www.junit.org/node/580). By using this Rule you can capsule each of your tests with a fully vm lifecycle. Let us assume we have the following Unit Test:
+
+```java@Test
+public void testJdbc() {
+ System.out.println("Test starts");
+ try {
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection connection = DriverManager.getConnection("jdbc:mysql://192.168.50.4/testapp?user=dbuser&password=dbuser");
+
+ Statement statement = connection.createStatement();
+ String table = "CREATE TABLE mytable (data_entry VARCHAR(254))";
+ statement.executeUpdate(table);
+ statement.close();
+
+ for(int i=0; i < 100; i++) {
+ statement = connection.createStatement();
+ statement.executeUpdate("INSERT INTO mytable VALUES(\"" + UUID.randomUUID().toString() + "\")");
+ statement.close();
+ }
+
+ statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) FROM mytable");
+ resultSet.next();
+ Assert.assertEquals(100, resultSet.getInt(1));
+ statement.close();
+ connection.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail();
+ }
+}
```
+
+The test creates the table "mytable", adds 100 rows into it and checks the rowcount. To run this test successfully you need a machine with the hard ip "192.168.50.4" and a MySQL Server. You need a database "testapp" on the server too. On this database there must not be a table called "mytable". So you can only run this Unit Test one time because it doesn't drop the table "mytable" at the end. You can expand the test and drop the table at the end but what will happen in case of an error? Every time the test starts automatically you do not know the state of the server, database and table. Another problem is that you can't run the test parallel.
+
+With Vagrant-Binding you can create your database server as a vm on the fly. All you need to do is adding a `VagrantTestRule` to your test class:
+
+```javapublic VagrantTestRule testRule = new VagrantTestRule(createConfig());
```
+
+The Rule needs a configuration that is easily created:
+
+```javapublic static VagrantConfiguration createConfig() {
+ PuppetProvisionerConfig puppetConfig = PuppetProvisionerConfigBuilder
+ .create()
+ .withManifestPath("/path/to/manifests")
+ .withManifestFile("dbserver.pp")
+ .withDebug(true)
+ .build();
+
+ VagrantVmConfig vmConfig = VagrantVmConfigBuilder
+ .create()
+ .withName("mysqlvm")
+ .withHostOnlyIp("192.168.50.4")
+ .withBoxName("lucid32")
+ .withPuppetProvisionerConfig(puppetConfig)
+ .build();
+
+ VagrantEnvironmentConfig environmentConfig = VagrantEnvironmentConfigBuilder
+ .create()
+ .withVagrantVmConfig(vmConfig)
+ .build();
+
+ VagrantFileTemplateConfiguration fileTemplateConfiguration = VagrantFileTemplateConfigurationBuilder
+ .create()
+ .withLocalFile(new File("/path/to/my.cnf"))
+ .withPathInVagrantFolder("files/my.cnf")
+ .build();
+
+ VagrantConfiguration configuration = VagrantConfigurationBuilder
+ .create()
+ .withVagrantEnvironmentConfig(environmentConfig)
+ .withVagrantFileTemplateConfiguration(fileTemplateConfiguration)
+ .build();
+
+ return configuration;
+}
```
+
+The "VagrantTestRule" syncs every single test with the livecycle of the Vagrant environment. Each vm that is defined in the environments starts before the UnitTests runs and stops after the test:
+
+
+
+You can access the environment and execute commands on the virtual machines by SSH for example while the test is running by calling "testRule.getEnvironment()".
+
+I'm using a Puppet script that I found on [github](https://github.com/moolsan/vagrant-puppet-demo) to configure the database server vm with Puppet.
+
+I will host a project with some demos and tutorials within the next days on github. You need to download and install the Vagrant-Binding project as maven dependency because it is not available at Maven Central Repository at the moment.
+
+## Current state of the project and some limitations
+
+The API is in a very early state. I haven't even tried everything until today and there are only a few Unit Tests. There is currently no existing javadoc and only some simple examples. So please do not use this API in production - at the moment :)
+
+There is a [jruby bug](https://github.com/jarib/childprocess/issues/26) on windows 64 bit so that Vagrant-Binding is actually not working there.
+
+## Further reading
+
+Vagrant has a very good [quickstart](http://vagrantup.com/v1/docs/getting-started/index.html) and [documentation](http://vagrantup.com/v1/docs/index.html). All of the features I implemented until today are strongly adopted from Vagrant. There are are lot of [good](http://www.javacodegeeks.com/2012/08/introduction-to-puppet-for-vagrant-users.html) [Puppet](https://github.com/moolsan/vagrant-puppet-demo) [examples](http://www.tomcatexpert.com/blog/2010/04/29/deploying-tomcat-applications-puppet) [out](http://www.javacodegeeks.com/2012/06/serving-files-with-puppet-standalone-in.html) [there](http://blog.codecentric.de/en/2012/02/automated-virtual-test-environments-with-vagrant-and-puppet/). I read ["Pulling Strings With Puppet"](http://www.amazon.de/Pulling-Strings-With-Puppet-Configuration/dp/1590599780/ref=sr_1_7?ie=UTF8&qid=1351633216&sr=8-7) that helped me a lot.
diff --git a/content/posts/2012-11-13-jgridfx-first-demo.md b/content/posts/2012-11-13-jgridfx-first-demo.md
index 8727afbd..a75f5cc4 100644
--- a/content/posts/2012-11-13-jgridfx-first-demo.md
+++ b/content/posts/2012-11-13-jgridfx-first-demo.md
@@ -8,8 +8,8 @@ categories: [JavaFX]
excerpt: 'This is the first demo of GridFX - the successor of JGrid.'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-Greetings from[Devoxx](http://www.devoxx.com). I'm currently porting the [JGrid]({{< ref "/posts/2011-07-15-jgrid" >}}) project to JavaFX. Here is a first preview:
+Greetings from[Devoxx](http://www.devoxx.com). I'm currently porting the [JGrid](/posts/2011-07-15-jgrid) project to JavaFX. Here is a first preview:
-{{< vimeo 53374280 >}}
+
I will release the first sources later this week.
diff --git a/content/posts/2012-11-14-playing-with-gridfx-and-itunes-webservices.md b/content/posts/2012-11-14-playing-with-gridfx-and-itunes-webservices.md
index fce4cd09..2f2e296c 100644
--- a/content/posts/2012-11-14-playing-with-gridfx-and-itunes-webservices.md
+++ b/content/posts/2012-11-14-playing-with-gridfx-and-itunes-webservices.md
@@ -10,5 +10,5 @@ preview_image: "/posts/preview-images/software-development-green.svg"
---
I started a second demo for the [GridFX]({{ site.baseurl }}{% link pages/projects/gridfx.md %}) component. The demo let you search for movie trailers and watch them. Therefore I used the [iTunes REST API](http://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html) and a JavaFX [MediaView](http://docs.oracle.com/javafx/2/media/simpleplayer.htm) in combination with the GridFX. Here is a short movie:
-{{< vimeo 53462905 >}}
+
diff --git a/content/posts/2012-11-17-custom-ui-controls-with-javafx-part-1.md b/content/posts/2012-11-17-custom-ui-controls-with-javafx-part-1.md
index 4a116046..8181659d 100644
--- a/content/posts/2012-11-17-custom-ui-controls-with-javafx-part-1.md
+++ b/content/posts/2012-11-17-custom-ui-controls-with-javafx-part-1.md
@@ -1,147 +1,131 @@
----
-outdated: true
-showInBlog: false
-title: 'Custom UI Controls with JavaFX - Part 1'
-date: "2012-11-17"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'One thing I often done is Swing was customization of components and the creation of new components types. With the last release of JavaFX you can easily create custom controls with this new UI toolkit, too. This post gives a first overview about the JavaFX APIs to create custom controls.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-One thing I often done is Swing was customization of components and the creation of new components types. One example for this is the [JGrid]({{< ref "/posts/2011-07-15-jgrid" >}}). Since JavaFX was out I wanted to [port the JGrid to it]({{< ref "/posts/2012-11-14-gridfx-is-hosted-at-github" >}}). After some experiments and bad prototyps I think I found the right way to do it. The talks from [Gerrit Grunwald](http://harmoniccode.blogspot.de) and [Jonathan Giles](http://jonathangiles.net/blog/) at [JavaOne](http://www.oracle.com/javaone/index.html) helped me really a lot to do so. The records of this talks is online ([link](https://oracleus.activeevents.com/connect/sessionDetail.ww?SESSION_ID=2425&tclass=popup), [link](https://oracleus.activeevents.com/connect/sessionDetail.ww?SESSION_ID=4726&tclass=popup)) so I would advise everybody who is interest in this topic to spend some time and watch them.
-
-## Getting started
-
-Every UI component in JavaFX is composed by a __control__, a __skin__ and a __behavior__. In an ideal case there is a css part to.
-
-
-
-Best way to start is by creating a new control class that extends `javafx.scene.control.Control`. This class is basically comparable to `JComponent`. It should hold the properties of the component and acts as the main class for it because instances of this class will later created in your application code and added to the UI tree.
-
-{{< highlight java >}}
-MyCustomControl myControl = new MyCustomControl();
-panel.getChildren().add(myControl);
-{{< / highlight >}}
-
-When programming swing components the right way you put everything that depends on the visualization or user interaction into a UI class (see `LabelUI` for example). JavaFX goes one step further and provides the skin class for all visualization and layout related code and the behavior class for all user interaction.
-
-
-
-To do so in JavaFX you need to know how the classes depends on each other. Here is a short chart that shows the relations between them:
-
-
-
-## Creating the Behavior
-
-If your component only visualizes data and has no interaction it 's quite simple to create a behavior. Therefore you only need to extend the `com.sun.javafx.scene.control.behavior.BehaviorBase`.
-
-{{< highlight java >}}
-public class MyCustomControlBehavior extends BehaviorBase {
-
- public MyCustomControlBehavior(MyCustomControl control) {
- super(control);
- }
-}
-{{< / highlight >}}
-
-Some of you may be confused when seeing the package of BehaviorBase. At the moment this is a __private API__ and normally you should not use this classes in your code but the guys at Oracle know about this problem and will provide the __BehaviorBase as a public API with JavaFX 8__. So best practice is to use the private class now and refactor the import once Java 8 is out.
-
-## Creating the Skin
-
-After the behavior class is created we can take a look at the skin. Your skin class will mostly extend `com.sun.javafx.scene.control.skin.BaseSkin` and create a new behavior for your control. Your code normally should look like this:
-
-{{< highlight java >}}
-public class MyCustomControlSkin extends SkinBase{
-
- public MyCustomControlSkin(MyCustomControl control) {
- super(control, new MyCustomControlBehavior(control));
- }
-}
-{{< / highlight >}}
-
-As you can see the BaseSkin is a private API as well. It will also changed to public with Java 8.
-
-## Creating the Control
-
-The last class we will need is the control. First we create a simple empty class:
-
-{{< highlight java >}}
-public class MyCustomControl extends Control {
-
- public MyCustomControl() {
- }
-}
-{{< / highlight >}}
-
-At this point we have a leak in the dependencies of our three classes. The skin knows about the behavior and control. Here everything looks right. However in application code you will simply create a new control and use it as I showed earlier. The problem is that the control class do not know anything about the skin or behavior. This was one of the biggest pitfalls I was confronted with while learning JavaFX.
-
-## Putting it together
-
-What first looks as a great problem is part of the potency JavaFX provides. With JavaFX it should be very easy to create different visualisation (skins) for controls. For this part you can customize the look of components by css. Because the skin is the main part of this look it has to defined by css, too. So instead of creating a skin object for the control by your own you only define the skin class that should be used for your control. The instanciation and everything else is automatically done by the JavaFX APIs. To do so you have to bind your control to a css class.
-
-Firts off all you have to create a new css file in your project. I think best practice is to use the same package as the controls has and but a css file under src/main/resource:
-
-
-
-Inside the css you have to specify a new selector for your component and add the skin as a property to it. This will for example look like this:
-
-{{< highlight css >}}
-.custom-control {
- -fx-skin: "com.guigarage.customcontrol.MyCustomControlSkin";
-}
-{{< / highlight >}}
-
-Once you have created the css you have to define it in your control. Therefore you have to configure the path to the css file and the selector of your component:
-
-{{< highlight java >}}
-public class MyCustomControl extends Control {
-
- public MyCustomControl() {
- getStyleClass().add("custom-control");
- }
-
- @Override
- protected String getUserAgentStylesheet() {
- return MyCustomControl.class.getResource("customcontrol.css").toExternalForm();
- }
-}
-{{< / highlight >}}
-
-After all this stuff is done correctly JavaFX will create a skin instance for your control. You do not need to take care about this instantiation or the dependency mechanism. At this point I want to thank [Jonathan Giles](http://jonathangiles.net/blog/) who taked some time to code the css integration for gridfx together with me and explained me all the mechanisms and benefits.
-
-## Access the Skin and Behavior
-
-Normally there is no need to access the skin or the behavior from within the controller. But if you have the need to do you can access them this way:
-
-
-
-Because controler.getSkin() receives a javafx.scene.control.Skin and not a SkinBase you have to cast it if you need the Behavior:
-
-{{< highlight java >}}
-((SkinBase)getSkin()).getBehavior();
-{{< / highlight >}}
-
-## Workaround for css haters
-
-For some of you this mechanism seems to be a little to oversized. Maybe you only need a specific control once in your application and you do not plan to skin it with css and doing all this stuff. For this use case there is a nice workaround in the JavaFX API. You can ignore all the css stuff and set the skin class to your control in code:
-
-{{< highlight java >}}
-public class MyCustomControl extends Control {
- public MyCustomControl() {
- setSkinClassName(MyCustomControlSkin.class.getName());
- }
-}
-{{< / highlight >}}
-
-The benefit of this workflow is that refactoring of packages or classnames don't break your code and you don't need a extra css file. On the other side there is a great handicap. You can't use css defined skins in any extension of this control. __I think that every public API like gridfx should use the css way__. In some internal use cases the hard coded way could be faster.
-
-## Conclusion
-
-Now we created a control, a skin and a behavior that are working fine and can be added to your UI tree. But like in swing when simply extending the JComponent you don't see anything on screen. So the next step is to style and layout your component. I will handle this topic in my next post.
-
-If you want to look at some code of existing custom components check out [jgridfx](https://github.com/guigarage/gridfx) or [JFXtras](https://github.com/JFXtras/jfxtras-labs). At jgridfx the following files match with this article:
-
-* `com.guigarage.fx.grid.GridView` (control)
-* `com.guigarage.fx.grid.skin.GridViewSkin` (skin)
-* `com.guigarage.fx.grid.behavior.GridViewBehavior` (behavior)
-* `/src/main/resources/com/guigarage/fx/grid/gridview.css` (css)
+---
+outdated: true
+showInBlog: false
+title: 'Custom UI Controls with JavaFX - Part 1'
+date: "2012-11-17"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'One thing I often done is Swing was customization of components and the creation of new components types. With the last release of JavaFX you can easily create custom controls with this new UI toolkit, too. This post gives a first overview about the JavaFX APIs to create custom controls.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+One thing I often done is Swing was customization of components and the creation of new components types. One example for this is the [JGrid](/posts/2011-07-15-jgrid). Since JavaFX was out I wanted to [port the JGrid to it](/posts/2012-11-14-gridfx-is-hosted-at-github). After some experiments and bad prototyps I think I found the right way to do it. The talks from [Gerrit Grunwald](http://harmoniccode.blogspot.de) and [Jonathan Giles](http://jonathangiles.net/blog/) at [JavaOne](http://www.oracle.com/javaone/index.html) helped me really a lot to do so. The records of this talks is online ([link](https://oracleus.activeevents.com/connect/sessionDetail.ww?SESSION_ID=2425&tclass=popup), [link](https://oracleus.activeevents.com/connect/sessionDetail.ww?SESSION_ID=4726&tclass=popup)) so I would advise everybody who is interest in this topic to spend some time and watch them.
+
+## Getting started
+
+Every UI component in JavaFX is composed by a __control__, a __skin__ and a __behavior__. In an ideal case there is a css part to.
+
+
+
+Best way to start is by creating a new control class that extends `javafx.scene.control.Control`. This class is basically comparable to `JComponent`. It should hold the properties of the component and acts as the main class for it because instances of this class will later created in your application code and added to the UI tree.
+
+```javaMyCustomControl myControl = new MyCustomControl();
+panel.getChildren().add(myControl);
```
+
+When programming swing components the right way you put everything that depends on the visualization or user interaction into a UI class (see `LabelUI` for example). JavaFX goes one step further and provides the skin class for all visualization and layout related code and the behavior class for all user interaction.
+
+
+
+To do so in JavaFX you need to know how the classes depends on each other. Here is a short chart that shows the relations between them:
+
+
+
+## Creating the Behavior
+
+If your component only visualizes data and has no interaction it 's quite simple to create a behavior. Therefore you only need to extend the `com.sun.javafx.scene.control.behavior.BehaviorBase`.
+
+```javapublic class MyCustomControlBehavior extends BehaviorBase {
+
+ public MyCustomControlBehavior(MyCustomControl control) {
+ super(control);
+ }
+}
```
+
+Some of you may be confused when seeing the package of BehaviorBase. At the moment this is a __private API__ and normally you should not use this classes in your code but the guys at Oracle know about this problem and will provide the __BehaviorBase as a public API with JavaFX 8__. So best practice is to use the private class now and refactor the import once Java 8 is out.
+
+## Creating the Skin
+
+After the behavior class is created we can take a look at the skin. Your skin class will mostly extend `com.sun.javafx.scene.control.skin.BaseSkin` and create a new behavior for your control. Your code normally should look like this:
+
+```javapublic class MyCustomControlSkin extends SkinBase{
+
+ public MyCustomControlSkin(MyCustomControl control) {
+ super(control, new MyCustomControlBehavior(control));
+ }
+}
```
+
+As you can see the BaseSkin is a private API as well. It will also changed to public with Java 8.
+
+## Creating the Control
+
+The last class we will need is the control. First we create a simple empty class:
+
+```javapublic class MyCustomControl extends Control {
+
+ public MyCustomControl() {
+ }
+}
```
+
+At this point we have a leak in the dependencies of our three classes. The skin knows about the behavior and control. Here everything looks right. However in application code you will simply create a new control and use it as I showed earlier. The problem is that the control class do not know anything about the skin or behavior. This was one of the biggest pitfalls I was confronted with while learning JavaFX.
+
+## Putting it together
+
+What first looks as a great problem is part of the potency JavaFX provides. With JavaFX it should be very easy to create different visualisation (skins) for controls. For this part you can customize the look of components by css. Because the skin is the main part of this look it has to defined by css, too. So instead of creating a skin object for the control by your own you only define the skin class that should be used for your control. The instanciation and everything else is automatically done by the JavaFX APIs. To do so you have to bind your control to a css class.
+
+Firts off all you have to create a new css file in your project. I think best practice is to use the same package as the controls has and but a css file under src/main/resource:
+
+
+
+Inside the css you have to specify a new selector for your component and add the skin as a property to it. This will for example look like this:
+
+```css.custom-control {
+ -fx-skin: "com.guigarage.customcontrol.MyCustomControlSkin";
+}
```
+
+Once you have created the css you have to define it in your control. Therefore you have to configure the path to the css file and the selector of your component:
+
+```javapublic class MyCustomControl extends Control {
+
+ public MyCustomControl() {
+ getStyleClass().add("custom-control");
+ }
+
+ @Override
+ protected String getUserAgentStylesheet() {
+ return MyCustomControl.class.getResource("customcontrol.css").toExternalForm();
+ }
+}
```
+
+After all this stuff is done correctly JavaFX will create a skin instance for your control. You do not need to take care about this instantiation or the dependency mechanism. At this point I want to thank [Jonathan Giles](http://jonathangiles.net/blog/) who taked some time to code the css integration for gridfx together with me and explained me all the mechanisms and benefits.
+
+## Access the Skin and Behavior
+
+Normally there is no need to access the skin or the behavior from within the controller. But if you have the need to do you can access them this way:
+
+
+
+Because controler.getSkin() receives a javafx.scene.control.Skin and not a SkinBase you have to cast it if you need the Behavior:
+
+```java((SkinBase)getSkin()).getBehavior();
```
+
+## Workaround for css haters
+
+For some of you this mechanism seems to be a little to oversized. Maybe you only need a specific control once in your application and you do not plan to skin it with css and doing all this stuff. For this use case there is a nice workaround in the JavaFX API. You can ignore all the css stuff and set the skin class to your control in code:
+
+```javapublic class MyCustomControl extends Control {
+ public MyCustomControl() {
+ setSkinClassName(MyCustomControlSkin.class.getName());
+ }
+}
```
+
+The benefit of this workflow is that refactoring of packages or classnames don't break your code and you don't need a extra css file. On the other side there is a great handicap. You can't use css defined skins in any extension of this control. __I think that every public API like gridfx should use the css way__. In some internal use cases the hard coded way could be faster.
+
+## Conclusion
+
+Now we created a control, a skin and a behavior that are working fine and can be added to your UI tree. But like in swing when simply extending the JComponent you don't see anything on screen. So the next step is to style and layout your component. I will handle this topic in my next post.
+
+If you want to look at some code of existing custom components check out [jgridfx](https://github.com/guigarage/gridfx) or [JFXtras](https://github.com/JFXtras/jfxtras-labs). At jgridfx the following files match with this article:
+
+* `com.guigarage.fx.grid.GridView` (control)
+* `com.guigarage.fx.grid.skin.GridViewSkin` (skin)
+* `com.guigarage.fx.grid.behavior.GridViewBehavior` (behavior)
+* `/src/main/resources/com/guigarage/fx/grid/gridview.css` (css)
diff --git a/content/posts/2012-11-17-swing-is-dead.md b/content/posts/2012-11-17-swing-is-dead.md
index 737e1ea6..283ab824 100644
--- a/content/posts/2012-11-17-swing-is-dead.md
+++ b/content/posts/2012-11-17-swing-is-dead.md
@@ -10,10 +10,10 @@ preview_image: "/posts/preview-images/software-development-green.svg"
---
JavaFX is the new UI API for Java Desktop applications and since summer it is part of Java 7. So every new Java Runtime is shipped with JavaFX. I think it's the perfect time to play with this great API and learn how to create cool applications with a better user experience than ever before.
-To learn JavaFX I started the [gridFX]({{< ref "/posts/2012-11-14-gridfx-is-hosted-at-github" >}}) project that provide a grid based control for JavaFX. While programming this control I learned a lot about JavaFX and all the different included APIs.
+To learn JavaFX I started the [gridFX](/posts/2012-11-14-gridfx-is-hosted-at-github) project that provide a grid based control for JavaFX. While programming this control I learned a lot about JavaFX and all the different included APIs.
By doing so it was sometimes hard to understand some of the paradigms that are used in JavaFX. It took a lot of research and the help of some guys ([Gerrit Grunwald](http://harmoniccode.blogspot.de), [Jonathan Giles](http://jonathangiles.net)) to understand this approaches and use them to create a better code and integration to the given APIs. After understanding all this stuff I can say that JavaFX is a really powerful API with a lot of potential.
After all I think that the learning curve for JavaFX is much different to the one for swing. The basics are currently hard to understand and learn but ones you decode them everything is so much easier.
-I want to use my blog to provide some basic tutorials about the different APIs and technics of JavaFX. All this tutorials are based on [demos]({{< ref "/posts/2012-11-14-playing-with-gridfx-and-itunes-webservices" >}}) that will use gridFX. Hope you like them.
+I want to use my blog to provide some basic tutorials about the different APIs and technics of JavaFX. All this tutorials are based on [demos](/posts/2012-11-14-playing-with-gridfx-and-itunes-webservices) that will use gridFX. Hope you like them.
diff --git a/content/posts/2012-11-21-gridfx-pagination.md b/content/posts/2012-11-21-gridfx-pagination.md
index 3d302bb5..c3b11c95 100644
--- a/content/posts/2012-11-21-gridfx-pagination.md
+++ b/content/posts/2012-11-21-gridfx-pagination.md
@@ -1,41 +1,39 @@
----
-outdated: true
-showInBlog: false
-title: 'gridfx & pagination'
-date: "2012-11-21"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'With the JavaFX API for pagination it is possible to combine GridFX with the given features and create a grid that supports pagination.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-The [GridFX]({{ site.baseurl }}{% link pages/projects/gridfx.md %}) component has currently one big problem. For every item inside the model a new cell is created inside the scene graph. So if you have 100.000 items in the item list of a the grid it will contain 100.000 cells. If every cell contains 4 nodes the scene graph will contain 400.000 nodes. In swing you used [renderer classes](http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer) to avoid this problem. But JavaFX work different. Instead of using only one renderer instance and painting this again and again JavaFX uses cell factories to create new instances for every cell. The trick is, that only the cells you currently see on screen are added to the scene graph. Old cells will be dropped from the scene graph when the view is scrolling and recycled or reused later. This logic is implemented in com.sun.javafx.scene.control.skin.VirtualFlow and used by the JavaFX [ListView](http://docs.oracle.com/javafx/2/ui_controls/list-view.htm) for example. I will implement this behavior to gridfx as soon as possible.
-
-
-
-While playing with other JavaFX features and APIs I found another solution for this problem. With the [Pagination](http://docs.oracle.com/javafx/2/ui_controls/pagination.htm) class you can split your UI in different pages. An example for this method is the iOS home screen. Here all your apps are split in different pages and you can flip through them.
-
-
-
-I tried to imitate this behavior for the GridView and will share my experience here.
-
-A list of items should be cut in little peaces so that each part fits exactly into one page of the Pagination Control and the page count depends on the item count. Thanks to the [JavaFX property binding](http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm) this plan wasn't to hard to implement. I created a helper class ([GridPaginationHelper.java](https://github.com/guigarage/gridfx/blob/master/src/main/java/com/guigarage/fx/grid/util/GridPaginationHelper.java)) that takes care of all the bindings and calculations. You only need a cell factory for the GridView. There are some problems with Pagination so that not everything is working as it should. Will later talk about this. First a short movie that shows the current state:
-
-{{< vimeo 54046675 >}}
-
-You can see how the Pagination animates through all pages and the page count is computed every time the size of the cells is changing. You can see the problems that the implementation has at this stage, too. Sometimes the navigation bar flickers or disappear for a moment. This a very strange behavior and I can't find the cause. Then I can not access the size of the page inside the Pagination Control. At the moment I'm working with the following hack:
-
-{{< highlight java >}}
-pageHeight = pagination.getHeight() - 64;
-{{< / highlight >}}
-
-There is another limitation of the Pagination Control. You can not deactivate the animation. When the cell size changes the current page index may change while showing the same cells. At this moment the animation should be deactivated.
-
-Maybe I have done something wrong or don't understand the complete usage of Pagination but I think that behavior I want to copy is used in a lot of modern applications:
-
-
-
-
-
-
-
-I will open some tickets at Jira for this issues. Maybe someone has I idea how to do this a better way in the meantime. I'm open for better and new ideas.
+---
+outdated: true
+showInBlog: false
+title: 'gridfx & pagination'
+date: "2012-11-21"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'With the JavaFX API for pagination it is possible to combine GridFX with the given features and create a grid that supports pagination.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+The [GridFX]({{ site.baseurl }}{% link pages/projects/gridfx.md %}) component has currently one big problem. For every item inside the model a new cell is created inside the scene graph. So if you have 100.000 items in the item list of a the grid it will contain 100.000 cells. If every cell contains 4 nodes the scene graph will contain 400.000 nodes. In swing you used [renderer classes](http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer) to avoid this problem. But JavaFX work different. Instead of using only one renderer instance and painting this again and again JavaFX uses cell factories to create new instances for every cell. The trick is, that only the cells you currently see on screen are added to the scene graph. Old cells will be dropped from the scene graph when the view is scrolling and recycled or reused later. This logic is implemented in com.sun.javafx.scene.control.skin.VirtualFlow and used by the JavaFX [ListView](http://docs.oracle.com/javafx/2/ui_controls/list-view.htm) for example. I will implement this behavior to gridfx as soon as possible.
+
+
+
+While playing with other JavaFX features and APIs I found another solution for this problem. With the [Pagination](http://docs.oracle.com/javafx/2/ui_controls/pagination.htm) class you can split your UI in different pages. An example for this method is the iOS home screen. Here all your apps are split in different pages and you can flip through them.
+
+
+
+I tried to imitate this behavior for the GridView and will share my experience here.
+
+A list of items should be cut in little peaces so that each part fits exactly into one page of the Pagination Control and the page count depends on the item count. Thanks to the [JavaFX property binding](http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm) this plan wasn't to hard to implement. I created a helper class ([GridPaginationHelper.java](https://github.com/guigarage/gridfx/blob/master/src/main/java/com/guigarage/fx/grid/util/GridPaginationHelper.java)) that takes care of all the bindings and calculations. You only need a cell factory for the GridView. There are some problems with Pagination so that not everything is working as it should. Will later talk about this. First a short movie that shows the current state:
+
+
+
+You can see how the Pagination animates through all pages and the page count is computed every time the size of the cells is changing. You can see the problems that the implementation has at this stage, too. Sometimes the navigation bar flickers or disappear for a moment. This a very strange behavior and I can't find the cause. Then I can not access the size of the page inside the Pagination Control. At the moment I'm working with the following hack:
+
+```javapageHeight = pagination.getHeight() - 64;
```
+
+There is another limitation of the Pagination Control. You can not deactivate the animation. When the cell size changes the current page index may change while showing the same cells. At this moment the animation should be deactivated.
+
+Maybe I have done something wrong or don't understand the complete usage of Pagination but I think that behavior I want to copy is used in a lot of modern applications:
+
+
+
+
+
+
+
+I will open some tickets at Jira for this issues. Maybe someone has I idea how to do this a better way in the meantime. I'm open for better and new ideas.
diff --git a/content/posts/2012-11-25-maven-support-for-datafx.md b/content/posts/2012-11-25-maven-support-for-datafx.md
index 84eb35cf..0b9e23af 100644
--- a/content/posts/2012-11-25-maven-support-for-datafx.md
+++ b/content/posts/2012-11-25-maven-support-for-datafx.md
@@ -1,31 +1,29 @@
----
-outdated: true
-showInBlog: false
-title: 'Maven support for DataFX'
-date: "2012-11-25"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'Since DataFX is one of the big JavaFX related libraries out there it makes sense to use it in modern Maven based applications. This post gives an overview how you can use DataFX in a Maven based project.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-At [Devoxx](http://www.devoxx.com/display/DV12/Home) I met [Johan Vos](https://twitter.com/johanvos) and we talked about [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) and Maven support. Now two weeks later we released DataFX 1.0 with Maven support and I am a official contributor of this great project. Thanks to Johan and Jonathan!
-
-With this post I will give a short "Getting Started" documentation for everyone who wants to use DataFX in a Maven based project.
-
-You can easily add a dependency to DataFX 1.0 to any Maven project. With doing so a JavaFX 2.2 dependency is added to your project, too. Just add the following dependency to your Maven pom:
-
-{{< highlight xml >}}
-
- org.javafxdata
- datafx-core
- 1.0
-
-{{< / highlight >}}
-
-Since all datafx-core artifacts are available at [Maven Central Repository](http://search.maven.org) the provision of DataFX will work automatically.
-
-If you are interested in how we added JavaFX as a dependency to DataFX you can read [here]({{< ref "/posts/2012-10-13-building-javafx-applications-with-maven" >}}) about it.
-
-This description shows how to add DataFX to your dependency hierarchy. If you want to run or distribute your application we recommend this [Maven plugin](https://github.com/zonski/javafx-maven-plugin) that provides a lot of functionality to a JavaFX Maven project. You can find a tutorial about this plugin [here](http://www.zenjava.com/2012/11/24/from-zero-to-javafx-in-5-minutes/).
-
-I hope you like the way how we integrated Maven support to DataFX and it this will help you creating cool JavaFX apps.
+---
+outdated: true
+showInBlog: false
+title: 'Maven support for DataFX'
+date: "2012-11-25"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'Since DataFX is one of the big JavaFX related libraries out there it makes sense to use it in modern Maven based applications. This post gives an overview how you can use DataFX in a Maven based project.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+At [Devoxx](http://www.devoxx.com/display/DV12/Home) I met [Johan Vos](https://twitter.com/johanvos) and we talked about [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) and Maven support. Now two weeks later we released DataFX 1.0 with Maven support and I am a official contributor of this great project. Thanks to Johan and Jonathan!
+
+With this post I will give a short "Getting Started" documentation for everyone who wants to use DataFX in a Maven based project.
+
+You can easily add a dependency to DataFX 1.0 to any Maven project. With doing so a JavaFX 2.2 dependency is added to your project, too. Just add the following dependency to your Maven pom:
+
+```xml
+ org.javafxdata
+ datafx-core
+ 1.0
+
```
+
+Since all datafx-core artifacts are available at [Maven Central Repository](http://search.maven.org) the provision of DataFX will work automatically.
+
+If you are interested in how we added JavaFX as a dependency to DataFX you can read [here](/posts/2012-10-13-building-javafx-applications-with-maven) about it.
+
+This description shows how to add DataFX to your dependency hierarchy. If you want to run or distribute your application we recommend this [Maven plugin](https://github.com/zonski/javafx-maven-plugin) that provides a lot of functionality to a JavaFX Maven project. You can find a tutorial about this plugin [here](http://www.zenjava.com/2012/11/24/from-zero-to-javafx-in-5-minutes/).
+
+I hope you like the way how we integrated Maven support to DataFX and it this will help you creating cool JavaFX apps.
diff --git a/content/posts/2012-11-29-custom-ui-controls-with-javafx-part-2.md b/content/posts/2012-11-29-custom-ui-controls-with-javafx-part-2.md
index 94afcaa3..28d76be1 100644
--- a/content/posts/2012-11-29-custom-ui-controls-with-javafx-part-2.md
+++ b/content/posts/2012-11-29-custom-ui-controls-with-javafx-part-2.md
@@ -1,246 +1,222 @@
----
-outdated: true
-showInBlog: false
-title: 'Custom UI Controls with JavaFX (Part 2)'
-date: "2012-11-29"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'One thing I often done is Swing was customization of components and the creation of new components types. With the last release of JavaFX you can easily create custom controls with this new UI toolkit, too. This post gives a first overview about the JavaFX APIs to create custom controls.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-I started a [series of JavaFX tutorials last week]({{< ref "/posts/2012-11-17-custom-ui-controls-with-javafx-part-1" >}}). In this second part I will explain how to layout custom controls and measure their bounds. Like in my last post I will try to show the differences and benefits of JavaFX compared to Swing.
-
-## Floating Point Bounds
-
-JavaFX uses a Scene Graph as the structure for all graphical nodes. This graph supports transformations like scaling or rotation for all its children in a very easy way.
-
-In Swing it is easy to translate a panel with all its children in x or y direction. In JavaFX you can now translate, scale or rotate a parent node with all children according to the x, y an z axes. But before we take a look at this transformations I will show you the simple way of setting bounds in JavaFX. There are three important methodes that every Node in JavaFX provides:
-
-{{< highlight java >}}
-void relocate(double x, double y)
-
-void resize(double width, double height)
-
-void resizeRelocate(double x, double y, double width, double height)
-{{< / highlight >}}
-
-This methods are equivalent to the following ones that a provided by JComponent:
-
-{{< highlight java >}}
-void setLocation(int x, int y)
-
-void setSize(int width, int height)
-
-void setBounds(int x, int y, int width, int height)
-{{< / highlight >}}
-
-The difference between them is that JavaFX uses "double" as parameter type. The methods of JComponent have it's historical background in AWT. I think at the time of implementation no one thought about rectangles that were arranged between pixels and were drawn with antialiasing. The JavaFX methods provides this functionality and once transformation comes into play everyone should understand why this is essential.
-
-## Let's do a basic layout
-
-When layouting a swing UI you normally do not call the methods mentioned above in your code. Layout managers do all the work for you. In most cases you have a container like the JPanel with LayoutManager like BorderLayout that layouts all children of the container within it's bounds.
-
-JavaFX don't know LayoutManagers. All layouting is done directly by the containers. The basic layout container is called Pane and when looking at the type hierarchy of this class you will find containers with different layout algorithms like the VBox or HBox.
-
-
-
-You can read about the different layout containers and their special scopes [here](http://docs.oracle.com/javafx/2/layout/builtin_layouts.htm). When creation custom panes there are a few more points to take care of. I will talk about this in a later post.
-
-## Preparing custom control for layout
-
-A LayoutManager in Swing computes the bounds of all children by three properties:
-
-{{< highlight java >}}
-Dimension getMaximumSize()
-
-Dimension getPreferredSize()
-
-Dimension getMinimumSize()
-{{< / highlight >}}
-
-A LayoutManager can use this properties of every child to compute its bounds inside the layout. When using FlowLayout for example every child has exactly its preferred dimension. So when you created your custom JComponent you needed to override this methods. This mechanism has one big problem: You can not calculate a dynamic aspect ratio of the children. Ever asked yourself why JLabel do not support automatic word wrapping? I think the leak of aspect ratio calculation in swing is the reason for this limitation. You can only calculate the preferred bounds of a component but you can not calculate the preferred width dependent to its height by using the default Swing workflow and APIs.
-
-With JavaFX you can do this calculations. Each Node in JavaFX provides the following methodes:
-
-{{< highlight java >}}
-double computeMinHeight(double width)
-
-double computeMinWidth(double height)
-
-double computeMaxHeight(double width)
-
-double computeMaxWidth(double height)
-
-double computePrefHeight(double width)
-
-double computePrefWidth(double height)
-{{< / highlight >}}
-
-By overriding this methods you can control how your custom control will be layouted in a pane. At the first moment everything looks right and easy. You can calculate the components height by its width and vice versa. But to use this calculations JavaFX needs a hint how the bias of a component is working. This is the point where the content bias comes into play. With this property every node can define if its width depends on the height or in opposite way. The current value is defined by this method:
-
-{{< highlight java >}}
-Orientation getContentBias()
-{{< / highlight >}}
-
-If the node is resizable and its height depends on its width the method should return Orientation.HORIZONTAL. If its width depends on its height return Orientation.VERTICAL. If your custom component do not need a width/height dependency you can even return null for its content bias. In this case -1 will always be passed to all methodes (computePrefWidth, etc.). Now your calculations will not depend on this value and we will have the same behavior as in Swing. The component do not use aspect ratio.
-
-So it is no problem anymore to provide a word wrap in a Textcomponent when using JavaFX. I will explain the usage of this methodes with a more easy example. Let's assume that we need a component that always has a surface area of 24 pixels.
-
-
-
-With swing we would only have a few different ways/dimensions to create such a component:
-
-{{< highlight java >}}
-Dimension getPreferredSize() {
- return new Dimension(24,1);
- //All other different versions
- //return new Dimension(1,24);
- //return new Dimension(2,12);
- //return new Dimension(12,2);
- //return new Dimension(8,3);
- //return new Dimension(3,8);
- //return new Dimension(6,4);
- //return new Dimension(4,6);
-}
-{{< / highlight >}}
-
-In reality there is a unlimited count of rectangles that have a area of 24 pixels. For example a rectangle with a width of 4,7 and a height of 5,105... has exact this area.
-
-
-
-With JavaFX and the extended ways to calculate the dimension of components and the use of double values we can create all of this rectangles (this is only limited by the range of double values). First of all we need to implement all this different methods for dimension calculation:
-
-{{< highlight java >}}
-@Override
-protected double computeMaxHeight(double width) {
- if (width > 0) {
- return Double.MAX_VALUE;
- } else {
- return 24.0 / width;
- }
-}
-
-@Override
-protected double computeMaxWidth(double height) {
- if (height > 0) {
- return Double.MAX_VALUE;
- } else {
- return 24.0 / height;
- }
-}
-
-@Override
-protected double computeMinHeight(double width) {
- if (width > 0) {
- return Double.MIN_VALUE;
- } else {
- return 24.0 / width;
- }
-}
-
-@Override
-protected double computeMinWidth(double height) {
- if (height > 0) {
- return Double.MIN_VALUE;
- } else {
- return 24.0 / height;
- }
-}
-
-@Override
-protected double computePrefHeight(double width) {
- if (width > 0) {
- return 4;
- } else {
- return 24.0 / width;
- }
-}
-
-@Override
-protected double computePrefWidth(double height) {
- if (height > 0) {
- return 6;
- } else {
- return 24.0 / height;
- }
-}
-{{< / highlight >}}
-
-All methodes can handle -1 as parameter and returns a default value in that case.
-
-Here is a movie showing the layout with Orientation.HORIZONTAL. Because a 24 pixel area would be very small. So I changed it to 240.000 for this movie:
-
-{{< vimeo 54478790 >}}
-
-And here is the movie with Orientation.VERTICAL:
-
-{{< vimeo 54479737 >}}
-
-As mentioned in my last post each Custom Control needs a Skin. To do things right you have to override all compute...-methods in your Skin and not in the Control class. Only getContentBias() needs to be overridden in the Control.
-
-## Useful hints
-
-If your component should has a constant dimension you can easily set all properties instead of overriding all the methods:
-
-{{< highlight java >}}
-myControl.setPrefWidth(4);
-myControl.setPrefHeight(6);
-
-//myControl.setPrefSize(4, 6);
-{{< / highlight >}}
-
-By default Control.USE_COMPUTED_SIZE is set for this properties. This indicates JavaFX to calculate the dimension by using mecanisms mentioned above.
-
-Another hint is to set Control.USE_PREF_SIZE to max/min size instead of overriding all methods. This will use the preferred size for min/max size:
-
-{{< highlight java >}}
-myControl.setMaxSize(USE_PREF_SIZE, USE_PREF_SIZE);
-{{< / highlight >}}
-
-Once a component is layouted you can access it's current bounds with:
-
-{{< highlight java >}}
-myControl.getBoundsInLocal()
-{{< / highlight >}}
-
-You can find more information about JavaFX layout [here](http://amyfowlersblog.wordpress.com/2011/06/02/javafx2-0-layout-a-class-tour/).
-
-### But I need a control that is not resizable
-
-The JavaFX layout mechanism even supports this feature. Every Node has this method:
-
-{{< highlight java >}}
-boolean isResizable()
-{{< / highlight >}}
-
-When this method returns false all (official) layout panes will not resize your control. In this case the layout only handles the location of your control.
-
-## Transformation
-
-As I mentioned before Nodes support transformation. In special translation, rotation and scaling are currently supported. Very important is to not equalize transformation with layouting. A transform in JavaFX changes the visual bounds of a layouted component. Every component needs to be layouted as descripted above. Once this is done the control can be transformed by a mouse event, for example. Here is a short example that rotates a node by mouse over event:
-
-{{< highlight java >}}
-myControl.setOnMouseEntered(new EventHandler() {
-
- @Override
- public void handle(MouseEvent arg0) {
- setRotate(15.0);
- }
-});
-
-myControl.setOnMouseExited(new EventHandler() {
-
- @Override
- public void handle(MouseEvent arg0) {
- setRotate(0);
- }
-});
-{{< / highlight >}}
-
-To measure the current visual bounds of a components once it is transformed we have the additional method getBoundsInParent(). Other than getBoundsInLocal() this method returns the bounds which include the transforms of the component.
-
-
-
-You can find more informations about transformations in JavaFX [here](http://docs.oracle.com/javafx/2/transformations/jfxpub-transformations.htm).
-
-You can download the example I used for this post [here](https://github.com/downloads/guigarage/gridfx-demos/layout-demo.zip).
+---
+outdated: true
+showInBlog: false
+title: 'Custom UI Controls with JavaFX (Part 2)'
+date: "2012-11-29"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'One thing I often done is Swing was customization of components and the creation of new components types. With the last release of JavaFX you can easily create custom controls with this new UI toolkit, too. This post gives a first overview about the JavaFX APIs to create custom controls.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+I started a [series of JavaFX tutorials last week](/posts/2012-11-17-custom-ui-controls-with-javafx-part-1). In this second part I will explain how to layout custom controls and measure their bounds. Like in my last post I will try to show the differences and benefits of JavaFX compared to Swing.
+
+## Floating Point Bounds
+
+JavaFX uses a Scene Graph as the structure for all graphical nodes. This graph supports transformations like scaling or rotation for all its children in a very easy way.
+
+In Swing it is easy to translate a panel with all its children in x or y direction. In JavaFX you can now translate, scale or rotate a parent node with all children according to the x, y an z axes. But before we take a look at this transformations I will show you the simple way of setting bounds in JavaFX. There are three important methodes that every Node in JavaFX provides:
+
+```javavoid relocate(double x, double y)
+
+void resize(double width, double height)
+
+void resizeRelocate(double x, double y, double width, double height)
```
+
+This methods are equivalent to the following ones that a provided by JComponent:
+
+```javavoid setLocation(int x, int y)
+
+void setSize(int width, int height)
+
+void setBounds(int x, int y, int width, int height)
```
+
+The difference between them is that JavaFX uses "double" as parameter type. The methods of JComponent have it's historical background in AWT. I think at the time of implementation no one thought about rectangles that were arranged between pixels and were drawn with antialiasing. The JavaFX methods provides this functionality and once transformation comes into play everyone should understand why this is essential.
+
+## Let's do a basic layout
+
+When layouting a swing UI you normally do not call the methods mentioned above in your code. Layout managers do all the work for you. In most cases you have a container like the JPanel with LayoutManager like BorderLayout that layouts all children of the container within it's bounds.
+
+JavaFX don't know LayoutManagers. All layouting is done directly by the containers. The basic layout container is called Pane and when looking at the type hierarchy of this class you will find containers with different layout algorithms like the VBox or HBox.
+
+
+
+You can read about the different layout containers and their special scopes [here](http://docs.oracle.com/javafx/2/layout/builtin_layouts.htm). When creation custom panes there are a few more points to take care of. I will talk about this in a later post.
+
+## Preparing custom control for layout
+
+A LayoutManager in Swing computes the bounds of all children by three properties:
+
+```javaDimension getMaximumSize()
+
+Dimension getPreferredSize()
+
+Dimension getMinimumSize()
```
+
+A LayoutManager can use this properties of every child to compute its bounds inside the layout. When using FlowLayout for example every child has exactly its preferred dimension. So when you created your custom JComponent you needed to override this methods. This mechanism has one big problem: You can not calculate a dynamic aspect ratio of the children. Ever asked yourself why JLabel do not support automatic word wrapping? I think the leak of aspect ratio calculation in swing is the reason for this limitation. You can only calculate the preferred bounds of a component but you can not calculate the preferred width dependent to its height by using the default Swing workflow and APIs.
+
+With JavaFX you can do this calculations. Each Node in JavaFX provides the following methodes:
+
+```javadouble computeMinHeight(double width)
+
+double computeMinWidth(double height)
+
+double computeMaxHeight(double width)
+
+double computeMaxWidth(double height)
+
+double computePrefHeight(double width)
+
+double computePrefWidth(double height)
```
+
+By overriding this methods you can control how your custom control will be layouted in a pane. At the first moment everything looks right and easy. You can calculate the components height by its width and vice versa. But to use this calculations JavaFX needs a hint how the bias of a component is working. This is the point where the content bias comes into play. With this property every node can define if its width depends on the height or in opposite way. The current value is defined by this method:
+
+```javaOrientation getContentBias()
```
+
+If the node is resizable and its height depends on its width the method should return Orientation.HORIZONTAL. If its width depends on its height return Orientation.VERTICAL. If your custom component do not need a width/height dependency you can even return null for its content bias. In this case -1 will always be passed to all methodes (computePrefWidth, etc.). Now your calculations will not depend on this value and we will have the same behavior as in Swing. The component do not use aspect ratio.
+
+So it is no problem anymore to provide a word wrap in a Textcomponent when using JavaFX. I will explain the usage of this methodes with a more easy example. Let's assume that we need a component that always has a surface area of 24 pixels.
+
+
+
+With swing we would only have a few different ways/dimensions to create such a component:
+
+```javaDimension getPreferredSize() {
+ return new Dimension(24,1);
+ //All other different versions
+ //return new Dimension(1,24);
+ //return new Dimension(2,12);
+ //return new Dimension(12,2);
+ //return new Dimension(8,3);
+ //return new Dimension(3,8);
+ //return new Dimension(6,4);
+ //return new Dimension(4,6);
+}
```
+
+In reality there is a unlimited count of rectangles that have a area of 24 pixels. For example a rectangle with a width of 4,7 and a height of 5,105... has exact this area.
+
+
+
+With JavaFX and the extended ways to calculate the dimension of components and the use of double values we can create all of this rectangles (this is only limited by the range of double values). First of all we need to implement all this different methods for dimension calculation:
+
+```java@Override
+protected double computeMaxHeight(double width) {
+ if (width > 0) {
+ return Double.MAX_VALUE;
+ } else {
+ return 24.0 / width;
+ }
+}
+
+@Override
+protected double computeMaxWidth(double height) {
+ if (height > 0) {
+ return Double.MAX_VALUE;
+ } else {
+ return 24.0 / height;
+ }
+}
+
+@Override
+protected double computeMinHeight(double width) {
+ if (width > 0) {
+ return Double.MIN_VALUE;
+ } else {
+ return 24.0 / width;
+ }
+}
+
+@Override
+protected double computeMinWidth(double height) {
+ if (height > 0) {
+ return Double.MIN_VALUE;
+ } else {
+ return 24.0 / height;
+ }
+}
+
+@Override
+protected double computePrefHeight(double width) {
+ if (width > 0) {
+ return 4;
+ } else {
+ return 24.0 / width;
+ }
+}
+
+@Override
+protected double computePrefWidth(double height) {
+ if (height > 0) {
+ return 6;
+ } else {
+ return 24.0 / height;
+ }
+}
```
+
+All methodes can handle -1 as parameter and returns a default value in that case.
+
+Here is a movie showing the layout with Orientation.HORIZONTAL. Because a 24 pixel area would be very small. So I changed it to 240.000 for this movie:
+
+
+
+And here is the movie with Orientation.VERTICAL:
+
+
+
+As mentioned in my last post each Custom Control needs a Skin. To do things right you have to override all compute...-methods in your Skin and not in the Control class. Only getContentBias() needs to be overridden in the Control.
+
+## Useful hints
+
+If your component should has a constant dimension you can easily set all properties instead of overriding all the methods:
+
+```javamyControl.setPrefWidth(4);
+myControl.setPrefHeight(6);
+
+//myControl.setPrefSize(4, 6);
```
+
+By default Control.USE_COMPUTED_SIZE is set for this properties. This indicates JavaFX to calculate the dimension by using mecanisms mentioned above.
+
+Another hint is to set Control.USE_PREF_SIZE to max/min size instead of overriding all methods. This will use the preferred size for min/max size:
+
+```javamyControl.setMaxSize(USE_PREF_SIZE, USE_PREF_SIZE);
```
+
+Once a component is layouted you can access it's current bounds with:
+
+```javamyControl.getBoundsInLocal()
```
+
+You can find more information about JavaFX layout [here](http://amyfowlersblog.wordpress.com/2011/06/02/javafx2-0-layout-a-class-tour/).
+
+### But I need a control that is not resizable
+
+The JavaFX layout mechanism even supports this feature. Every Node has this method:
+
+```javaboolean isResizable()
```
+
+When this method returns false all (official) layout panes will not resize your control. In this case the layout only handles the location of your control.
+
+## Transformation
+
+As I mentioned before Nodes support transformation. In special translation, rotation and scaling are currently supported. Very important is to not equalize transformation with layouting. A transform in JavaFX changes the visual bounds of a layouted component. Every component needs to be layouted as descripted above. Once this is done the control can be transformed by a mouse event, for example. Here is a short example that rotates a node by mouse over event:
+
+```javamyControl.setOnMouseEntered(new EventHandler() {
+
+ @Override
+ public void handle(MouseEvent arg0) {
+ setRotate(15.0);
+ }
+});
+
+myControl.setOnMouseExited(new EventHandler() {
+
+ @Override
+ public void handle(MouseEvent arg0) {
+ setRotate(0);
+ }
+});
```
+
+To measure the current visual bounds of a components once it is transformed we have the additional method getBoundsInParent(). Other than getBoundsInLocal() this method returns the bounds which include the transforms of the component.
+
+
+
+You can find more informations about transformations in JavaFX [here](http://docs.oracle.com/javafx/2/transformations/jfxpub-transformations.htm).
+
+You can download the example I used for this post [here](https://github.com/downloads/guigarage/gridfx-demos/layout-demo.zip).
diff --git a/content/posts/2012-11-29-the-future-of-vagrant-binding.md b/content/posts/2012-11-29-the-future-of-vagrant-binding.md
index 699f8cd1..e1033b20 100644
--- a/content/posts/2012-11-29-the-future-of-vagrant-binding.md
+++ b/content/posts/2012-11-29-the-future-of-vagrant-binding.md
@@ -8,6 +8,6 @@ categories: [General, Vagrant-Binding]
excerpt: "Currently I'm working on Chef support for the Vagrant-Binding. So you can choose between Puppet and Chef as provisioner."
preview_image: "/posts/preview-images/software-development-green.svg"
---
-The last weeks my top priority was [JavaFX]({{< ref "/posts/2012-11-17-custom-ui-controls-with-javafx-part-1" >}}) and [GridFX]({{< ref "/posts/2012-11-29-gridfx-is-moving-forward" >}}). But this doesn't mean that [Vagrant-Binding]({{< ref "/posts/2012-11-01-introducing-vagrant-binding" >}}) stands still. Currently I'm working on [Chef](http://www.opscode.com/chef/) support for the API. So you can choose between [Puppet](http://puppetlabs.com) and Chef as provisioner. I have some great plans for the future and I think that [Vagrants future and the founding of HashiCorp](http://www.hashicorp.com/blog/announcing-hashicorp.html) will be very positive for Vagrant-Binding. I was always thinking how to add [AWS](http://aws.amazon.com) as a second provider next to [VirtualBox](https://www.virtualbox.org). I hope that Vagrants further development will provide exactly this features :)
+The last weeks my top priority was [JavaFX](/posts/2012-11-17-custom-ui-controls-with-javafx-part-1) and [GridFX](/posts/2012-11-29-gridfx-is-moving-forward). But this doesn't mean that [Vagrant-Binding](/posts/2012-11-01-introducing-vagrant-binding) stands still. Currently I'm working on [Chef](http://www.opscode.com/chef/) support for the API. So you can choose between [Puppet](http://puppetlabs.com) and Chef as provisioner. I have some great plans for the future and I think that [Vagrants future and the founding of HashiCorp](http://www.hashicorp.com/blog/announcing-hashicorp.html) will be very positive for Vagrant-Binding. I was always thinking how to add [AWS](http://aws.amazon.com) as a second provider next to [VirtualBox](https://www.virtualbox.org). I hope that Vagrants further development will provide exactly this features :)
I am, by the way, not a Chef expert. So maybe anyone out there wants to help me with the Chef integration and provides some Chef projects that covers all the support Chef features in Vagrant. It would be a superb help for a full functional and great API.
diff --git a/content/posts/2012-12-10-access-puppet-forge-repository-with-java.md b/content/posts/2012-12-10-access-puppet-forge-repository-with-java.md
index 75d73330..2641e621 100644
--- a/content/posts/2012-12-10-access-puppet-forge-repository-with-java.md
+++ b/content/posts/2012-12-10-access-puppet-forge-repository-with-java.md
@@ -1,25 +1,23 @@
----
-outdated: true
-showInBlog: false
-title: 'Access Puppet Forge Repository with Java'
-date: "2012-12-10"
-author: hendrik
-categories: [Vagrant-Binding]
-excerpt: 'To integrate Puppet modules more easy to Vagrant-Binding projects I created a Java API that access Puppet Forge by REST.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-To integrate Puppet modules more easy to [Vagrant-Binding]({{< ref "/posts/2012-11-01-introducing-vagrant-binding" >}}) projects I created a Java API that access Puppet Forge by REST. You can search for modules or download any module to your locale disc. So you can easily add modules from the repository to your own Vagrant environments. The API is currently not part of Vagrant-Binding and can be found [here](https://github.com/guigarage/puppet-forge-ws) but I plan to integrate the API in the future. Additionally I added a demo to the [Vagrant-Binding-Demos]({{ site.baseurl }}{% post_url 2012-11-03-vagrant-binding-demos %}
-) project that can be found at [github](https://github.com/guigarage/vagrant-binding-demos/blob/master/src/main/java/com/guigarage/vagrant/tutorials/PuppetTutorial2.java). Here is a short example that uses the API:
-
-{{< highlight java >}}
-PuppetForgeClient client = new PuppetForgeClient();
-File moduleFolder = new File("/path/to/my/modules");
-
-ListallDescriptions = client.findModules("mongodb");
-
-for(PuppetForgeModuleDescription description : allDescriptions) {
- System.out.println("Installing " + description.getFullName());
- PuppetForgeModule module = client.findModule(description);
- client.installToModulesDir(moduleFolder, module);
-}
-{{< / highlight >}}
+---
+outdated: true
+showInBlog: false
+title: 'Access Puppet Forge Repository with Java'
+date: "2012-12-10"
+author: hendrik
+categories: [Vagrant-Binding]
+excerpt: 'To integrate Puppet modules more easy to Vagrant-Binding projects I created a Java API that access Puppet Forge by REST.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+To integrate Puppet modules more easy to [Vagrant-Binding](/posts/2012-11-01-introducing-vagrant-binding) projects I created a Java API that access Puppet Forge by REST. You can search for modules or download any module to your locale disc. So you can easily add modules from the repository to your own Vagrant environments. The API is currently not part of Vagrant-Binding and can be found [here](https://github.com/guigarage/puppet-forge-ws) but I plan to integrate the API in the future. Additionally I added a demo to the [Vagrant-Binding-Demos]({{ site.baseurl }}{% post_url 2012-11-03-vagrant-binding-demos %}
+) project that can be found at [github](https://github.com/guigarage/vagrant-binding-demos/blob/master/src/main/java/com/guigarage/vagrant/tutorials/PuppetTutorial2.java). Here is a short example that uses the API:
+
+```javaPuppetForgeClient client = new PuppetForgeClient();
+File moduleFolder = new File("/path/to/my/modules");
+
+ListallDescriptions = client.findModules("mongodb");
+
+for(PuppetForgeModuleDescription description : allDescriptions) {
+ System.out.println("Installing " + description.getFullName());
+ PuppetForgeModule module = client.findModule(description);
+ client.installToModulesDir(moduleFolder, module);
+}
```
diff --git a/content/posts/2012-12-12-some-news-about-vagrant-binding.md b/content/posts/2012-12-12-some-news-about-vagrant-binding.md
index 4fad5c8c..bb0a7593 100644
--- a/content/posts/2012-12-12-some-news-about-vagrant-binding.md
+++ b/content/posts/2012-12-12-some-news-about-vagrant-binding.md
@@ -8,4 +8,4 @@ categories: [General, Vagrant-Binding]
excerpt: 'Yesterday I gave a Vagrant-Binding talk at JUG Dortmund. I received really great feedback and thanks to some productive discussions the future of the API is getting more clearly to me.'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-Yesterday I gave a [Vagrant-Binding]({{< ref "/posts/2012-11-01-introducing-vagrant-binding" >}}) presentation at [JUG Dortmund](http://www.jugdo.de/?p=75). I received really great feedback and thanks to some productive discussions the future of the API is getting more clearly to me. You can download the slides of the talk [here](http://de.slideshare.net/HendrikEbbers/vagrant-puppet-jug-2). The German jaxenter has published an [article about Vagrant-Binding](http://it-republik.de/jaxenter/artikel/Einweg-VM-zur-Runtime-erstellen-5516.html) today. So it seems that there are really people out there wanting to use this stuff. Thanks for all the positive feedback and support.
+Yesterday I gave a [Vagrant-Binding](/posts/2012-11-01-introducing-vagrant-binding) presentation at [JUG Dortmund](http://www.jugdo.de/?p=75). I received really great feedback and thanks to some productive discussions the future of the API is getting more clearly to me. You can download the slides of the talk [here](http://de.slideshare.net/HendrikEbbers/vagrant-puppet-jug-2). The German jaxenter has published an [article about Vagrant-Binding](http://it-republik.de/jaxenter/artikel/Einweg-VM-zur-Runtime-erstellen-5516.html) today. So it seems that there are really people out there wanting to use this stuff. Thanks for all the positive feedback and support.
diff --git a/content/posts/2012-12-28-my-first-steps-with-javafx-on-raspberry-pi.md b/content/posts/2012-12-28-my-first-steps-with-javafx-on-raspberry-pi.md
index 551a0c34..927a8942 100644
--- a/content/posts/2012-12-28-my-first-steps-with-javafx-on-raspberry-pi.md
+++ b/content/posts/2012-12-28-my-first-steps-with-javafx-on-raspberry-pi.md
@@ -12,7 +12,7 @@ Today I started playing with my Pi & JavaFX. Even after a few hours I can say th
I created a screensaver as a first demo. The programm loads random pictures (2848 × 4288 pixel) and animates them on the screen:
-{{< youtube r0GEm1pEhoE >}}
+
I used a experimental build of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) for loading and scaling all the pictures. In my point of view the performance of all animations is awesome. Oracle has really done a great work!
diff --git a/content/posts/2012-12-29-gridfx-on-raspberry-pi-javafx-8.md b/content/posts/2012-12-29-gridfx-on-raspberry-pi-javafx-8.md
index 0053ec32..1fc0d441 100644
--- a/content/posts/2012-12-29-gridfx-on-raspberry-pi-javafx-8.md
+++ b/content/posts/2012-12-29-gridfx-on-raspberry-pi-javafx-8.md
@@ -1,35 +1,31 @@
----
-outdated: true
-showInBlog: false
-title: 'GridFX on Raspberry Pi & JavaFX 8'
-date: "2012-12-29"
-author: hendrik
-categories: [IoT, JavaFX]
-excerpt: 'For my first JFX demo I created a experimental GridFX version for JavaFX 8.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-For my [first JFX demo]({{< ref "/posts/2012-12-28-my-first-steps-with-javafx-on-raspberry-pi" >}}) I tried to create a experimental [GridFX]({{ site.baseurl }}{% link pages/projects/gridfx.md %}) version for JavaFX 8. As I mentioned in an [earlier post]({{< ref "/posts/2012-11-17-custom-ui-controls-with-javafx-part-1" >}}) there are some API changed between JavaFX 2 and 8. For GridFX I had to change two things:
-
-* The BaseSkin class is now public
-* The CSS support that I used in GridFX seams to work completely different in JavaFX 8.
-
-Both issues were fixed very fast and an GridFX demo was running on my Mac where I have JDK "build 1.8.0-ea-b69" installed ([download it here](http://jdk8.java.net/download.html)). But after deploying the demo on my Pi nothing happened...
-
-So I created a log file for the java output by adding some parameters to the shell command:
-
-{{< highlight shell >}}
-java -cp myApp.jar com.guigarage.Demo >log 2>&1
-{{< / highlight >}}
-
-The logging showed me the cause of my problems:
-
-{{< highlight shell >}}
-java.lang.NoSuchMethodError: javafx.scene.control.SkinBase.(Ljavafx/scene/control/Control;)V at com.guigarage.fx.grid.skin.GridViewSkin.(GridViewSkin.java:24)
-{{< / highlight >}}
-
-While everything compiled perfectly on my Mac, the Pi has a different JavaFX compilation / version ("build 1.8.0-ea-b36e"). As a first solution I downloaded the "jfxrt.jar" file from my Pi and included it to the GridFX project on my Mac. After doing so I saw all the compilation problems in Eclipse and had a change to resolve them. It would be very nice to have a real 1.8.0-ea-b36 build installed on my Mac. Any idea where to get it?
-
-But after fixing all this problems the GridFX demo is running on my Pi:
-
-{{< youtube OZv6WUpEzS8 >}}
-
+---
+outdated: true
+showInBlog: false
+title: 'GridFX on Raspberry Pi & JavaFX 8'
+date: "2012-12-29"
+author: hendrik
+categories: [IoT, JavaFX]
+excerpt: 'For my first JFX demo I created a experimental GridFX version for JavaFX 8.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+For my [first JFX demo](/posts/2012-12-28-my-first-steps-with-javafx-on-raspberry-pi) I tried to create a experimental [GridFX]({{ site.baseurl }}{% link pages/projects/gridfx.md %}) version for JavaFX 8. As I mentioned in an [earlier post](/posts/2012-11-17-custom-ui-controls-with-javafx-part-1) there are some API changed between JavaFX 2 and 8. For GridFX I had to change two things:
+
+* The BaseSkin class is now public
+* The CSS support that I used in GridFX seams to work completely different in JavaFX 8.
+
+Both issues were fixed very fast and an GridFX demo was running on my Mac where I have JDK "build 1.8.0-ea-b69" installed ([download it here](http://jdk8.java.net/download.html)). But after deploying the demo on my Pi nothing happened...
+
+So I created a log file for the java output by adding some parameters to the shell command:
+
+```shelljava -cp myApp.jar com.guigarage.Demo >log 2>&1
```
+
+The logging showed me the cause of my problems:
+
+```shelljava.lang.NoSuchMethodError: javafx.scene.control.SkinBase.(Ljavafx/scene/control/Control;)V at com.guigarage.fx.grid.skin.GridViewSkin.(GridViewSkin.java:24)
```
+
+While everything compiled perfectly on my Mac, the Pi has a different JavaFX compilation / version ("build 1.8.0-ea-b36e"). As a first solution I downloaded the "jfxrt.jar" file from my Pi and included it to the GridFX project on my Mac. After doing so I saw all the compilation problems in Eclipse and had a change to resolve them. It would be very nice to have a real 1.8.0-ea-b36 build installed on my Mac. Any idea where to get it?
+
+But after fixing all this problems the GridFX demo is running on my Pi:
+
+
+
diff --git a/content/posts/2012-12-31-bindabletransition.md b/content/posts/2012-12-31-bindabletransition.md
index 8803cebc..7b68809f 100644
--- a/content/posts/2012-12-31-bindabletransition.md
+++ b/content/posts/2012-12-31-bindabletransition.md
@@ -1,42 +1,38 @@
----
-outdated: true
-showInBlog: false
-title: 'BindableTransition'
-date: "2012-12-31"
-author: hendrik
-categories: [General, JavaFX]
-excerpt: 'JavaFX supports a lot of transition and animation classes. But sometimes you need a special animation for that no default transition is provided by JavaFX.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-JavaFX supports a lot of [transition and animation](http://docs.oracle.com/javafx/2/animations/basics.htm#CJAJJAGI) classes for Node properties like the [`javafx.animation.ScaleTransition`](http://docs.oracle.com/javafx/2/api/javafx/animation/ScaleTransition.html). But sometimes you need a special animation for that no default transition is provided by JavaFX. Currently the best pratice is to extend [`javafx.animation.Transition`](http://docs.oracle.com/javafx/2/api/javafx/animation/Transition.html) and override the `interpolate(double frac)` method:
-
-{{< highlight java >}}
-protected void interpolate(double frac) {
- myProperty.set(frac);
-}
-{{< / highlight >}}
-
-Because JavaFX offers [PropertyBinding](http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm) I created a `BindableTransition` which current fraction is a `Property` and can be bind to any other `NumberProperty`. Here is an example:
-
-{{< highlight java >}}
-Button button = new Button("BindableTransition");
-DropShadow shadow = DropShadowBuilder.create().build();
-button.setEffect(shadow);
-
-final Duration duration = Duration.millis(1200);
-BindableTransition transition = new BindableTransition(duration);
-transition.setCycleCount(1000);
-transition.setAutoReverse(true);
-
-shadow.offsetXProperty().bind(transition.fractionProperty().multiply(32));
-shadow.offsetYProperty().bind(transition.fractionProperty().multiply(32));
-button.translateXProperty().bind(transition.fractionProperty().multiply(-32));
-
-transition.play();
-{{< / highlight >}}
-
-The `fractionProperty` of the `BindableTransition` is bound to three different properties and the result will look like this:
-
-{{< vimeo 56550389 >}}
-
-The [BindableTransition](https://github.com/JFXtras/jfxtras-labs/blob/master/src/main/java/jfxtras/labs/animation/BindableTransition.java) class and a [demo](https://github.com/JFXtras/jfxtras-labs/blob/master/src/test/java/jfxtras/labs/animation/BindableTransitionTrial.java)are commited to the [JFXtras project](http://jfxtras.org).
+---
+outdated: true
+showInBlog: false
+title: 'BindableTransition'
+date: "2012-12-31"
+author: hendrik
+categories: [General, JavaFX]
+excerpt: 'JavaFX supports a lot of transition and animation classes. But sometimes you need a special animation for that no default transition is provided by JavaFX.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+JavaFX supports a lot of [transition and animation](http://docs.oracle.com/javafx/2/animations/basics.htm#CJAJJAGI) classes for Node properties like the [`javafx.animation.ScaleTransition`](http://docs.oracle.com/javafx/2/api/javafx/animation/ScaleTransition.html). But sometimes you need a special animation for that no default transition is provided by JavaFX. Currently the best pratice is to extend [`javafx.animation.Transition`](http://docs.oracle.com/javafx/2/api/javafx/animation/Transition.html) and override the `interpolate(double frac)` method:
+
+```javaprotected void interpolate(double frac) {
+ myProperty.set(frac);
+}
```
+
+Because JavaFX offers [PropertyBinding](http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm) I created a `BindableTransition` which current fraction is a `Property` and can be bind to any other `NumberProperty`. Here is an example:
+
+```javaButton button = new Button("BindableTransition");
+DropShadow shadow = DropShadowBuilder.create().build();
+button.setEffect(shadow);
+
+final Duration duration = Duration.millis(1200);
+BindableTransition transition = new BindableTransition(duration);
+transition.setCycleCount(1000);
+transition.setAutoReverse(true);
+
+shadow.offsetXProperty().bind(transition.fractionProperty().multiply(32));
+shadow.offsetYProperty().bind(transition.fractionProperty().multiply(32));
+button.translateXProperty().bind(transition.fractionProperty().multiply(-32));
+
+transition.play();
```
+
+The `fractionProperty` of the `BindableTransition` is bound to three different properties and the result will look like this:
+
+
+
+The [BindableTransition](https://github.com/JFXtras/jfxtras-labs/blob/master/src/main/java/jfxtras/labs/animation/BindableTransition.java) class and a [demo](https://github.com/JFXtras/jfxtras-labs/blob/master/src/test/java/jfxtras/labs/animation/BindableTransitionTrial.java)are commited to the [JFXtras project](http://jfxtras.org).
diff --git a/content/posts/2013-01-01-invokeandwait-for-javafx.md b/content/posts/2013-01-01-invokeandwait-for-javafx.md
index 3b02080c..3d297b26 100644
--- a/content/posts/2013-01-01-invokeandwait-for-javafx.md
+++ b/content/posts/2013-01-01-invokeandwait-for-javafx.md
@@ -1,84 +1,82 @@
----
-outdated: true
-showInBlog: false
-title: 'invokeAndWait for JavaFX'
-date: "2013-01-01"
-author: hendrik
-categories: [DataFX, General, JavaFX]
-excerpt: "Swing offers the two methods SwingUtilities.invokeAndWait(...) and SwingUtilities.invokeLater(...) to execute a Runnable object on Swings event dispatching thread. Let's have a look how we can have the same functionallity in JavaFX"
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Swing offers the two methods `SwingUtilities.invokeAndWait(...)` and `SwingUtilities.invokeLater(...) to execute a Runnable object on Swings event dispatching thread. You can read more about this methods [http://javarevisited.blogspot.de/2011/09/invokeandwait-invokelater-swing-example.html](here).
-
-As I currently know JavaFX provides only `Platform.runLater(...)` that is the equivalent of SwingUtilities.invokeLater(...). A "runAndWait" method doesn't exist at the moment. While developing some [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) stuff and my [first Raspberry Pi demo]({{< ref "/posts/2012-12-28-my-first-steps-with-javafx-on-raspberry-pi" >}}) I needed this feature in JavaFX. So I created a `runAndWait` method that will hopefully be part of DataFX in some future. Until then you can use this code in your project:
-
-{{< highlight java >}}
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import javafx.application.Platform;
-
-public class FXUtilities {
-
- private static class ThrowableWrapper {
- Throwable t;
- }
-
- /**
- * Invokes a Runnable in JFX Thread and waits while it's finished. Like
- * SwingUtilities.invokeAndWait does for EDT.
- *
- * @param run
- * The Runnable that has to be called on JFX thread.
- * @throws InterruptedException
- * f the execution is interrupted.
- * @throws ExecutionException
- * If a exception is occurred in the run method of the Runnable
- */
- public static void runAndWait(final Runnable run)
- throws InterruptedException, ExecutionException {
- if (Platform.isFxApplicationThread()) {
- try {
- run.run();
- } catch (Exception e) {
- throw new ExecutionException(e);
- }
- } else {
- final Lock lock = new ReentrantLock();
- final Condition condition = lock.newCondition();
- final ThrowableWrapper throwableWrapper = new ThrowableWrapper();
- lock.lock();
- try {
- Platform.runLater(new Runnable() {
-
- @Override
- public void run() {
- lock.lock();
- try {
- run.run();
- } catch (Throwable e) {
- throwableWrapper.t = e;
- } finally {
- try {
- condition.signal();
- } finally {
- lock.unlock();
- }
- }
- }
- });
- condition.await();
- if (throwableWrapper.t != null) {
- throw new ExecutionException(throwableWrapper.t);
- }
- } finally {
- lock.unlock();
- }
- }
- }
-}
-{{< / highlight >}}
-
-It's working for all my needs. Please give me some feedback if there are any problems or bug.
+---
+outdated: true
+showInBlog: false
+title: 'invokeAndWait for JavaFX'
+date: "2013-01-01"
+author: hendrik
+categories: [DataFX, General, JavaFX]
+excerpt: "Swing offers the two methods SwingUtilities.invokeAndWait(...) and SwingUtilities.invokeLater(...) to execute a Runnable object on Swings event dispatching thread. Let's have a look how we can have the same functionallity in JavaFX"
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Swing offers the two methods `SwingUtilities.invokeAndWait(...)` and `SwingUtilities.invokeLater(...) to execute a Runnable object on Swings event dispatching thread. You can read more about this methods [http://javarevisited.blogspot.de/2011/09/invokeandwait-invokelater-swing-example.html](here).
+
+As I currently know JavaFX provides only `Platform.runLater(...)` that is the equivalent of SwingUtilities.invokeLater(...). A "runAndWait" method doesn't exist at the moment. While developing some [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) stuff and my [first Raspberry Pi demo](/posts/2012-12-28-my-first-steps-with-javafx-on-raspberry-pi) I needed this feature in JavaFX. So I created a `runAndWait` method that will hopefully be part of DataFX in some future. Until then you can use this code in your project:
+
+```javaimport java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javafx.application.Platform;
+
+public class FXUtilities {
+
+ private static class ThrowableWrapper {
+ Throwable t;
+ }
+
+ /**
+ * Invokes a Runnable in JFX Thread and waits while it's finished. Like
+ * SwingUtilities.invokeAndWait does for EDT.
+ *
+ * @param run
+ * The Runnable that has to be called on JFX thread.
+ * @throws InterruptedException
+ * f the execution is interrupted.
+ * @throws ExecutionException
+ * If a exception is occurred in the run method of the Runnable
+ */
+ public static void runAndWait(final Runnable run)
+ throws InterruptedException, ExecutionException {
+ if (Platform.isFxApplicationThread()) {
+ try {
+ run.run();
+ } catch (Exception e) {
+ throw new ExecutionException(e);
+ }
+ } else {
+ final Lock lock = new ReentrantLock();
+ final Condition condition = lock.newCondition();
+ final ThrowableWrapper throwableWrapper = new ThrowableWrapper();
+ lock.lock();
+ try {
+ Platform.runLater(new Runnable() {
+
+ @Override
+ public void run() {
+ lock.lock();
+ try {
+ run.run();
+ } catch (Throwable e) {
+ throwableWrapper.t = e;
+ } finally {
+ try {
+ condition.signal();
+ } finally {
+ lock.unlock();
+ }
+ }
+ }
+ });
+ condition.await();
+ if (throwableWrapper.t != null) {
+ throw new ExecutionException(throwableWrapper.t);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ }
+}
```
+
+It's working for all my needs. Please give me some feedback if there are any problems or bug.
diff --git a/content/posts/2013-01-10-custom-ui-controls-with-javafx-part3.md b/content/posts/2013-01-10-custom-ui-controls-with-javafx-part3.md
index acbd0678..1b467302 100644
--- a/content/posts/2013-01-10-custom-ui-controls-with-javafx-part3.md
+++ b/content/posts/2013-01-10-custom-ui-controls-with-javafx-part3.md
@@ -1,222 +1,198 @@
----
-outdated: true
-showInBlog: false
-title: 'Custom UI Controls with JavaFX (Part3)'
-date: "2013-01-10"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'In this post I will explain the basic JavaFX Property API. I will first explain the old Swing way to better understand the idea of the new API and all problems that are solved by it.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this post I will explain the basic JavaFX Property API because most of the planed future tutorials will depend on Properties. I will first explain the old Swing way to better understand the idea of the new API and all problems that are solved by it.
-
-## Properties in Swing
-
-In Swing every Component is a [JavaBean](http://docs.oracle.com/javase/tutorial/javabeans/) and its fields (bean properties) are accessible by getters and setters. If you want to change the text of a button you have to call the setter method:
-
-{{< highlight java >}}
-jbutton.setText("click me");
-
-You can receive the current text by calling the getter method:
-
-String currentText = jbutton.getText();
-{{< / highlight >}}
-
-With this methods you can easily modify and control your user interface in a static way. For example you can receive and check all entered data by calling the required getter methods on your components once the save button is pressed.
-
-But in the last years user experience has changed. Data should be validated in the moment it has been entered by the user and the background color of a application should change on the fly while the user is dropping the mouse over the colorchooser. All this things can be done with Swing and [PropertyChangeSupport](http://docs.oracle.com/javase/6/docs/api/java/beans/PropertyChangeSupport.html). In a well coded Swing Control every change of a bean property fires a PropertyChangeEvent to all its listeners. The official Swing components offer this feature for all properties. Here is a short example that shows `PropertyChangeSupport` in a custom JComponent:
-
-{{< highlight java >}}
-public class JCustomComponent extends JComponent {
-
- private int volume;
-
- public int getVolume() {
- return volume;
- }
-
- public void setVolume(int volume) {
- int oldValue = this.volume;
- this.volume = volume;
- firePropertyChange("volume", oldValue, this.volume);
- }
-}
-{{< / highlight >}}
-
-It's quite simple to access this feature outside of the component:
-
-{{< highlight java >}}
-JCustomComponent customComponent = new JCustomComponent();
-customComponent.addPropertyChangeListener("volume", new PropertyChangeListener() {
-
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- System.out.println("Volume changed to " + evt.getNewValue());
- }
-});
-{{< / highlight >}}
-
-The problem is that all this stuff produces a lot of redundant code and do not last for modern and big applications.
-
-## Glue code and BeansBinding
-
-Most of the time `PropertyChangeSupport` is used in Swing applications to connect the view to a data model. By doing so a lot of code looks like this:
-
-{{< highlight java >}}
-//example code from http://goo.gl/T6Iqg
-slider.addValueListener(new ChangeListener() {
- public void stateChanged(ChangeEvent e) {
- selectedObject.setFoo(slider.getValue());
- }
-});
-
-selectedObject.addPropertyChangeListener(new PropertyChangeListener() {
- public void propertyChanged(PropertyChangeEvent e) {
- if (e.getPropertyName() == null || "foo".equals(e.getPropertyName())) {
- slider.setValue(selectedObject.getFoo());
- }
- }
-});
-{{< / highlight >}}
-
-This code is really painful and vulnerable to (copy & paste) errors. Thanks to the BeansBinding API the modern Swing developer do not need this glue code and simply bind properties. The API allow to bind two different properties with each other so that all changes are automatically adopted by the opposite side. Here is a short example of a binding:
-
-{{< highlight java >}}
-//example code from http://goo.gl/KmGz1
-Property slideValue = BeanProperty.create("value");
-Property tintValue = BeanProperty.create("tint");
-Binding tintBinding = Bindings.createAutoBinding(UpdateStrategy.READ, tintSlider, slideValue, tintedPanel, tintValue);
-tintBinding.bind();
-tintSlider.setValue(0);
-{{< / highlight >}}
-
-With the API you can create one way or bidirectional bindings. The difference is that in a one way binding only one side is a observer. In a bidirectional binding every change on any side is adopted by the opposite side.
-
-If you are interested in BeansBinding with Swing I suggest you to [read](http://today.java.net/pub/a/2008/03/20/synchronizing-properties-with-beans-binding.html) [this](http://weblogs.java.net/blog/zixle/archive/2006/05/ease_of_swing_d.html) [articles](https://blogs.oracle.com/geertjan/entry/beans_binding_via_the_road).
-
-## JavaFX Properties
-
-JavaFX includes the [`javafx.beans.property.Property`](http://docs.oracle.com/javafx/2/api/javafx/beans/property/Property.html) Interface that extend property handling and binding with some great features and a very simple but powerful API. All JavaFX controls use the property API to grant access to their fields. Normally next to the getter & setter methods there is a new method to access the property. Here is a example for the "double cellWidth" attribute of [GridView]({{< ref "/posts/2012-11-29-gridfx-is-moving-forward" >}}):
-
-{{< highlight java >}}
-private DoubleProperty cellWidth;
-
-public final DoubleProperty cellWidthProperty() {
- if (cellWidth == null) {
- cellWidth = new SimpleDoubleProperty(64);
- }
- return cellWidth;
-}
-
-public void setCellWidth(double value) {
- cellWidthProperty().set(value);
-}
-
-public double getCellWidth() {
- return cellWidth == null ? 64.0 : cellWidth.get();
-}
-{{< / highlight >}}
-
-As you can see there is no "double cellWidth" field in the code. Instead of this the attribute is wrapped in a Property. JavaFX offers a set of basic property classes for primitive datatypes like String or double. All this basic implementations are part of the package [`javafx.beans.property.*`](http://docs.oracle.com/javafx/2/api/javafx/beans/property/package-summary.html).
-
-The getter and setter methods work directly with the Property instance and set or request the current value from the property. Next to all this `Simple*Property` classes there are some special implementations like read only implementations that can be used if you want to prevent your field from external changes. In this case only removing the setter-method is not enough because you can access the Property instance. It's recommend to use `ReadOnly**Property` classes (like [`ReadOnlyDoubleProperty`](http://docs.oracle.com/javafx/2/api/javafx/beans/property/ReadOnlyDoubleProperty.html)) in this case.
-
-## The benefit of Properties
-
-By using the above described design for bean properties in JavaFX you will get a lot of pros in your code. First of all JavaFX properties offer support for [`ChangeListener`](http://docs.oracle.com/javafx/2/api/javafx/beans/value/ChangeListener.html). So you can add listeners to every property:
-
-{{< highlight java >}}
-SimpleStringProperty textProp = new SimpleStringProperty();
-textProp.addListener(new ChangeListener() {
-
- @Override
- public void changed(ObservableValue extends String> observableValue, String oldValue, String newValue) {
- System.out.println("Value changed: " + oldValue + " -> " + newValue);
- }
-});
-
-Slider mySlider = new Slider();
-mySlider.valueProperty().addListener(new ChangeListener() {
-
- @Override
- public void changed(ObservableValue extends Number> observableValue, Number oldValue, Number newValue) {
- System.out.println("Value changed!");
- }
-});
-{{< / highlight >}}
-
-The usage of `ChangeListener` in JavaFX is equivalent to PropertyChangeSupport in Swing. But in my eyes there are some benefits. The code looks much cleaner and it's very easy to add a listener to one specific field / property. In Swing you have to add the field name as a String parameter and produce plenty of refactoring risk. Next to the ChangeLister you can register [`InvalidationListener`](http://docs.oracle.com/javafx/2/api/javafx/beans/InvalidationListener.html) to your properties. You can read more about the difference between this two listener types [here](http://blog.netopyr.com/2012/02/08/when-to-use-a-changelistener-or-an-invalidationlistener/).
-
-## Let's bind this stuff
-
-Another and in my opinion the best feature of JavaFX properties is the binding function. For this the Property interface offers the following methods:
-
-{{< highlight java >}}
-void bind(javafx.beans.value.ObservableValue other);
-
-void unbind();
-
-boolean isBound();
-
-void bindBidirectional(javafx.beans.property.Property other);
-
-void unbindBidirectional(javafx.beans.property.Property other);
-{{< / highlight >}}
-
-By using this methods you can create bindings between JavaFX properties very easy and with much cleaner code than in Swing. In the following example the value of a slider will be bound to the cell width of a grid:
-
-{{< highlight java >}}
-GridView myGrid = new GridView<>();
-Slider columnWidthSlider = SliderBuilder.create().min(10).max(512).build();
-myGrid.cellWidthProperty().bind(columnWidthSlider.valueProperty());
-{{< / highlight >}}
-
-By doing so the change of the slider will directly change the cell width of the grid because this property is bound to the value property of the slider. You can see the result in a video (0:20):
-
-{{< vimeo 53462905 >}}
-
-By using the `bind(..)` method a change of the column width will not influence the slider value because we have a one way binding. But creating a bidirectional binding is easy as pie:
-
-{{< highlight java >}}
-Slider mySlider1 = SliderBuilder.create().min(10).max(512).build();
-Slider mySlider2 = SliderBuilder.create().min(10).max(512).build();
-mySlider1.valueProperty().bindBidirectional(mySlider2.valueProperty());
-{{< / highlight >}}
-
-Now whatever slider is changed, the other one will adopt it's value:
-
-{{< vimeo 57128737 >}}
-
-You can simply remove a binding by calling `property.unbind()` in your code.
-
-With this methods you can easily bind two or more properties with the same value type (String, double, etc.). But sometimes you need a more complex binding. Maybe you need to bind a slider value to the visible property of a label. The label should appear once the slider value reaches a maximum. The JavaFX Property API offers some conversion methods for this needs. Most property types provides specific methods that create a new binding. Here is an sample that uses some of this methods:
-
-{{< highlight java >}}
-Slider mySlider1 = new Slider();
-Label myLabel = LabelBuilder.create().text("ALERT!").visible(false).build();
-myLabel.visibleProperty().bind(mySlider1.valueProperty().multiply(2).greaterThan(100));
-{{< / highlight >}}
-
-In line 3 the valueProperty in converted to a new double binding that is always double the size of the wrapped property. Now by calling the greaterThan(..) method we create a boolean binding that is wrapped around the double binding. This bindings value is true while the wrapped value is > 100. So if the value of the slider is greater than 50 (50 * 2 > 100) the label will be visible:
-
-{{< vimeo 57133467 >}}
-
-Next to this functions there is the util class [`javafx.beans.binding.Bindings`](http://docs.oracle.com/javafx/2/api/javafx/beans/binding/Bindings.html) that provides a lot of additional functions and support. For example you can add converters to a binding by using this class:
-
-{{< highlight java >}}
-SimpleIntegerProperty intProp = new SimpleIntegerProperty();
-SimpleStringProperty textProp = new SimpleStringProperty();
-StringConverter extends Number> converter = new IntegerStringConverter();
-
-Bindings.bindBidirectional(textProp, intProp, (StringConverter)converter);
-{{< / highlight >}}
-
-Once you set the value of the StringProperty to "8" the IntegerProperty will update it's wrapped value to 8 and vice versa.
-
-You can read more about the Property API & binding [here](http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm).
-
-## Properties for custom controls
-
-For custom components in JavaFX it is highly recommend to provide properties for all attributes of the control. By doing so you and other developers can easily bind this attributes to other properties or add change listener to them. Many JavaFX APIs (basic & 3rdParty) support the Property API. For example the next release of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) will provide properties for all received data so that you can easily bind your control attributes to the data that will be loaded in background. So you can bind the items inside a ListView to the result of a REST request with only one line of code.
-
-One of my next tutorials will show how you can bind your custom control properties to CSS properties.
+---
+outdated: true
+showInBlog: false
+title: 'Custom UI Controls with JavaFX (Part3)'
+date: "2013-01-10"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'In this post I will explain the basic JavaFX Property API. I will first explain the old Swing way to better understand the idea of the new API and all problems that are solved by it.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this post I will explain the basic JavaFX Property API because most of the planed future tutorials will depend on Properties. I will first explain the old Swing way to better understand the idea of the new API and all problems that are solved by it.
+
+## Properties in Swing
+
+In Swing every Component is a [JavaBean](http://docs.oracle.com/javase/tutorial/javabeans/) and its fields (bean properties) are accessible by getters and setters. If you want to change the text of a button you have to call the setter method:
+
+```javajbutton.setText("click me");
+
+You can receive the current text by calling the getter method:
+
+String currentText = jbutton.getText();
```
+
+With this methods you can easily modify and control your user interface in a static way. For example you can receive and check all entered data by calling the required getter methods on your components once the save button is pressed.
+
+But in the last years user experience has changed. Data should be validated in the moment it has been entered by the user and the background color of a application should change on the fly while the user is dropping the mouse over the colorchooser. All this things can be done with Swing and [PropertyChangeSupport](http://docs.oracle.com/javase/6/docs/api/java/beans/PropertyChangeSupport.html). In a well coded Swing Control every change of a bean property fires a PropertyChangeEvent to all its listeners. The official Swing components offer this feature for all properties. Here is a short example that shows `PropertyChangeSupport` in a custom JComponent:
+
+```javapublic class JCustomComponent extends JComponent {
+
+ private int volume;
+
+ public int getVolume() {
+ return volume;
+ }
+
+ public void setVolume(int volume) {
+ int oldValue = this.volume;
+ this.volume = volume;
+ firePropertyChange("volume", oldValue, this.volume);
+ }
+}
```
+
+It's quite simple to access this feature outside of the component:
+
+```javaJCustomComponent customComponent = new JCustomComponent();
+customComponent.addPropertyChangeListener("volume", new PropertyChangeListener() {
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ System.out.println("Volume changed to " + evt.getNewValue());
+ }
+});
```
+
+The problem is that all this stuff produces a lot of redundant code and do not last for modern and big applications.
+
+## Glue code and BeansBinding
+
+Most of the time `PropertyChangeSupport` is used in Swing applications to connect the view to a data model. By doing so a lot of code looks like this:
+
+```java//example code from http://goo.gl/T6Iqg
+slider.addValueListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent e) {
+ selectedObject.setFoo(slider.getValue());
+ }
+});
+
+selectedObject.addPropertyChangeListener(new PropertyChangeListener() {
+ public void propertyChanged(PropertyChangeEvent e) {
+ if (e.getPropertyName() == null || "foo".equals(e.getPropertyName())) {
+ slider.setValue(selectedObject.getFoo());
+ }
+ }
+});
```
+
+This code is really painful and vulnerable to (copy & paste) errors. Thanks to the BeansBinding API the modern Swing developer do not need this glue code and simply bind properties. The API allow to bind two different properties with each other so that all changes are automatically adopted by the opposite side. Here is a short example of a binding:
+
+```java//example code from http://goo.gl/KmGz1
+Property slideValue = BeanProperty.create("value");
+Property tintValue = BeanProperty.create("tint");
+Binding tintBinding = Bindings.createAutoBinding(UpdateStrategy.READ, tintSlider, slideValue, tintedPanel, tintValue);
+tintBinding.bind();
+tintSlider.setValue(0);
```
+
+With the API you can create one way or bidirectional bindings. The difference is that in a one way binding only one side is a observer. In a bidirectional binding every change on any side is adopted by the opposite side.
+
+If you are interested in BeansBinding with Swing I suggest you to [read](http://today.java.net/pub/a/2008/03/20/synchronizing-properties-with-beans-binding.html) [this](http://weblogs.java.net/blog/zixle/archive/2006/05/ease_of_swing_d.html) [articles](https://blogs.oracle.com/geertjan/entry/beans_binding_via_the_road).
+
+## JavaFX Properties
+
+JavaFX includes the [`javafx.beans.property.Property`](http://docs.oracle.com/javafx/2/api/javafx/beans/property/Property.html) Interface that extend property handling and binding with some great features and a very simple but powerful API. All JavaFX controls use the property API to grant access to their fields. Normally next to the getter & setter methods there is a new method to access the property. Here is a example for the "double cellWidth" attribute of [GridView](/posts/2012-11-29-gridfx-is-moving-forward):
+
+```javaprivate DoubleProperty cellWidth;
+
+public final DoubleProperty cellWidthProperty() {
+ if (cellWidth == null) {
+ cellWidth = new SimpleDoubleProperty(64);
+ }
+ return cellWidth;
+}
+
+public void setCellWidth(double value) {
+ cellWidthProperty().set(value);
+}
+
+public double getCellWidth() {
+ return cellWidth == null ? 64.0 : cellWidth.get();
+}
```
+
+As you can see there is no "double cellWidth" field in the code. Instead of this the attribute is wrapped in a Property. JavaFX offers a set of basic property classes for primitive datatypes like String or double. All this basic implementations are part of the package [`javafx.beans.property.*`](http://docs.oracle.com/javafx/2/api/javafx/beans/property/package-summary.html).
+
+The getter and setter methods work directly with the Property instance and set or request the current value from the property. Next to all this `Simple*Property` classes there are some special implementations like read only implementations that can be used if you want to prevent your field from external changes. In this case only removing the setter-method is not enough because you can access the Property instance. It's recommend to use `ReadOnly**Property` classes (like [`ReadOnlyDoubleProperty`](http://docs.oracle.com/javafx/2/api/javafx/beans/property/ReadOnlyDoubleProperty.html)) in this case.
+
+## The benefit of Properties
+
+By using the above described design for bean properties in JavaFX you will get a lot of pros in your code. First of all JavaFX properties offer support for [`ChangeListener`](http://docs.oracle.com/javafx/2/api/javafx/beans/value/ChangeListener.html). So you can add listeners to every property:
+
+```javaSimpleStringProperty textProp = new SimpleStringProperty();
+textProp.addListener(new ChangeListener() {
+
+ @Override
+ public void changed(ObservableValue extends String> observableValue, String oldValue, String newValue) {
+ System.out.println("Value changed: " + oldValue + " -> " + newValue);
+ }
+});
+
+Slider mySlider = new Slider();
+mySlider.valueProperty().addListener(new ChangeListener() {
+
+ @Override
+ public void changed(ObservableValue extends Number> observableValue, Number oldValue, Number newValue) {
+ System.out.println("Value changed!");
+ }
+});
```
+
+The usage of `ChangeListener` in JavaFX is equivalent to PropertyChangeSupport in Swing. But in my eyes there are some benefits. The code looks much cleaner and it's very easy to add a listener to one specific field / property. In Swing you have to add the field name as a String parameter and produce plenty of refactoring risk. Next to the ChangeLister you can register [`InvalidationListener`](http://docs.oracle.com/javafx/2/api/javafx/beans/InvalidationListener.html) to your properties. You can read more about the difference between this two listener types [here](http://blog.netopyr.com/2012/02/08/when-to-use-a-changelistener-or-an-invalidationlistener/).
+
+## Let's bind this stuff
+
+Another and in my opinion the best feature of JavaFX properties is the binding function. For this the Property interface offers the following methods:
+
+```javavoid bind(javafx.beans.value.ObservableValue other);
+
+void unbind();
+
+boolean isBound();
+
+void bindBidirectional(javafx.beans.property.Property other);
+
+void unbindBidirectional(javafx.beans.property.Property other);
```
+
+By using this methods you can create bindings between JavaFX properties very easy and with much cleaner code than in Swing. In the following example the value of a slider will be bound to the cell width of a grid:
+
+```javaGridView myGrid = new GridView<>();
+Slider columnWidthSlider = SliderBuilder.create().min(10).max(512).build();
+myGrid.cellWidthProperty().bind(columnWidthSlider.valueProperty());
```
+
+By doing so the change of the slider will directly change the cell width of the grid because this property is bound to the value property of the slider. You can see the result in a video (0:20):
+
+
+
+By using the `bind(..)` method a change of the column width will not influence the slider value because we have a one way binding. But creating a bidirectional binding is easy as pie:
+
+```javaSlider mySlider1 = SliderBuilder.create().min(10).max(512).build();
+Slider mySlider2 = SliderBuilder.create().min(10).max(512).build();
+mySlider1.valueProperty().bindBidirectional(mySlider2.valueProperty());
```
+
+Now whatever slider is changed, the other one will adopt it's value:
+
+
+
+You can simply remove a binding by calling `property.unbind()` in your code.
+
+With this methods you can easily bind two or more properties with the same value type (String, double, etc.). But sometimes you need a more complex binding. Maybe you need to bind a slider value to the visible property of a label. The label should appear once the slider value reaches a maximum. The JavaFX Property API offers some conversion methods for this needs. Most property types provides specific methods that create a new binding. Here is an sample that uses some of this methods:
+
+```javaSlider mySlider1 = new Slider();
+Label myLabel = LabelBuilder.create().text("ALERT!").visible(false).build();
+myLabel.visibleProperty().bind(mySlider1.valueProperty().multiply(2).greaterThan(100));
```
+
+In line 3 the valueProperty in converted to a new double binding that is always double the size of the wrapped property. Now by calling the greaterThan(..) method we create a boolean binding that is wrapped around the double binding. This bindings value is true while the wrapped value is > 100. So if the value of the slider is greater than 50 (50 * 2 > 100) the label will be visible:
+
+
+
+Next to this functions there is the util class [`javafx.beans.binding.Bindings`](http://docs.oracle.com/javafx/2/api/javafx/beans/binding/Bindings.html) that provides a lot of additional functions and support. For example you can add converters to a binding by using this class:
+
+```javaSimpleIntegerProperty intProp = new SimpleIntegerProperty();
+SimpleStringProperty textProp = new SimpleStringProperty();
+StringConverter extends Number> converter = new IntegerStringConverter();
+
+Bindings.bindBidirectional(textProp, intProp, (StringConverter)converter);
```
+
+Once you set the value of the StringProperty to "8" the IntegerProperty will update it's wrapped value to 8 and vice versa.
+
+You can read more about the Property API & binding [here](http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm).
+
+## Properties for custom controls
+
+For custom components in JavaFX it is highly recommend to provide properties for all attributes of the control. By doing so you and other developers can easily bind this attributes to other properties or add change listener to them. Many JavaFX APIs (basic & 3rdParty) support the Property API. For example the next release of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) will provide properties for all received data so that you can easily bind your control attributes to the data that will be loaded in background. So you can bind the items inside a ListView to the result of a REST request with only one line of code.
+
+One of my next tutorials will show how you can bind your custom control properties to CSS properties.
diff --git a/content/posts/2013-01-16-this-is-for-the-native-ones.md b/content/posts/2013-01-16-this-is-for-the-native-ones.md
index b101d681..7d6590fa 100644
--- a/content/posts/2013-01-16-this-is-for-the-native-ones.md
+++ b/content/posts/2013-01-16-this-is-for-the-native-ones.md
@@ -1,94 +1,90 @@
----
-outdated: true
-showInBlog: false
-title: 'This is for the native ones'
-date: "2013-01-16"
-author: hendrik
-categories: [AquaFX, General, JavaFX]
-excerpt: 'JavaFX provides the ability to style controls by CSS or code. We are using this functionallity to create native looking controls.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-As you can read in an [earlier post]({{< ref "/posts/2012-11-17-custom-ui-controls-with-javafx-part-1" >}}), JavaFX provides the ability to style controls by CSS or code. Most of the techniques you can use to style components are described in [this great JavaOne talk by Gerrit Grunwald](https://oracleus.activeevents.com/connect/sessionDetail.ww?SESSION_ID=2425). The following graphic shows the basic relationship between all parts that are involved in component styling:
-
-
-
-As you can see in the graphic, the CSS file is the main entry point for the Control styling. The CSS defines UI related properties like colors or fonts. In addition to this the CSS specifies the Skin class that will be used to style the Control.
-
-## Official JavaFX styles
-
-JavaFX currently offers one system independent style that is named "Caspian". The style is completely defined in one CSS file:
-
-{{< highlight java >}}
-com.sun.javafx.scene.control.skin.caspian.caspian.css
-{{< / highlight >}}
-
-Oracle and the JavaFX team did a really great job by designing this cross platform skin. I my opinion it looks great on every OS. Here is a short extract of the Style:
-
-
-
-You can see the complete blueprint [here](http://javafx-jira.kenai.com/secure/attachment/34815/Caspian.png) (you need to be logged in to OpenJFX Jira). The Caspian style offers definitions for all default JavaFX controls.
-
-The following chart describes the style handling for the JavaFX Button with the official caspian CSS file:
-
-
-
-While JavaFX 2.x only offers the caspian style, JavaFX 8 will provide a second one called "Modena".
-
-
-
-Here you can see a preview of Buttons with Modena style. Compared to Caspian it's brighter and the controls look a little flatter. Modena is still in development and can change all the time until JavaFX 8 will be released.
-
-While the current preview of Modena really looks great (see full preview at OpenJFX Jira [http://javafx-jira.kenai.com/secure/attachment/34814/Modena-v0.1.png](here)) it's still a cross platform Look & Feel. You can compare the "Caspian" and "Modena" styles to the "Metal" and "Nimbus" Look & Feel of Swing. Both are designed for cross platform use, too. But Swing benefit are the system L&Fs. So if you have to develop a application with a native look, you currently have to use Swing because it offers native Look & Feels for Windows, Mac OS and Linux. But since JavaFX 2.x is out we do not want to use Swing anymore :)
-
-## Native JavaFX styles
-
-As described above JavaFX officially only offers cross platform skins. According to a [mail by Richard Bair](http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-January/005281.html) from the JavaFX mailing list oracle won't provide native skins for JavaFX in the near future.
-
-Thanks to the great JavaFX community the first approaches for native styles appeared the last month. Jasper Potts created some [basic CSS styles for buttons](http://fxexperience.com/2011/12/styling-fx-buttons-with-css/) that copy the native style of iOS, Mac OS Lion and Windows 7.
-
-
-
-The second starting point is [JMetro](http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/), a project maintained by [Pedro Duque Vieira](http://twitter.com/P_Duke), that provides Windows 8 Metro skins for JavaFX controls with the support of a dark and a light theme.
-
-
-
-
-
-JMetro is part of [JFXtras](http://jfxtras.org) and can be found at [github](https://github.com/JFXtras/jfxtras-styles). While writing this post the following controls are supported by JMetro:
-
-* Button
-* ToggleButton
-* CheckBox
-* RadioButton
-* ContextMenu
-* MenuItem
-* ScrollBar
-* ScrollPane
-* ComboBox
-
-The next supported Control will be the JFXtras Calender Control. You can find a cool preview [here](http://pixelduke.wordpress.com/2013/01/14/java-calendar-with-a-metro-style/).
-
-The last approach I've found is from [software4java](http://blog.software4java.com). On this blog you can find some pictures and videos of [iOS](http://blog.software4java.com/?p=27), [Mac OS and Windows 7 related styles](http://blog.software4java.com/?p=15) for JavaFX. But there is no activity since April 2012 and the sources were never provided.
-
-## JavaFX goes Aqua
-
-The current community based projects demonstrate that it's possible to create native looking skins for JavaFX controls. According to this conditions a student I'm currently responsible for is planning the bachelor of science thesis based on JavaFX. Currently it is planned to develop a native JavaFX skin for Mac OS. The project should combine skins for JavaFX controls like it's done with JMetro and provide new Mac specific controls on the other hand like [macwidgets](http://code.google.com/p/macwidgets/) does for Java Swing.
-
-We have done a first prove of concept and are happy to share the result with you. Do you find out which shutdown window is the native one and which one is developed in JavaFX?
-
-{{< youtube GbJDg5wsJ9E >}}
-
-
-Our first code is hacked in many ways and needs a lot of refactoring for sure. But it was a lot of fun and we learned a lot about CSS and JavaFX skins. Even if it's hacked at some points we do not use any bitmaps. Everything is done with CSS, JavaFX effects and the SVG support. We created some basic concepts how to create this aqua related skins for JavaFX. The following chart shows the class relations and inheritance for a Button:
-
-
-
-As you can see we still use the basic Button class from JavaFX. So every Button can be skinned to a Aqua Button. The Button will be styled by a special Skin class ("AquaButtonSkin") because the usage of CSS isn't enough for some points. As you can see in the video the default button of a dialog has a blinking animation in MacOS. This effect can't be generated by CSS. But because there is only one global CSS file for the Aqua Skin you can style a complete application (once every control type is supported) by only adding one line to your code. As described at the beginning of this article all Skin classes are defined inside the CSS and will be managed by JavaFX automatically. Here is the code to set the style to your application:
-
-{{< highlight java >}}
-myScene.getStylesheets().add(AquaSkin.getStylesheet());
-{{< / highlight >}}
-
-## One last hurdle
-
-We currently defining the proposal of the thesis and plan to submit it next week. The topic of the project is not really typical for an exam and it's not supported by a company. But we like the topic and open source development a lot more than a project that is related to our company so we chose this one. It could be difficult to convince the university of this project. Maybe some feedback from the JavaFX community can help. So if you like this idea (or even if you have some critique) please give us a short review or feedback. We hope that we can confirm the benefit of this project this way.
+---
+outdated: true
+showInBlog: false
+title: 'This is for the native ones'
+date: "2013-01-16"
+author: hendrik
+categories: [AquaFX, General, JavaFX]
+excerpt: 'JavaFX provides the ability to style controls by CSS or code. We are using this functionallity to create native looking controls.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+As you can read in an [earlier post](/posts/2012-11-17-custom-ui-controls-with-javafx-part-1), JavaFX provides the ability to style controls by CSS or code. Most of the techniques you can use to style components are described in [this great JavaOne talk by Gerrit Grunwald](https://oracleus.activeevents.com/connect/sessionDetail.ww?SESSION_ID=2425). The following graphic shows the basic relationship between all parts that are involved in component styling:
+
+
+
+As you can see in the graphic, the CSS file is the main entry point for the Control styling. The CSS defines UI related properties like colors or fonts. In addition to this the CSS specifies the Skin class that will be used to style the Control.
+
+## Official JavaFX styles
+
+JavaFX currently offers one system independent style that is named "Caspian". The style is completely defined in one CSS file:
+
+```javacom.sun.javafx.scene.control.skin.caspian.caspian.css
```
+
+Oracle and the JavaFX team did a really great job by designing this cross platform skin. I my opinion it looks great on every OS. Here is a short extract of the Style:
+
+
+
+You can see the complete blueprint [here](http://javafx-jira.kenai.com/secure/attachment/34815/Caspian.png) (you need to be logged in to OpenJFX Jira). The Caspian style offers definitions for all default JavaFX controls.
+
+The following chart describes the style handling for the JavaFX Button with the official caspian CSS file:
+
+
+
+While JavaFX 2.x only offers the caspian style, JavaFX 8 will provide a second one called "Modena".
+
+
+
+Here you can see a preview of Buttons with Modena style. Compared to Caspian it's brighter and the controls look a little flatter. Modena is still in development and can change all the time until JavaFX 8 will be released.
+
+While the current preview of Modena really looks great (see full preview at OpenJFX Jira [http://javafx-jira.kenai.com/secure/attachment/34814/Modena-v0.1.png](here)) it's still a cross platform Look & Feel. You can compare the "Caspian" and "Modena" styles to the "Metal" and "Nimbus" Look & Feel of Swing. Both are designed for cross platform use, too. But Swing benefit are the system L&Fs. So if you have to develop a application with a native look, you currently have to use Swing because it offers native Look & Feels for Windows, Mac OS and Linux. But since JavaFX 2.x is out we do not want to use Swing anymore :)
+
+## Native JavaFX styles
+
+As described above JavaFX officially only offers cross platform skins. According to a [mail by Richard Bair](http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-January/005281.html) from the JavaFX mailing list oracle won't provide native skins for JavaFX in the near future.
+
+Thanks to the great JavaFX community the first approaches for native styles appeared the last month. Jasper Potts created some [basic CSS styles for buttons](http://fxexperience.com/2011/12/styling-fx-buttons-with-css/) that copy the native style of iOS, Mac OS Lion and Windows 7.
+
+
+
+The second starting point is [JMetro](http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/), a project maintained by [Pedro Duque Vieira](http://twitter.com/P_Duke), that provides Windows 8 Metro skins for JavaFX controls with the support of a dark and a light theme.
+
+
+
+
+
+JMetro is part of [JFXtras](http://jfxtras.org) and can be found at [github](https://github.com/JFXtras/jfxtras-styles). While writing this post the following controls are supported by JMetro:
+
+* Button
+* ToggleButton
+* CheckBox
+* RadioButton
+* ContextMenu
+* MenuItem
+* ScrollBar
+* ScrollPane
+* ComboBox
+
+The next supported Control will be the JFXtras Calender Control. You can find a cool preview [here](http://pixelduke.wordpress.com/2013/01/14/java-calendar-with-a-metro-style/).
+
+The last approach I've found is from [software4java](http://blog.software4java.com). On this blog you can find some pictures and videos of [iOS](http://blog.software4java.com/?p=27), [Mac OS and Windows 7 related styles](http://blog.software4java.com/?p=15) for JavaFX. But there is no activity since April 2012 and the sources were never provided.
+
+## JavaFX goes Aqua
+
+The current community based projects demonstrate that it's possible to create native looking skins for JavaFX controls. According to this conditions a student I'm currently responsible for is planning the bachelor of science thesis based on JavaFX. Currently it is planned to develop a native JavaFX skin for Mac OS. The project should combine skins for JavaFX controls like it's done with JMetro and provide new Mac specific controls on the other hand like [macwidgets](http://code.google.com/p/macwidgets/) does for Java Swing.
+
+We have done a first prove of concept and are happy to share the result with you. Do you find out which shutdown window is the native one and which one is developed in JavaFX?
+
+
+
+
+Our first code is hacked in many ways and needs a lot of refactoring for sure. But it was a lot of fun and we learned a lot about CSS and JavaFX skins. Even if it's hacked at some points we do not use any bitmaps. Everything is done with CSS, JavaFX effects and the SVG support. We created some basic concepts how to create this aqua related skins for JavaFX. The following chart shows the class relations and inheritance for a Button:
+
+
+
+As you can see we still use the basic Button class from JavaFX. So every Button can be skinned to a Aqua Button. The Button will be styled by a special Skin class ("AquaButtonSkin") because the usage of CSS isn't enough for some points. As you can see in the video the default button of a dialog has a blinking animation in MacOS. This effect can't be generated by CSS. But because there is only one global CSS file for the Aqua Skin you can style a complete application (once every control type is supported) by only adding one line to your code. As described at the beginning of this article all Skin classes are defined inside the CSS and will be managed by JavaFX automatically. Here is the code to set the style to your application:
+
+```javamyScene.getStylesheets().add(AquaSkin.getStylesheet());
```
+
+## One last hurdle
+
+We currently defining the proposal of the thesis and plan to submit it next week. The topic of the project is not really typical for an exam and it's not supported by a company. But we like the topic and open source development a lot more than a project that is related to our company so we chose this one. It could be difficult to convince the university of this project. Maybe some feedback from the JavaFX community can help. So if you like this idea (or even if you have some critique) please give us a short review or feedback. We hope that we can confirm the benefit of this project this way.
diff --git a/content/posts/2013-02-09-datafx-observableexecutor-preview.md b/content/posts/2013-02-09-datafx-observableexecutor-preview.md
index 2cec93f3..77c8ce4f 100644
--- a/content/posts/2013-02-09-datafx-observableexecutor-preview.md
+++ b/content/posts/2013-02-09-datafx-observableexecutor-preview.md
@@ -1,44 +1,40 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX: ObservableExecutor Preview'
-date: "2013-02-09"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'Since December we are working on a new DataFX version. DataFX will provide a new low level API for multithreading and background tasks in JavaFX.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Since December we are working on a new [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) version. DataFX will provide a new low level API for multithreading and background tasks in JavaFX. With this API everyone can create new and custom DataSources that will fetch data in background and publish it to JavaFX properties (like you can do with the SwingWorker in Swing). Additionally we will provide some basic concurrency features like the [invokeAndWait-method]({{< ref "/posts/2013-01-01-invokeandwait-for-javafx" >}}).
-
-Next to this features we created a new [Executor](http://docs.oracle.com/javase/tutorial/essential/concurrency/exinter.html) class that offers some additional features for the use with JavaFX. The `ObservableExecutor` holds a ListProperty with all currently scheduled or running tasks. By using this Property you can easily observe all tasks in your UI. We will provide a ListCell class to visualize the running tasks of the executor with only a few lines of code:
-
-{{< highlight java >}}
-Executor executor = new ObservableExecutor();
-ListView> list = new ListView<>();
-list.setCellFactory(new ServiceListCellFactory());
-list.itemsProperty().bind(executor.currentServicesProperty());
-{{< / highlight >}}
-
-The ObservableExecutor uses the wrapper pattern to hold any Executor. Because all task are wrapped into [Services](http://docs.oracle.com/javafx/2/api/javafx/concurrent/Service.html) you can easily access the title, message or progress of any task. A short example that shows the current state of the API can be found here:
-
-{{< youtube eQaVNQKy1U0 >}}
-
-Because Runnable & Callable normally do not provide title, message and progress properties we created extended interfaces (`DataFXRunnable` & `DataFXCallable`) where all this functions are injected while using them with the ObservableExecutor.
-
-At the current state tasks can be passed to an `ObservableExecutor` by the following methods:
-
-{{< highlight java >}}
-public Worker submit(Service service);
-
-public Worker submit(Task task);
-
-public Worker submit(Callable callable);
-
-public Worker submit(Runnable runnable);
-
-public void execute(Runnable runnable);
-{{< / highlight >}}
-
-There are some additional features, too. You can mark a task as not cancelable for example.
-
-Hope you like this stuff!
+---
+outdated: true
+showInBlog: false
+title: 'DataFX: ObservableExecutor Preview'
+date: "2013-02-09"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'Since December we are working on a new DataFX version. DataFX will provide a new low level API for multithreading and background tasks in JavaFX.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Since December we are working on a new [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) version. DataFX will provide a new low level API for multithreading and background tasks in JavaFX. With this API everyone can create new and custom DataSources that will fetch data in background and publish it to JavaFX properties (like you can do with the SwingWorker in Swing). Additionally we will provide some basic concurrency features like the [invokeAndWait-method](/posts/2013-01-01-invokeandwait-for-javafx).
+
+Next to this features we created a new [Executor](http://docs.oracle.com/javase/tutorial/essential/concurrency/exinter.html) class that offers some additional features for the use with JavaFX. The `ObservableExecutor` holds a ListProperty with all currently scheduled or running tasks. By using this Property you can easily observe all tasks in your UI. We will provide a ListCell class to visualize the running tasks of the executor with only a few lines of code:
+
+```javaExecutor executor = new ObservableExecutor();
+ListView> list = new ListView<>();
+list.setCellFactory(new ServiceListCellFactory());
+list.itemsProperty().bind(executor.currentServicesProperty());
```
+
+The ObservableExecutor uses the wrapper pattern to hold any Executor. Because all task are wrapped into [Services](http://docs.oracle.com/javafx/2/api/javafx/concurrent/Service.html) you can easily access the title, message or progress of any task. A short example that shows the current state of the API can be found here:
+
+
+
+Because Runnable & Callable normally do not provide title, message and progress properties we created extended interfaces (`DataFXRunnable` & `DataFXCallable`) where all this functions are injected while using them with the ObservableExecutor.
+
+At the current state tasks can be passed to an `ObservableExecutor` by the following methods:
+
+```javapublic Worker submit(Service service);
+
+public Worker submit(Task task);
+
+public Worker submit(Callable callable);
+
+public Worker submit(Runnable runnable);
+
+public void execute(Runnable runnable);
```
+
+There are some additional features, too. You can mark a task as not cancelable for example.
+
+Hope you like this stuff!
diff --git a/content/posts/2013-03-02-global-stylesheet-for-your-javafx-application.md b/content/posts/2013-03-02-global-stylesheet-for-your-javafx-application.md
index 0bcc1c24..958a34d1 100644
--- a/content/posts/2013-03-02-global-stylesheet-for-your-javafx-application.md
+++ b/content/posts/2013-03-02-global-stylesheet-for-your-javafx-application.md
@@ -1,47 +1,37 @@
----
-outdated: true
-showInBlog: false
-title: 'Global Stylesheet for your JavaFX Application'
-date: "2013-03-02"
-author: hendrik
-categories: [General, JavaFX]
-excerpt: 'There is a way to set a global Stylesheet to all JavaFX Scenes in your app. By using the JavaFX 8 class StyleManager you can define the default CSS files.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-You can style your JavaFX [Scene](http://docs.oracle.com/javafx/2/api/javafx/scene/Scene.html) by CSS as you can read [here]({{< ref "/posts/2013-01-16-this-is-for-the-native-ones" >}}) and [here](http://docs.oracle.com/javafx/2/css_tutorial/jfxpub-css_tutorial.htm). All this examples show how to apply a specific Stylesheet to one Scene by using
-
-{{< highlight java >}}
-myScene.getStylesheets().add("path/to/custom.css");
-{{< / highlight >}}
-
-Inside the SceneGraph of this Scene all Nodes will use the defined Stylesheets. But while your Application grows you will normally have more than one Scene. Each [Window](http://docs.oracle.com/javafx/2/api/javafx/stage/Window.html) in JavaFX holds its own Scene. Even if your Application only uses one [Stage](http://docs.oracle.com/javafx/2/api/javafx/stage/Stage.html) you will normally have more than one window while every [ContextMenu](http://docs.oracle.com/javafx/2/api/javafx/scene/control/ContextMenu.html) is Window. So if you use custom ContextMenus or a [ChoiceBox](http://docs.oracle.com/javafx/2/api/javafx/scene/control/ChoiceBox.html) inside your application this Components will technically be displayed in a separate Window with a new Scene and SceneGraph. But with the code mentioned above only "myScene" will use the custom Stylesheet. The Scene of the ContextMenu will not be affected by this. One trick here is to set the Stylesheet manually to the Scene of the Window:
-
-{{< highlight java >}}
-myContextMenu.getScene().getStylesheets().add("path/to/custom.css");
-{{< / highlight >}}
-
-But this is only a bad workaround and you won't do this for every ContextMenu. When you use a ChoiceBox you even can't access the Scene of the popup because this is defined in private methods of the ChoiceBoxSkin.
-
-But there is a way to set a global Stylesheet to all Scenes. By using the JavaFX 8 class StyleManager you can define the default CSS files. The class uses the singleton pattern and can easily accepted. The following code will add a CSS file to all Stylesheets of all Scenes:
-
-{{< highlight java >}}
-StyleManager.getInstance().addUserAgentStylesheet(AQUA_CSS_NAME);
-{{< / highlight >}}
-
-Currently there is one bug with this. The default Stylesheet (currently [caspian]({{< ref "/posts/2013-01-16-this-is-for-the-native-ones" >}})) is defined inside the StyleManger, too. But the default will not be set until a first Node is created. When adding a additional user defined Stylesheet a Exception is thrown. So to avoid problems you have to set the default CSS before adding a custom one. This can currently only done by calling a private API:
-
-{{< highlight java >}}
-PlatformImpl.setDefaultPlatformUserAgentStylesheet();
-StyleManager.getInstance().addUserAgentStylesheet(AQUA_CSS_NAME);
-{{< / highlight >}}
-
-I will open a issue at [http://javafx-jira.kenai.com](http://javafx-jira.kenai.com) about this behavior.
-
-## Addition
-
-With the help of Jonathan Giles I found a better way without using private APIs. You can easily set the default stylesheet by using "Application.setUserAgentStylesheet(String url)". If you use null as parameter value the default stylesheet (currently caspian) will be used. So here is the code without using a private API:
-
-{{< highlight java >}}
-Application.setUserAgentStylesheet(null);
-StyleManager.getInstance().addUserAgentStylesheet(AQUA_CSS_NAME);
-{{< / highlight >}}
+---
+outdated: true
+showInBlog: false
+title: 'Global Stylesheet for your JavaFX Application'
+date: "2013-03-02"
+author: hendrik
+categories: [General, JavaFX]
+excerpt: 'There is a way to set a global Stylesheet to all JavaFX Scenes in your app. By using the JavaFX 8 class StyleManager you can define the default CSS files.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+You can style your JavaFX [Scene](http://docs.oracle.com/javafx/2/api/javafx/scene/Scene.html) by CSS as you can read [here](/posts/2013-01-16-this-is-for-the-native-ones) and [here](http://docs.oracle.com/javafx/2/css_tutorial/jfxpub-css_tutorial.htm). All this examples show how to apply a specific Stylesheet to one Scene by using
+
+```javamyScene.getStylesheets().add("path/to/custom.css");
```
+
+Inside the SceneGraph of this Scene all Nodes will use the defined Stylesheets. But while your Application grows you will normally have more than one Scene. Each [Window](http://docs.oracle.com/javafx/2/api/javafx/stage/Window.html) in JavaFX holds its own Scene. Even if your Application only uses one [Stage](http://docs.oracle.com/javafx/2/api/javafx/stage/Stage.html) you will normally have more than one window while every [ContextMenu](http://docs.oracle.com/javafx/2/api/javafx/scene/control/ContextMenu.html) is Window. So if you use custom ContextMenus or a [ChoiceBox](http://docs.oracle.com/javafx/2/api/javafx/scene/control/ChoiceBox.html) inside your application this Components will technically be displayed in a separate Window with a new Scene and SceneGraph. But with the code mentioned above only "myScene" will use the custom Stylesheet. The Scene of the ContextMenu will not be affected by this. One trick here is to set the Stylesheet manually to the Scene of the Window:
+
+```javamyContextMenu.getScene().getStylesheets().add("path/to/custom.css");
```
+
+But this is only a bad workaround and you won't do this for every ContextMenu. When you use a ChoiceBox you even can't access the Scene of the popup because this is defined in private methods of the ChoiceBoxSkin.
+
+But there is a way to set a global Stylesheet to all Scenes. By using the JavaFX 8 class StyleManager you can define the default CSS files. The class uses the singleton pattern and can easily accepted. The following code will add a CSS file to all Stylesheets of all Scenes:
+
+```javaStyleManager.getInstance().addUserAgentStylesheet(AQUA_CSS_NAME);
```
+
+Currently there is one bug with this. The default Stylesheet (currently [caspian](/posts/2013-01-16-this-is-for-the-native-ones)) is defined inside the StyleManger, too. But the default will not be set until a first Node is created. When adding a additional user defined Stylesheet a Exception is thrown. So to avoid problems you have to set the default CSS before adding a custom one. This can currently only done by calling a private API:
+
+```javaPlatformImpl.setDefaultPlatformUserAgentStylesheet();
+StyleManager.getInstance().addUserAgentStylesheet(AQUA_CSS_NAME);
```
+
+I will open a issue at [http://javafx-jira.kenai.com](http://javafx-jira.kenai.com) about this behavior.
+
+## Addition
+
+With the help of Jonathan Giles I found a better way without using private APIs. You can easily set the default stylesheet by using "Application.setUserAgentStylesheet(String url)". If you use null as parameter value the default stylesheet (currently caspian) will be used. So here is the code without using a private API:
+
+```javaApplication.setUserAgentStylesheet(null);
+StyleManager.getInstance().addUserAgentStylesheet(AQUA_CSS_NAME);
```
diff --git a/content/posts/2013-03-02-update-for-the-native-ones.md b/content/posts/2013-03-02-update-for-the-native-ones.md
index 42b7e3a6..0735705c 100644
--- a/content/posts/2013-03-02-update-for-the-native-ones.md
+++ b/content/posts/2013-03-02-update-for-the-native-ones.md
@@ -8,7 +8,7 @@ categories: [AquaFX, General, JavaFX]
excerpt: 'I was keen on starting with the first components for the native Look and Feel for JavaFX. Now I want to show you what is the result.'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-Since [my project]({{< ref "/posts/2013-01-16-this-is-for-the-native-ones" >}}) was accepted, I was keen on starting with the first components. Now I want to show you what is the result.
+Since [my project](/posts/2013-01-16-this-is-for-the-native-ones) was accepted, I was keen on starting with the first components. Now I want to show you what is the result.
## Remember the shutdown dialog?
@@ -68,7 +68,7 @@ The good news in this context is, that all of this stuff works on retina- and no
There are some points, which had to be decided before I really could start and which are not absolutely clear.
-Currently all CSS-styling is overriding caspian.css, as it is the default style. But we all look forward to modena replacing caspian for JavaFX 8. This may cause some trouble in future concerning new controls, which do not have Mac OS-Styling yet. For this reason, it is not that clear, how to apply mac_os.css to an application. Hendrik describes the different variations using the StyleManager in [his latest blogpost]({{< ref "/posts/2013-03-02-global-stylesheet-for-your-javafx-application" >}}). Thoughtless usage of style management also causes trouble with PopUp-components.
+Currently all CSS-styling is overriding caspian.css, as it is the default style. But we all look forward to modena replacing caspian for JavaFX 8. This may cause some trouble in future concerning new controls, which do not have Mac OS-Styling yet. For this reason, it is not that clear, how to apply mac_os.css to an application. Hendrik describes the different variations using the StyleManager in [his latest blogpost](/posts/2013-03-02-global-stylesheet-for-your-javafx-application). Thoughtless usage of style management also causes trouble with PopUp-components.
The main approach in styling the components is, using CSS as much as possible. Everything, that is not possible in CSS e.g. multiple effects on one component or animations is implemented in Aqua*Skins, which simply override the skin of the affected control. In this way, effects and animations are no problem.
diff --git a/content/posts/2013-03-17-introducing-marvinfx.md b/content/posts/2013-03-17-introducing-marvinfx.md
index c544f40b..48b2ecdf 100644
--- a/content/posts/2013-03-17-introducing-marvinfx.md
+++ b/content/posts/2013-03-17-introducing-marvinfx.md
@@ -1,125 +1,115 @@
----
-outdated: true
-showInBlog: false
-title: 'Introducing MarvinFx'
-date: "2013-03-17"
-author: hendrik
-categories: [JavaFX]
-excerpt: "For all my current JavaFX work I need a simple test framework to check the behavior of controls or complete scenes. Since I'm working more and more with the Property API I mainly wanted to to test the properties and their behavior of controls and scenes."
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-For all my current JavaFX work I need a simple test framework to check the behavior of controls or complete scenes. Since I'm working more and more with the [Property API]({{< ref "/posts/2013-01-10-custom-ui-controls-with-javafx-part3" >}}) I mainly wanted to to test the properties and their behavior of controls and scenes.
-
-[FEST](http://fest.easytesting.org) is doing a great job for automated tests in Swing and with [JemmyFX](http://jemmy.java.net/JemmyFXGuide/jemmy-guide.html) a first framework for JavaFX is available. But both of this framework don't have a (good) support for Properties.
-
-Because of this I started my own testing framework for JavaFX. [MarvinFX](https://github.com/guigarage/MarvinFX) has the goal to easily test JavaFX controls and scenes with a special attention on properties. The framework is currently in a very early state and only a few parts are implemented. But I think that already the current state can point out where the journey will lead. And maybe I will receive some helpful suggestions.
-
-You can simply use MarvinFX with a JUnit test. By using Marvin you can create a JavaFX Scene of the Application part you want to test:
-
-{{< highlight java >}}
-@Test
-public void test1() {
- Button b1 = new Button("Test123");
- MarvinFx.show(b1);
-}
-{{< / highlight >}}
-
-Marvin will generate a Parent (StackPane) for the Button and put everything in a Scene. The Scene will automatically be shown on the screen.
-
-To test parts of the ui you need a Robot that will generate user interactions for you. It is planned that MarvinFX will provide a OS based robot (by `AWTRobot`) and a Java based robot (by `JFXRobot`) under the surface. At the current state the mouse handling of the robot is working.
-
-{{< highlight java >}}
-@Test
-public void test2() {
- Button b1 = new Button("Test123");
- MarvinFx.show(b1);
- NodeFixture
- TextfieldFixture textfieldFixture = new TextfieldFixture<>(textField);
- StringPropertySupervisor supervisor = textfieldFixture.createTextPropertySupervisor();
- supervisor.assertStringEndsWith("MarvFX");
- supervisor.assertStringStartsWith("Hello");
- supervisor.assertStringLenghtIsEquals(12);
- supervisor.assertStringLenghtIsGreaterThan(11);
- supervisor.assertStringLenghtIsLessThan(13);
-}
-{{< / highlight >}}
-
-All this methods work internally with so called MarvinFXRules. For every assertion MarvinFX provides a special rule. You can simply write your own rules and check them with the supervisor:
-
-{{< highlight java >}}
-@Test
-public void test5() {
- TextField textField = new TextField("Hello MarvFX");
- MarvinFx.show(textField);
- TextfieldFixture textfieldFixture = new TextfieldFixture<>(textField);
- StringPropertySupervisor supervisor = textfieldFixture.createTextPropertySupervisor();
- //Custom Rule
- StringEndsWithRule rule = new StringEndsWithRule("MarvFX");
- supervisor.checkAssertion(rule);
-}
-{{< / highlight >}}
-
-Because every assertion is encapsulated in a MarvinRule you can use a underlying API and boolean logic to combine them:
-
-{{< highlight java >}}
-@Test
-public void test5() {
- TextField textField = new TextField("Hello MarvFX");
- MarvinFx.show(textField);
- TextfieldFixture textfieldFixture = new TextfieldFixture<>(textField);
- StringPropertySupervisor supervisor = textfieldFixture.createTextPropertySupervisor();
- StringEndsWithRule rule1 = new StringEndsWithRule("MarvFX");
- StringStartsWithRule rule2 = new StringStartsWithRule("Hello");
- StringStartsWithRule wrongRule1 = new StringStartsWithRule("ABC");
- supervisor.checkAssertion(rule1.and(rule2));
- supervisor.checkAssertion(rule1.or(rule2));
- supervisor.checkAssertion(wrongRule1.or(rule1));
- supervisor.checkAssertion(wrongRule1.or(rule1).and(rule2));
- supervisor.checkAssertion(rule1.and(rule2).or(wrongRule1));
- supervisor.checkAssertion(rule1.and(rule2).or(wrongRule1.or(rule2)));
-}
-{{< / highlight >}}
-
-Hope you like this ;)
+---
+outdated: true
+showInBlog: false
+title: 'Assertions and Rules in MarvinFX'
+date: "2013-03-20"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'Today I added some new features to MarvinFX. For all basic property types (String, Number, Boolean, etc...) MarvinFX will provide methods to check some common assertions for this properties. '
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Today I added some new features to [MarvinFX](/posts/2013-03-17-introducing-marvinfx). For all basic property types (String, Number, Boolean, etc...) MarvinFX will provide methods to check some common assertions for this properties. All this methods will be part of the PropertySupervisor classes. Here is a short example that tests a String property:
+
+```java@Test
+public void test5() {
+ TextField textField = new TextField("Hello MarvFX");
+ MarvinFx.show(textField);
+ TextfieldFixture textfieldFixture = new TextfieldFixture<>(textField);
+ StringPropertySupervisor supervisor = textfieldFixture.createTextPropertySupervisor();
+ supervisor.assertStringEndsWith("MarvFX");
+ supervisor.assertStringStartsWith("Hello");
+ supervisor.assertStringLenghtIsEquals(12);
+ supervisor.assertStringLenghtIsGreaterThan(11);
+ supervisor.assertStringLenghtIsLessThan(13);
+}
```
+
+All this methods work internally with so called MarvinFXRules. For every assertion MarvinFX provides a special rule. You can simply write your own rules and check them with the supervisor:
+
+```java@Test
+public void test5() {
+ TextField textField = new TextField("Hello MarvFX");
+ MarvinFx.show(textField);
+ TextfieldFixture textfieldFixture = new TextfieldFixture<>(textField);
+ StringPropertySupervisor supervisor = textfieldFixture.createTextPropertySupervisor();
+ //Custom Rule
+ StringEndsWithRule rule = new StringEndsWithRule("MarvFX");
+ supervisor.checkAssertion(rule);
+}
```
+
+Because every assertion is encapsulated in a MarvinRule you can use a underlying API and boolean logic to combine them:
+
+```java@Test
+public void test5() {
+ TextField textField = new TextField("Hello MarvFX");
+ MarvinFx.show(textField);
+ TextfieldFixture textfieldFixture = new TextfieldFixture<>(textField);
+ StringPropertySupervisor supervisor = textfieldFixture.createTextPropertySupervisor();
+ StringEndsWithRule rule1 = new StringEndsWithRule("MarvFX");
+ StringStartsWithRule rule2 = new StringStartsWithRule("Hello");
+ StringStartsWithRule wrongRule1 = new StringStartsWithRule("ABC");
+ supervisor.checkAssertion(rule1.and(rule2));
+ supervisor.checkAssertion(rule1.or(rule2));
+ supervisor.checkAssertion(wrongRule1.or(rule1));
+ supervisor.checkAssertion(wrongRule1.or(rule1).and(rule2));
+ supervisor.checkAssertion(rule1.and(rule2).or(wrongRule1));
+ supervisor.checkAssertion(rule1.and(rule2).or(wrongRule1.or(rule2)));
+}
```
+
+Hope you like this ;)
diff --git a/content/posts/2013-03-20-use-native-aqua-icons-in-javafx.md b/content/posts/2013-03-20-use-native-aqua-icons-in-javafx.md
index 7fc5d46a..9747b7f7 100644
--- a/content/posts/2013-03-20-use-native-aqua-icons-in-javafx.md
+++ b/content/posts/2013-03-20-use-native-aqua-icons-in-javafx.md
@@ -1,124 +1,120 @@
----
-outdated: true
-showInBlog: false
-title: 'Use native Aqua icons in JavaFX'
-date: "2013-03-20"
-author: hendrik
-categories: [AquaFX, JavaFX]
-excerpt: 'While planning AquaFX we found a way how to access Mac OS specific icons without using any closed APIs or Mac OS related classes.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-While planning [AquaFX]({{ site.baseurl }}{% link pages/projects/aquafx.md %}) we found a way how to access Mac OS specific icons without using any closed APIs or Mac OS related classes. We wrapped this in a simple util class. While using this on a Mac you will receive images by the underlying OS. On any other OS the function will return "null". We currently discuss if this should be part of AquaFX because this will be a part that is (under the hood) OS specific. All control skins of AquaFX are cross-platform. So you can skin your JavaFX application on Windows like a native Mac OS application (if you want :D ). Because we currently don't know if this sources will ever be part of AquaFX I simple will post them here:
-
-This enum contains all fetch able images that we found:
-
-{{< highlight java >}}
-public enum NsImageIcon {
- QUICK_LOOK_TEMPLATE("NSQuickLookTemplate"),
- BLUETOOTH_TEMPLATE("NSBluetoothTemplate"),
- I_CHAT_THEATER_TEMPLATE("NSIChatTheaterTemplate"),
- SLIDESHOW_TEMPLATE("NSSlideshowTemplate"),
- ACTION_TEMPLATE("NSActionTemplate"),
- SMART_BADGE_TEMPLATE("NSSmartBadgeTemplate"),
- PATH_TEMPLATE("NSPathTemplate"),
- INVALID_DATA_FREESTANDING_TEMPLATE("NSInvalidDataFreestandingTemplate"),
- LOCK_LOCKED_TEMPLATE("NSLockLockedTemplate"),
- LOCK_UNLOCKED_TEMPLATE("NSLockUnlockedTemplate"),
- GO_RIGHT_TEMPLATE("NSGoRightTemplate"),
- GO_LEFT_TEMPLATE("NSGoLeftTemplate"),
- RIGHT_FACING_TRIANGLE_TEMPLATE("NSRightFacingTriangleTemplate"),
- LEFT_FACING_TRIANGLE_TEMPLATE("NSLeftFacingTriangleTemplate"),
- ADD_TEMPLATE("NSAddTemplate"),
- REMOVE_TEMPLATE("NSRemoveTemplate"),
- REVEAL_FREESTANDING_TEMPLATE("NSRevealFreestandingTemplate"),
- FOLLOW_LINK_FREESTANDING_TEMPLATE("NSFollowLinkFreestandingTemplate"),
- ENTER_FULL_SCREEN_TEMPLATE("NSEnterFullScreenTemplate"),
- EXIT_FULL_SCREEN_TEMPLATE("NSExitFullScreenTemplate"),
- STOP_PROGRESS_TEMPLATE("NSStopProgressTemplate"),
- STOP_PRPGRESS_FREESTANDING_TEMPLATE("NSStopProgressFreestandingTemplate"),
- REFRESH_TEMPLATE("NSRefreshTemplate"),
- REFRESH_FREESTANDING_TEMPLATE("NSRefreshFreestandingTemplate"),
- FOLDER("NSFolder"),
- TRASH_EMPTY("NSTrashEmpty"),
- TRASH_FULL("NSTrashFull"),
- HOME_TEMPLATE("NSHomeTemplate"),
- BOOKMARKS_TEMPLATE("NSBookmarksTemplate"),
- CAUTION("NSCaution"),
- STATUS_AVAILABLE("NSStatusAvailable"),
- STATUS_PARTIALLY_AVAILABLE("NSStatusPartiallyAvailable"),
- STATUS_UNAVAILABLE("NSStatusUnavailable"),
- STATUS_NONE("NSStatusNone"),
- APPLICATION_ICON("NSApplicationIcon"),
- MENU_ON_STATE_TEMPLATE("NSMenuOnStateTemplate"),
- MENU_MIXED_STATE_TEMPLATE("NSMenuMixedStateTemplate"),
- USER_GUEST("NSUserGuest"),
- MOBILE_ME("NSMobileMe"),
- MULTIPLE_DOCUMENTS("NSMultipleDocuments"),
- USER("NSUser"),
- USER_GROUP("NSUserGroup"),
- EVERYONE("NSEveryone"),
- BONJOUR("NSBonjour"),
- DOT_MAC("NSDotMac"),
- COMPUTER("NSComputer"),
- FOLDER_BURNABLE("NSFolderBurnable"),
- FOLDER_SMART("NSFolderSmart"),
- NETWORK("NSNetwork"),
- USER_ACCOUNTS("NSUserAccounts"),
- PREFERENCES_GENERAL("NSPreferencesGeneral"),
- ADVANCED("NSAdvanced"),
- INFO("NSInfo"),
- FONT_PANEL("NSFontPanel"),
- COLOR_PANEL("NSColorPanel"),
- ICON_VIEW_TEMPLATE("NSIconViewTemplate"),
- LIST_VIEW_TEMPLATE("NSListViewTemplate"),
- COLUMN_VIEW_TEMPLATE("NSColumnViewTemplate"),
- FLOW_VIEW_TEMPLATE("NSFlowViewTemplate");
-
- private String name;
-
- private NsImageIcon(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-}
-{{< / highlight >}}
-
-And here is the loader class:
-
-{{< highlight java >}}
-import java.awt.Graphics;
-import java.awt.Toolkit;
-import java.awt.image.BufferedImage;
-
-import javafx.embed.swing.SwingFXUtils;
-import javafx.scene.image.Image;
-
-public class NsImageIconLoader {
-
- public static Image load(NsImageIcon icon) {
- System.setProperty("java.awt.headless", "false");
- java.awt.Image awtImage = Toolkit.getDefaultToolkit().getImage(
- "NSImage://" + icon.getName());
- BufferedImage bufferedImage = null;
- if (awtImage instanceof BufferedImage) {
- bufferedImage = (BufferedImage) awtImage;
- } else {
- bufferedImage = new BufferedImage(awtImage.getWidth(null),
- awtImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
- Graphics g = bufferedImage.createGraphics();
- g.drawImage(awtImage, 0, 0, null);
- g.dispose();
- }
- return SwingFXUtils.toFXImage(bufferedImage, null);
- }
-}
-{{< / highlight >}}
-
-Here is a overview of all icons that we have found:
-
-
-
-If anyone knows more icon names that can be loaded by Mac OS please let us know ;)
+---
+outdated: true
+showInBlog: false
+title: 'Use native Aqua icons in JavaFX'
+date: "2013-03-20"
+author: hendrik
+categories: [AquaFX, JavaFX]
+excerpt: 'While planning AquaFX we found a way how to access Mac OS specific icons without using any closed APIs or Mac OS related classes.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+While planning [AquaFX]({{ site.baseurl }}{% link pages/projects/aquafx.md %}) we found a way how to access Mac OS specific icons without using any closed APIs or Mac OS related classes. We wrapped this in a simple util class. While using this on a Mac you will receive images by the underlying OS. On any other OS the function will return "null". We currently discuss if this should be part of AquaFX because this will be a part that is (under the hood) OS specific. All control skins of AquaFX are cross-platform. So you can skin your JavaFX application on Windows like a native Mac OS application (if you want :D ). Because we currently don't know if this sources will ever be part of AquaFX I simple will post them here:
+
+This enum contains all fetch able images that we found:
+
+```javapublic enum NsImageIcon {
+ QUICK_LOOK_TEMPLATE("NSQuickLookTemplate"),
+ BLUETOOTH_TEMPLATE("NSBluetoothTemplate"),
+ I_CHAT_THEATER_TEMPLATE("NSIChatTheaterTemplate"),
+ SLIDESHOW_TEMPLATE("NSSlideshowTemplate"),
+ ACTION_TEMPLATE("NSActionTemplate"),
+ SMART_BADGE_TEMPLATE("NSSmartBadgeTemplate"),
+ PATH_TEMPLATE("NSPathTemplate"),
+ INVALID_DATA_FREESTANDING_TEMPLATE("NSInvalidDataFreestandingTemplate"),
+ LOCK_LOCKED_TEMPLATE("NSLockLockedTemplate"),
+ LOCK_UNLOCKED_TEMPLATE("NSLockUnlockedTemplate"),
+ GO_RIGHT_TEMPLATE("NSGoRightTemplate"),
+ GO_LEFT_TEMPLATE("NSGoLeftTemplate"),
+ RIGHT_FACING_TRIANGLE_TEMPLATE("NSRightFacingTriangleTemplate"),
+ LEFT_FACING_TRIANGLE_TEMPLATE("NSLeftFacingTriangleTemplate"),
+ ADD_TEMPLATE("NSAddTemplate"),
+ REMOVE_TEMPLATE("NSRemoveTemplate"),
+ REVEAL_FREESTANDING_TEMPLATE("NSRevealFreestandingTemplate"),
+ FOLLOW_LINK_FREESTANDING_TEMPLATE("NSFollowLinkFreestandingTemplate"),
+ ENTER_FULL_SCREEN_TEMPLATE("NSEnterFullScreenTemplate"),
+ EXIT_FULL_SCREEN_TEMPLATE("NSExitFullScreenTemplate"),
+ STOP_PROGRESS_TEMPLATE("NSStopProgressTemplate"),
+ STOP_PRPGRESS_FREESTANDING_TEMPLATE("NSStopProgressFreestandingTemplate"),
+ REFRESH_TEMPLATE("NSRefreshTemplate"),
+ REFRESH_FREESTANDING_TEMPLATE("NSRefreshFreestandingTemplate"),
+ FOLDER("NSFolder"),
+ TRASH_EMPTY("NSTrashEmpty"),
+ TRASH_FULL("NSTrashFull"),
+ HOME_TEMPLATE("NSHomeTemplate"),
+ BOOKMARKS_TEMPLATE("NSBookmarksTemplate"),
+ CAUTION("NSCaution"),
+ STATUS_AVAILABLE("NSStatusAvailable"),
+ STATUS_PARTIALLY_AVAILABLE("NSStatusPartiallyAvailable"),
+ STATUS_UNAVAILABLE("NSStatusUnavailable"),
+ STATUS_NONE("NSStatusNone"),
+ APPLICATION_ICON("NSApplicationIcon"),
+ MENU_ON_STATE_TEMPLATE("NSMenuOnStateTemplate"),
+ MENU_MIXED_STATE_TEMPLATE("NSMenuMixedStateTemplate"),
+ USER_GUEST("NSUserGuest"),
+ MOBILE_ME("NSMobileMe"),
+ MULTIPLE_DOCUMENTS("NSMultipleDocuments"),
+ USER("NSUser"),
+ USER_GROUP("NSUserGroup"),
+ EVERYONE("NSEveryone"),
+ BONJOUR("NSBonjour"),
+ DOT_MAC("NSDotMac"),
+ COMPUTER("NSComputer"),
+ FOLDER_BURNABLE("NSFolderBurnable"),
+ FOLDER_SMART("NSFolderSmart"),
+ NETWORK("NSNetwork"),
+ USER_ACCOUNTS("NSUserAccounts"),
+ PREFERENCES_GENERAL("NSPreferencesGeneral"),
+ ADVANCED("NSAdvanced"),
+ INFO("NSInfo"),
+ FONT_PANEL("NSFontPanel"),
+ COLOR_PANEL("NSColorPanel"),
+ ICON_VIEW_TEMPLATE("NSIconViewTemplate"),
+ LIST_VIEW_TEMPLATE("NSListViewTemplate"),
+ COLUMN_VIEW_TEMPLATE("NSColumnViewTemplate"),
+ FLOW_VIEW_TEMPLATE("NSFlowViewTemplate");
+
+ private String name;
+
+ private NsImageIcon(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
```
+
+And here is the loader class:
+
+```javaimport java.awt.Graphics;
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+
+import javafx.embed.swing.SwingFXUtils;
+import javafx.scene.image.Image;
+
+public class NsImageIconLoader {
+
+ public static Image load(NsImageIcon icon) {
+ System.setProperty("java.awt.headless", "false");
+ java.awt.Image awtImage = Toolkit.getDefaultToolkit().getImage(
+ "NSImage://" + icon.getName());
+ BufferedImage bufferedImage = null;
+ if (awtImage instanceof BufferedImage) {
+ bufferedImage = (BufferedImage) awtImage;
+ } else {
+ bufferedImage = new BufferedImage(awtImage.getWidth(null),
+ awtImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
+ Graphics g = bufferedImage.createGraphics();
+ g.drawImage(awtImage, 0, 0, null);
+ g.dispose();
+ }
+ return SwingFXUtils.toFXImage(bufferedImage, null);
+ }
+}
```
+
+Here is a overview of all icons that we have found:
+
+
+
+If anyone knows more icon names that can be loaded by Mac OS please let us know ;)
diff --git a/content/posts/2013-05-01-sbt-fxml-the-missing-link-between-fxml-and-your-code.md b/content/posts/2013-05-01-sbt-fxml-the-missing-link-between-fxml-and-your-code.md
index a97d0d7f..3f4f4abf 100644
--- a/content/posts/2013-05-01-sbt-fxml-the-missing-link-between-fxml-and-your-code.md
+++ b/content/posts/2013-05-01-sbt-fxml-the-missing-link-between-fxml-and-your-code.md
@@ -1,71 +1,65 @@
----
-outdated: true
-showInBlog: false
-title: 'sbt-fxml: The missing link between FXML and your code'
-date: "2013-05-01"
-author: phdoerfler
-categories: [JavaFX]
-excerpt: 'By usinf sbt-fxml FXML files suddenly type check thus allowing you to find mistakes almost instantly.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Greetings web! I was invited to write a guest post here about a little JavaFX project I started not long ago: [sbt-fxml](https://bitbucket.org/phdoerfler/sbt-fxml). It's a plugin for [SBT](http://scala-sbt.org) and it tries hard to generate boring code for you so you don't have to.
-
-It scans for [FXML](http://docs.oracle.com/javafx/2/fxml_get_started/jfxpub-fxml_get_started.htm) files - either hand written or created by [Scene Builder](http://www.oracle.com/technetwork/java/javafx/tools/index.html) - parses them and creates controller classes with a proper name, package structure, imports, declarations and types. That's right: types! So now your FXML files suddenly type check thus allowing you to find mistakes almost instantly. And because of SBT, you don't even have to manually start the build for it. It happens as soon as you save your files.
-
-
-
-## What exactly are controller classes?
-
-Controllers are simple POJOs into which the JavaFX runtime injects nodes from an FXML scenegraph. They provide the coder with a way to reference these nodes, so she doesn't have to use `node.lookup("#cssSelector")` which has [issues](http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-March/006638.html) itself. When loading an FXML, everything with an `fx:id` gets injected. To give an example, the following FXML:
-
-{{< highlight xml >}}
-
-{{< / highlight >}}
-
-could be accessed by a controller like this:
-
-{{< highlight java >}}
-public class MyController {
- @FXML
- private Button meep;
-}
-{{< / highlight >}}
-
-This is a minimalistic controller skeleton created by Scene Builder (View -> Show Sample Controller Skeleton) and it is indeed a good example of how little code is needed to use FXML files.
-
-## That's easy! Why the plugin?
-
-Even if it's only 4 lines of code it's still code I don't want to write. [DRY](http://de.wikipedia.org/wiki/Don’t_repeat_yourself), you know. It's code which was autogenerated by a tool and I don't see why it shouldn't stay that way. And although SceneBuilder can give you an example controller, the generated code is neither pretty nor is the generation automated, so you are likely to have a gap between FMXL and your codebase. Sbt-fxml does not have this limitation as it creates bindings the moment you save your FXML. Additionaly it does it's best to format the code nicely so it looks as whether it was hand written:
-
-{{< highlight java >}}
-// Auto generated by sbt-fxml, changes will be overwritten
-package com.example
-import javafx.fxml.FXML
-import javafx.scene.control.Button
-object MyController {
- @FXML
- var meep: Button = ???
-}
-{{< / highlight >}}
-
-## What's next?
-
-The plugin currently emits Scala code only. This is not by design, but felt like the natural choice for me when creating the plugin. This is likely to change in the future, though. Speaking of future, here is a list of what will be next:
-
-* Support generic nodes like `ListView>`
-* Handle many FXML files using the same controller class
-* Delete outdated controller classes
-* Implement creation of Java controller classes
-* Add more options to customize the output (indentation, etc.)
-* De-couple from SBT to allow other build tools (e.g. Maven, Gradle, Buildr, Ant, ...) to leverage sbt-fxml's functionality
-* Create a stand alone `main` so it can be used from the command line
-
-I am currently writing tests and refactor the code in order to meet those goals. At the end there will be a nice specification of what sbt-fxml can do and after the first three tasks, I will release a 1.0. You don't have to wait that long, though: There is a 1.0-SNAPSHOT, so if you're curious, feel free to try [sbt-fxml](https://bitbucket.org/phdoerfler/sbt-fxml/overview)!
-
-Thanks for reading!
-
-Phillip Dörfler [@phdoerfler](https://twitter.com/phdoerfler)
-
-This article is the first guest post at guigarage. I hope you like it :)
-In my eyes this article afford guigarage a wider range of JavaFX related stuff.
-If anyone is interested to write a guest post at guigarage please [ping me](https://twitter.com/hendrikEbbers)!
+---
+outdated: true
+showInBlog: false
+title: 'sbt-fxml: The missing link between FXML and your code'
+date: "2013-05-01"
+author: phdoerfler
+categories: [JavaFX]
+excerpt: 'By usinf sbt-fxml FXML files suddenly type check thus allowing you to find mistakes almost instantly.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Greetings web! I was invited to write a guest post here about a little JavaFX project I started not long ago: [sbt-fxml](https://bitbucket.org/phdoerfler/sbt-fxml). It's a plugin for [SBT](http://scala-sbt.org) and it tries hard to generate boring code for you so you don't have to.
+
+It scans for [FXML](http://docs.oracle.com/javafx/2/fxml_get_started/jfxpub-fxml_get_started.htm) files - either hand written or created by [Scene Builder](http://www.oracle.com/technetwork/java/javafx/tools/index.html) - parses them and creates controller classes with a proper name, package structure, imports, declarations and types. That's right: types! So now your FXML files suddenly type check thus allowing you to find mistakes almost instantly. And because of SBT, you don't even have to manually start the build for it. It happens as soon as you save your files.
+
+
+
+## What exactly are controller classes?
+
+Controllers are simple POJOs into which the JavaFX runtime injects nodes from an FXML scenegraph. They provide the coder with a way to reference these nodes, so she doesn't have to use `node.lookup("#cssSelector")` which has [issues](http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-March/006638.html) itself. When loading an FXML, everything with an `fx:id` gets injected. To give an example, the following FXML:
+
+```xml
```
+
+could be accessed by a controller like this:
+
+```javapublic class MyController {
+ @FXML
+ private Button meep;
+}
```
+
+This is a minimalistic controller skeleton created by Scene Builder (View -> Show Sample Controller Skeleton) and it is indeed a good example of how little code is needed to use FXML files.
+
+## That's easy! Why the plugin?
+
+Even if it's only 4 lines of code it's still code I don't want to write. [DRY](http://de.wikipedia.org/wiki/Don’t_repeat_yourself), you know. It's code which was autogenerated by a tool and I don't see why it shouldn't stay that way. And although SceneBuilder can give you an example controller, the generated code is neither pretty nor is the generation automated, so you are likely to have a gap between FMXL and your codebase. Sbt-fxml does not have this limitation as it creates bindings the moment you save your FXML. Additionaly it does it's best to format the code nicely so it looks as whether it was hand written:
+
+```java// Auto generated by sbt-fxml, changes will be overwritten
+package com.example
+import javafx.fxml.FXML
+import javafx.scene.control.Button
+object MyController {
+ @FXML
+ var meep: Button = ???
+}
```
+
+## What's next?
+
+The plugin currently emits Scala code only. This is not by design, but felt like the natural choice for me when creating the plugin. This is likely to change in the future, though. Speaking of future, here is a list of what will be next:
+
+* Support generic nodes like `ListView>`
+* Handle many FXML files using the same controller class
+* Delete outdated controller classes
+* Implement creation of Java controller classes
+* Add more options to customize the output (indentation, etc.)
+* De-couple from SBT to allow other build tools (e.g. Maven, Gradle, Buildr, Ant, ...) to leverage sbt-fxml's functionality
+* Create a stand alone `main` so it can be used from the command line
+
+I am currently writing tests and refactor the code in order to meet those goals. At the end there will be a nice specification of what sbt-fxml can do and after the first three tasks, I will release a 1.0. You don't have to wait that long, though: There is a 1.0-SNAPSHOT, so if you're curious, feel free to try [sbt-fxml](https://bitbucket.org/phdoerfler/sbt-fxml/overview)!
+
+Thanks for reading!
+
+Phillip Dörfler [@phdoerfler](https://twitter.com/phdoerfler)
+
+This article is the first guest post at guigarage. I hope you like it :)
+In my eyes this article afford guigarage a wider range of JavaFX related stuff.
+If anyone is interested to write a guest post at guigarage please [ping me](https://twitter.com/hendrikEbbers)!
diff --git a/content/posts/2013-05-09-aquatecture.md b/content/posts/2013-05-09-aquatecture.md
index ba1f5c76..79f1648b 100644
--- a/content/posts/2013-05-09-aquatecture.md
+++ b/content/posts/2013-05-09-aquatecture.md
@@ -1,63 +1,53 @@
----
-outdated: true
-showInBlog: false
-title: 'Aquatecture'
-date: "2013-05-09"
-author: hendrik
-categories: [AquaFX, General, JavaFX]
-excerpt: 'In this post I will show you some of the internal API stuff of AquaFX'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-While Claudine is working on all the needed Skins for AquaFX I will use the time to show you some of the internal API stuff of [AquaFX]({{ site.baseurl }}{% link pages/projects/aquafx.md %}) that Claudine has developed. Once the project is released you can easily style your complete application by just calling
-
-{{< highlight java >}}
-AquaFx.style();
-{{< / highlight >}}
-
-This will set the CSS Styles for all controls that are supported by AquaFX for you. Once this is done your application should look like a native one.
-
-While working a lot with Aqua and reading all the Apple style guides, etc. we noticed that simply setting one style for every control type is not enough to provide a great Aqua Look and Feel for JavaFX. Many native applications use the default controls like Buttons in different variations. For example you can have smaller controls or buttons with a more rounded border than the default one. Here is good overview about the different size variations of components:
-
-
-
-This Image is taken from the [Apple documentation of the native Swing Look&Feel for Mac OS](https://developer.apple.com/library/mac/#technotes/tn2007/tn2196.html).
-
-When using the Aqua L&F in Swing you can change the behavior of a component by adding a String as a clientProperty to the component:
-
-{{< highlight java >}}
-component.putClientProperty("JComponent.sizeVariant", "mini");
-{{< / highlight >}}
-
-I think with AquaFX Claudine found a better way to provide this different styles by simply providing Enums for all different designs. So you can change the size of the component by simply using this enum:
-
-{{< highlight java >}}
-public enum ControlSizeVariant implements StyleDefinition {
-REGULAR,
-SMALL,
-MINI;
-@Override public String getStyleName() {
-...
-}
-...
-}
-{{< / highlight >}}
-
-Now you can skin a button as a small control with just a method-call:
-
-{{< highlight java >}}
-AquaFx.resizeControl(myButton, ControlSizeVariant.SMALL);
-{{< / highlight >}}
-
-For doing so you only need the AquaFX class that is a static [facade](http://en.wikipedia.org/wiki/Facade_pattern) for all features AquaFX will provide. So a normal developer will only need to now this class and its' internal methods to skin and configure an application with AquaFX.
-
-But the rezise as shown above is not the only skin variation you can define. With AquaFX you can easily mix different variations, too. The Facade offers a method for that:
-
-{{< highlight java >}}
-AquaFx.skin(myButton, ButtonType.ROUND_RECT, ControlSizeVariant.SMALL);
-{{< / highlight >}}
-
-Cause all Enums implement the StyleDefinition interface you can commit as many as you want for a control. AquaFX will try to create the best look for you. Here is a example of some controls with a custom styling:
-
-
-
-At the moment some combinations of StyleDefinition don't make sense and I gave Claudine the hint to think about a [fluent approach](http://en.wikipedia.org/wiki/Facade_pattern) for skinning this variations. So maybe this is not the final API. But I think it's at a good point to share this ideas and features with you. Hope you like it.
+---
+outdated: true
+showInBlog: false
+title: 'Aquatecture'
+date: "2013-05-09"
+author: hendrik
+categories: [AquaFX, General, JavaFX]
+excerpt: 'In this post I will show you some of the internal API stuff of AquaFX'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+While Claudine is working on all the needed Skins for AquaFX I will use the time to show you some of the internal API stuff of [AquaFX]({{ site.baseurl }}{% link pages/projects/aquafx.md %}) that Claudine has developed. Once the project is released you can easily style your complete application by just calling
+
+```javaAquaFx.style();
```
+
+This will set the CSS Styles for all controls that are supported by AquaFX for you. Once this is done your application should look like a native one.
+
+While working a lot with Aqua and reading all the Apple style guides, etc. we noticed that simply setting one style for every control type is not enough to provide a great Aqua Look and Feel for JavaFX. Many native applications use the default controls like Buttons in different variations. For example you can have smaller controls or buttons with a more rounded border than the default one. Here is good overview about the different size variations of components:
+
+
+
+This Image is taken from the [Apple documentation of the native Swing Look&Feel for Mac OS](https://developer.apple.com/library/mac/#technotes/tn2007/tn2196.html).
+
+When using the Aqua L&F in Swing you can change the behavior of a component by adding a String as a clientProperty to the component:
+
+```javacomponent.putClientProperty("JComponent.sizeVariant", "mini");
```
+
+I think with AquaFX Claudine found a better way to provide this different styles by simply providing Enums for all different designs. So you can change the size of the component by simply using this enum:
+
+```javapublic enum ControlSizeVariant implements StyleDefinition {
+REGULAR,
+SMALL,
+MINI;
+@Override public String getStyleName() {
+...
+}
+...
+}
```
+
+Now you can skin a button as a small control with just a method-call:
+
+```javaAquaFx.resizeControl(myButton, ControlSizeVariant.SMALL);
```
+
+For doing so you only need the AquaFX class that is a static [facade](http://en.wikipedia.org/wiki/Facade_pattern) for all features AquaFX will provide. So a normal developer will only need to now this class and its' internal methods to skin and configure an application with AquaFX.
+
+But the rezise as shown above is not the only skin variation you can define. With AquaFX you can easily mix different variations, too. The Facade offers a method for that:
+
+```javaAquaFx.skin(myButton, ButtonType.ROUND_RECT, ControlSizeVariant.SMALL);
```
+
+Cause all Enums implement the StyleDefinition interface you can commit as many as you want for a control. AquaFX will try to create the best look for you. Here is a example of some controls with a custom styling:
+
+
+
+At the moment some combinations of StyleDefinition don't make sense and I gave Claudine the hint to think about a [fluent approach](http://en.wikipedia.org/wiki/Facade_pattern) for skinning this variations. So maybe this is not the final API. But I think it's at a good point to share this ideas and features with you. Hope you like it.
diff --git a/content/posts/2013-05-19-designing-javafx-business-applications-part-2.md b/content/posts/2013-05-19-designing-javafx-business-applications-part-2.md
index 6e05af08..61da6aa8 100644
--- a/content/posts/2013-05-19-designing-javafx-business-applications-part-2.md
+++ b/content/posts/2013-05-19-designing-javafx-business-applications-part-2.md
@@ -1,152 +1,138 @@
----
-outdated: true
-showInBlog: false
-title: 'Designing JavaFX Business Applications (Part 2)'
-date: "2013-05-19"
-author: hendrik
-categories: [General, JavaFX]
-excerpt: 'This is the second part of my series about JavaFX architecture and best practice for (business) application.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-This is the second part of my series about JavaFX architecture and best practice for (business) application. You can find the first part about middleware [here]({{< ref "/posts/2013-05-11-designing-javafx-business-applications-part-1" >}}).
-
-In this post I will show you a simply and modern way to bind your data model to your view by using [Context Dependency Injection (CDI)](http://en.wikipedia.org/wiki/Dependency_injection).
-
-## CDI?? What the hell??
-
-CDI is a modern design pattern that is for example part of JEE. By using dependency injection you can remove hard coded dependencies in your code. Here is a short example:
-
-{{< highlight java >}}
-public class Controller {
- @Inject
- Model model;
- public void action() {...}
-}
-{{< / highlight >}}
-
-If the Controller will be created by a CDI-Container the model field will be injected. This means that the CDI-Container will fill the field with a suitable instance of Model. How this model is created is not part of the Controller class. The controller only knows that he will get a injected instance of Model and can work with it.
-
-This is only a very short introduction to CDI. If you want to use it please read a [better documentation](http://docs.oracle.com/javaee/6/tutorial/doc/giwhl.html) :)
-
-## How a JavaFX application is mostly designed until now
-
-In a normal business application you will have views and workflows. For example you will have a overview of some important business values and a form dialog with [CRUD](http://en.wikipedia.org/wiki/Create,_read,_update_and_delete) functions.
-
-Normally you will define your views by code or with the [Scene Builder](http://docs.oracle.com/javafx/scenebuilder/1/get_started/jsbpub-get_started.htm). If you use the Scene Builder you can transfer all your UI code into the [fxml](http://docs.oracle.com/javafx/2/fxml_get_started/jfxpub-fxml_get_started.htm) file and handle the logic inside a controller class. The controller can now access the business data by calling data stores or any other of your classes.
-
-
-
-This pattern is good and is working much better that your old Swing code. You have a clean separation between the view and the business logic. But there are still some problems here:
-
-* The controller has hard dependencies to you business data classes.
-* The controller class is defined inside the fxml file.
-* Providing special business object instances only for one view workflow isn't easy.
-
-I will try to solve this problems with a new approach of JavaFX client development.
-
-## Let's pimp my JavaFX application
-
-To create a real modern and modular version of this we will do some inversion of control. First of all I don't like that the controller class for a fxml-view is defined inside the fxml. This is a refactoring killer. Cause if you rename the class or move it to another package this binding is broken. In addition I like it more to define the used view in the controller. Maybe this is not 100% compatible with the MVC pattern where different views can easily share one controller but we can define all dependencies in java code. To inverse this dependency I created a FXMLController annotation:
-
-{{< highlight java >}}
-@FXMLController("/com/guigarage/application/views/MyView.fxml")
-public class MyController {
-...
-}
-{{< / highlight >}}
-
-The internal path to the fxml file is defined by the annotation. By doing so I can simply create a view:
-
-{{< highlight java >}}
-Node myView FXMLHelper.create(MyController.class);
-{{< / highlight >}}
-
-FXMLHelper.create(..) is a Method that I created to do some magic (Don't be afraid, I will release a code for this design pattern later). The method creates the controller instance and the view and bind them.
-
-We can now easily add the node to our scene graph.
-
-
-
-But wait! Where is the controller instance? We don't have access to this object...
-
-Right, cause we don't need it :) Cause now comes the CDI magic.
-
-## Using the CDI pattern in JavaFX
-
-A first project that shows the use of CDI in JavaFX is [afterburner.fx](http://afterburner.adam-bien.com) by [Adam Bien](http://about.adam-bien.com). With this framework you can easily inject objects in your JavaFX controller. But this framework is very lightweight and don't support all default CDI features. There are no [producers](http://docs.oracle.com/javaee/6/tutorial/doc/gkgkv.html#gmgjt), [scopes](http://docs.oracle.com/javaee/6/tutorial/doc/gjbbk.html), etc.
-
-I created a new API that is currently based on [Weld](http://seamframework.org/Weld) (the JEE default implementation for CDI) and provides all the default CDI features. By using it you can use the @Inject annotation in you view controllers:
-
-{{< highlight java >}}
-public class MyController {
- @Inject
- Model myModel;
-}
-{{< / highlight >}}
-
-The model will be injected to your controller as mentioned above. Other CDI Annotations will work, too. Here is an example of a more complex version of a controller:
-
-{{< highlight java >}}
-public class MyController {
- @Inject
- @ModelQualifier
- Model myModel;
- @PostConstruct
- public void init() {....}
-}
-public class ModelFactory {
- @Produces
- @ModelQualifier
- public Model getModel() {
- ....
- }
-}
-{{< / highlight >}}
-
-In this example the model has a custom [Qualifier](https://blogs.oracle.com/arungupta/entry/totd_161_java_ee_6) annotation (@ModelQualifier). This will define a special Model type. This type is created by the ModelFactory. The getModel() method has a @Producer annotation that defines this method as a producer for the model class. Additionally the init() method of the controller has a [PostConstruct](http://docs.oracle.com/javaee/6/tutorial/doc/gmgkd.html) annotation. This method will automatically called once a controller is created.
-
-## Putting it all together
-
-After I added the @FXMLController annotation and CDI to my basic application it is really easy to create new views. The UI can be easily created by using the [Scene Builder](http://docs.oracle.com/javafx/scenebuilder/1/get_started/jsbpub-get_started.htm). Once this is done you can create the controller class and use CDI inside it. Cause you can inject everything that is needed it will be very easy to capsulate a view-controller-union as a single module. To create this I only need a line of code (as mentioned above):
-
-{{< highlight java >}}
-Node myView FXMLCDI.create(MyController.class);
-{{< / highlight >}}
-
-The FXMLCDI util class (my custom one) handles all the FXML and CDI stuff.
-
-
-
-## Thinking about Scopes
-
-Cause CDI is mostly used in JEE context at the moment most of the [Scopes](http://docs.oracle.com/javaee/6/tutorial/doc/gjbbk.html) don't fit to a JFX application. But we will need Scopes here, too.
-
-In the default CDI Scope a new instance of a class is created for every injection. Secondly you can use a singleton scope. By doing so only one instance of the class will be used in your application. All other default scopes are related to web applications (RequestScope, SessionScope, ...) and won't fit in a JavaFX application. While looking at other frameworks I found some interesting scopes that are part of [ADF](http://www.oracle.com/technetwork/developer-tools/adf/overview/index.html). Here you can use a ViewScope and a ViewFlowScope. I think this scopes are very useful for client applications and one of my next steps is the integration of this scopes in my FXML/CDI Framework.
-
-## A simple example
-
-Let's think about a dialog with some very important business values. This values should only be accessed by this dialog. But your application offers a twitter integration to post some stuff. The Twitter configuration is defined globally for the whole application. If you want to add a function to twitter the business values by just clicking a button in your dialog the controller could look like this:
-
-{{< highlight java >}}
-@FXMLController("/com/guigarage/application/views/ImportantDialog.fxml")
-public class ImportantDialogController {
- @Inject
- @DialogScope
- Model importantModel;
- @Inject
- @ApplicationScope
- Twitter twitter;
- @PostConstruct
- public void init() {
- importantModel.loadAllImportantValues();
- }
- @FXML
- public void twitter() {
- twitter.post(importantModel.getImportantBusinessValues());
- }
-}
-{{< / highlight >}}
-
-## And how can I use this stuff?
-
-At the moment my complete code is experimental but I plan to release it once it is more clean. Maybe you have some cool additional ideas for this pattern of JavaFX application development that I can add to the framework before it will be released ;)
+---
+outdated: true
+showInBlog: false
+title: 'Designing JavaFX Business Applications (Part 2)'
+date: "2013-05-19"
+author: hendrik
+categories: [General, JavaFX]
+excerpt: 'This is the second part of my series about JavaFX architecture and best practice for (business) application.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+This is the second part of my series about JavaFX architecture and best practice for (business) application. You can find the first part about middleware [here](/posts/2013-05-11-designing-javafx-business-applications-part-1).
+
+In this post I will show you a simply and modern way to bind your data model to your view by using [Context Dependency Injection (CDI)](http://en.wikipedia.org/wiki/Dependency_injection).
+
+## CDI?? What the hell??
+
+CDI is a modern design pattern that is for example part of JEE. By using dependency injection you can remove hard coded dependencies in your code. Here is a short example:
+
+```javapublic class Controller {
+ @Inject
+ Model model;
+ public void action() {...}
+}
```
+
+If the Controller will be created by a CDI-Container the model field will be injected. This means that the CDI-Container will fill the field with a suitable instance of Model. How this model is created is not part of the Controller class. The controller only knows that he will get a injected instance of Model and can work with it.
+
+This is only a very short introduction to CDI. If you want to use it please read a [better documentation](http://docs.oracle.com/javaee/6/tutorial/doc/giwhl.html) :)
+
+## How a JavaFX application is mostly designed until now
+
+In a normal business application you will have views and workflows. For example you will have a overview of some important business values and a form dialog with [CRUD](http://en.wikipedia.org/wiki/Create,_read,_update_and_delete) functions.
+
+Normally you will define your views by code or with the [Scene Builder](http://docs.oracle.com/javafx/scenebuilder/1/get_started/jsbpub-get_started.htm). If you use the Scene Builder you can transfer all your UI code into the [fxml](http://docs.oracle.com/javafx/2/fxml_get_started/jfxpub-fxml_get_started.htm) file and handle the logic inside a controller class. The controller can now access the business data by calling data stores or any other of your classes.
+
+
+
+This pattern is good and is working much better that your old Swing code. You have a clean separation between the view and the business logic. But there are still some problems here:
+
+* The controller has hard dependencies to you business data classes.
+* The controller class is defined inside the fxml file.
+* Providing special business object instances only for one view workflow isn't easy.
+
+I will try to solve this problems with a new approach of JavaFX client development.
+
+## Let's pimp my JavaFX application
+
+To create a real modern and modular version of this we will do some inversion of control. First of all I don't like that the controller class for a fxml-view is defined inside the fxml. This is a refactoring killer. Cause if you rename the class or move it to another package this binding is broken. In addition I like it more to define the used view in the controller. Maybe this is not 100% compatible with the MVC pattern where different views can easily share one controller but we can define all dependencies in java code. To inverse this dependency I created a FXMLController annotation:
+
+```java@FXMLController("/com/guigarage/application/views/MyView.fxml")
+public class MyController {
+...
+}
```
+
+The internal path to the fxml file is defined by the annotation. By doing so I can simply create a view:
+
+```javaNode myView FXMLHelper.create(MyController.class);
```
+
+FXMLHelper.create(..) is a Method that I created to do some magic (Don't be afraid, I will release a code for this design pattern later). The method creates the controller instance and the view and bind them.
+
+We can now easily add the node to our scene graph.
+
+
+
+But wait! Where is the controller instance? We don't have access to this object...
+
+Right, cause we don't need it :) Cause now comes the CDI magic.
+
+## Using the CDI pattern in JavaFX
+
+A first project that shows the use of CDI in JavaFX is [afterburner.fx](http://afterburner.adam-bien.com) by [Adam Bien](http://about.adam-bien.com). With this framework you can easily inject objects in your JavaFX controller. But this framework is very lightweight and don't support all default CDI features. There are no [producers](http://docs.oracle.com/javaee/6/tutorial/doc/gkgkv.html#gmgjt), [scopes](http://docs.oracle.com/javaee/6/tutorial/doc/gjbbk.html), etc.
+
+I created a new API that is currently based on [Weld](http://seamframework.org/Weld) (the JEE default implementation for CDI) and provides all the default CDI features. By using it you can use the @Inject annotation in you view controllers:
+
+```javapublic class MyController {
+ @Inject
+ Model myModel;
+}
```
+
+The model will be injected to your controller as mentioned above. Other CDI Annotations will work, too. Here is an example of a more complex version of a controller:
+
+```javapublic class MyController {
+ @Inject
+ @ModelQualifier
+ Model myModel;
+ @PostConstruct
+ public void init() {....}
+}
+public class ModelFactory {
+ @Produces
+ @ModelQualifier
+ public Model getModel() {
+ ....
+ }
+}
```
+
+In this example the model has a custom [Qualifier](https://blogs.oracle.com/arungupta/entry/totd_161_java_ee_6) annotation (@ModelQualifier). This will define a special Model type. This type is created by the ModelFactory. The getModel() method has a @Producer annotation that defines this method as a producer for the model class. Additionally the init() method of the controller has a [PostConstruct](http://docs.oracle.com/javaee/6/tutorial/doc/gmgkd.html) annotation. This method will automatically called once a controller is created.
+
+## Putting it all together
+
+After I added the @FXMLController annotation and CDI to my basic application it is really easy to create new views. The UI can be easily created by using the [Scene Builder](http://docs.oracle.com/javafx/scenebuilder/1/get_started/jsbpub-get_started.htm). Once this is done you can create the controller class and use CDI inside it. Cause you can inject everything that is needed it will be very easy to capsulate a view-controller-union as a single module. To create this I only need a line of code (as mentioned above):
+
+```javaNode myView FXMLCDI.create(MyController.class);
```
+
+The FXMLCDI util class (my custom one) handles all the FXML and CDI stuff.
+
+
+
+## Thinking about Scopes
+
+Cause CDI is mostly used in JEE context at the moment most of the [Scopes](http://docs.oracle.com/javaee/6/tutorial/doc/gjbbk.html) don't fit to a JFX application. But we will need Scopes here, too.
+
+In the default CDI Scope a new instance of a class is created for every injection. Secondly you can use a singleton scope. By doing so only one instance of the class will be used in your application. All other default scopes are related to web applications (RequestScope, SessionScope, ...) and won't fit in a JavaFX application. While looking at other frameworks I found some interesting scopes that are part of [ADF](http://www.oracle.com/technetwork/developer-tools/adf/overview/index.html). Here you can use a ViewScope and a ViewFlowScope. I think this scopes are very useful for client applications and one of my next steps is the integration of this scopes in my FXML/CDI Framework.
+
+## A simple example
+
+Let's think about a dialog with some very important business values. This values should only be accessed by this dialog. But your application offers a twitter integration to post some stuff. The Twitter configuration is defined globally for the whole application. If you want to add a function to twitter the business values by just clicking a button in your dialog the controller could look like this:
+
+```java@FXMLController("/com/guigarage/application/views/ImportantDialog.fxml")
+public class ImportantDialogController {
+ @Inject
+ @DialogScope
+ Model importantModel;
+ @Inject
+ @ApplicationScope
+ Twitter twitter;
+ @PostConstruct
+ public void init() {
+ importantModel.loadAllImportantValues();
+ }
+ @FXML
+ public void twitter() {
+ twitter.post(importantModel.getImportantBusinessValues());
+ }
+}
```
+
+## And how can I use this stuff?
+
+At the moment my complete code is experimental but I plan to release it once it is more clean. Maybe you have some cool additional ideas for this pattern of JavaFX application development that I can add to the framework before it will be released ;)
diff --git a/content/posts/2013-05-26-aquafx-lessons-learned-part-i.md b/content/posts/2013-05-26-aquafx-lessons-learned-part-i.md
index b80adf8b..12b37124 100644
--- a/content/posts/2013-05-26-aquafx-lessons-learned-part-i.md
+++ b/content/posts/2013-05-26-aquafx-lessons-learned-part-i.md
@@ -1,120 +1,112 @@
----
-outdated: true
-showInBlog: false
-title: 'AquaFX: lessons learned (Part I)'
-date: "2013-05-26"
-author: claudine
-categories: [AquaFX, JavaFX]
-excerpt: 'During the work on AquaFX there were some obstacles that needed to be overcome. In this article I want to summarize information, so that they might help people who just face the same questions, as I had.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-During the work on AquaFX there were some obstacles that needed to be overcome. With some research, the [CSS Reference Guide](http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html) and the help of google, most answers definitely can be found, so please don't be angry with me when those tips might be obvious for you. In this article I want to summarize information, so that they might help people who just face the same questions, as I had. And don't hesitate to contact me/ comment when you know a better way for some things or think they might be wrong :-)
-
-So, let's get started:
-
-## class selection & CSS
-
-Using CSS is pretty familiar to most developers. For me, it is a long time ago, that I styled HTML pages with CSS, so I had to learn some things over. Fortunately, JavaFX uses CSS in a simple yet powerful way.
-
-### class selection
-
-If you style controls, you have to explicitly select a desired section, to achieve your goal. This is the case, e.g. when you style a ComboBox or a CheckBox. The mark of a CheckBox can be selected by using `.check-box > .box > .mark { ... }`
-
-which navigates the selection through the substructure of this control to the class .mark. The concrete structures can be seen in [CSS Reference Guide](http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html) and by using [ScenicView](http://fxexperience.com/scenic-view/).
-
-#### So what does the ">" mean?
-
-It means, the class named after it, is a direct child of the class before. If there is a class .xy in the structure between those classes, the style won't be applied. Siblings do not affect this definition.
-
-In contrast, a definition like `.classA .subclassB { ... }` can be used. The difference is, that it does not matter how many classes are between those two. This causes JavaFX to invest more computing time for parsing the scenegraph, because the whole tree has to be checked for this possible constellation.
-
-Though I use this in my AquaToolBar e.g.
-
-This gives me the possibility to explicitly style Buttons in ToolBar in a different style than usual, although maybe wrapped in 1..n Panes, like HBoxes/ VBoxes.
-
-Another selector is `.classX.classY` which means nothing else, than they apply to the same thing. Since it is possible to add multiple style classes to a component, you can use this selection, to find a specific class in combination with another class. This allows you to set a differentiated styling of e.g. .button.alert and .text-field.alert.
-
-## adding style classes to controls
-
-So, how to add a class to control? The simplest way is `controlInstance.getStyleClass().add("my-style-class");` and for this control, styles defined in `.control-class.my-style-class { ... }` will be applied.
-
-## the difference between :armed and :pressed
-
-Another (maybe obvious) information is the difference between the pseudo-class `:armed` and `:pressed`.
-
-`:pressed` applies, when you press the mouse button on the control and stays applied, as long as the mouse remains being pressed, no matter whether you stay in the component with your cursor.
-
-`:armed` does the same, but is not applied any more when the cursor leaves the component. If mouse is still pressed and you enter component, it is applied again.
-
-## using relative units for dynamic sizing
-
-When using Mac OS X, you will find dialogs, where controls have a smaller size than usual. This is a point, which is adopted to AquaFX. With relative units, it is pretty easy to style size-independend.
-
-AquaFX uses a font size of 13px. The two size variants use 11px and 9px. All style definitions, which have to be dynamic, are defined in `em`. In my case especially `-fx-padding`.
-
-This makes my controls to shrink/grow, when the font size changes:
-
-
-
-## NEVER EVER DO THIS
-
-AquaFX is based on Caspian.css, which means I took the CSS and reworked it completely. This assures, that no component state is overseen. When working on so much components and details, the moment comes, when you loose attention for a moment and assign wrong values to properties.
-
-So, in my code there showed up the following line without being recognized:
-
-{{< highlight css >}}
--fx-text-fill : -fx-text-fill;
-{{< / highlight >}}
-
-As soon as the component, it belonged to, was used in a dialog my VM crashed and a nice greeting from Mac OS X welcomed me:
-
-
-
-Never, ever do this bad assignment... So, if something like this happens, CHECK YOUR CSS! ;-)
-
-## SVGs and icons
-
-I prefered using SVG paths for all tiny icons and symbols, so I'd love to share my way of working on those things. Like everything written here, this is no rule, just a description to show how some details are realized.
-
-### create SVG-paths
-
-To create and edit the SVG paths, I am using the open source SVG graphics editor [Inkscape](http://inkscape.org/download/?lang=de). Graphics can be created and the path can then be copied by selecting the graphic and choosing edit > XML-Editor:
-
-
-
-In this pop up the path for CSS is shown and can be copied:
-
-
-
-ready to use in CSS by setting `-fx-shape: ;`
-
-### the indeterminate ProgressIndicator
-
-One control, which require SVG paths is the indeterminate ProgressIndicator.
-
-
-
-Caspian has a different number of 'rotating' graphics. But, no problem for JavaFX!
-
-{{< highlight css >}}
--fx-indeterminate-segment-count: 12.0;
-{{< / highlight >}}
-
-This solves the problem.. What you have to do then, is defining every single path with:
-
-{{< highlight css >}}
-.progress-indicator:indeterminate .segment0 { -fx-shape:"...";}
-.progress-indicator:indeterminate .segment1 { -fx-shape:"...";}
-...
-.progress-indicator:indeterminate .segment11 { -fx-shape:"...";}
-{{< / highlight >}}
-
-and a little color
-
-{{< highlight css >}}
-.progress-indicator:indeterminate .segment { -fx-background-color: ...;}
-{{< / highlight >}}
-
-and you are done.
-
-In the next part I write more about some specific controls, like Buttons/ PillButtons, Lists vs. Tables, ToolBars, etc. So visit us again :-)
+---
+outdated: true
+showInBlog: false
+title: 'AquaFX: lessons learned (Part I)'
+date: "2013-05-26"
+author: claudine
+categories: [AquaFX, JavaFX]
+excerpt: 'During the work on AquaFX there were some obstacles that needed to be overcome. In this article I want to summarize information, so that they might help people who just face the same questions, as I had.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+During the work on AquaFX there were some obstacles that needed to be overcome. With some research, the [CSS Reference Guide](http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html) and the help of google, most answers definitely can be found, so please don't be angry with me when those tips might be obvious for you. In this article I want to summarize information, so that they might help people who just face the same questions, as I had. And don't hesitate to contact me/ comment when you know a better way for some things or think they might be wrong :-)
+
+So, let's get started:
+
+## class selection & CSS
+
+Using CSS is pretty familiar to most developers. For me, it is a long time ago, that I styled HTML pages with CSS, so I had to learn some things over. Fortunately, JavaFX uses CSS in a simple yet powerful way.
+
+### class selection
+
+If you style controls, you have to explicitly select a desired section, to achieve your goal. This is the case, e.g. when you style a ComboBox or a CheckBox. The mark of a CheckBox can be selected by using `.check-box > .box > .mark { ... }`
+
+which navigates the selection through the substructure of this control to the class .mark. The concrete structures can be seen in [CSS Reference Guide](http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html) and by using [ScenicView](http://fxexperience.com/scenic-view/).
+
+#### So what does the ">" mean?
+
+It means, the class named after it, is a direct child of the class before. If there is a class .xy in the structure between those classes, the style won't be applied. Siblings do not affect this definition.
+
+In contrast, a definition like `.classA .subclassB { ... }` can be used. The difference is, that it does not matter how many classes are between those two. This causes JavaFX to invest more computing time for parsing the scenegraph, because the whole tree has to be checked for this possible constellation.
+
+Though I use this in my AquaToolBar e.g.
+
+This gives me the possibility to explicitly style Buttons in ToolBar in a different style than usual, although maybe wrapped in 1..n Panes, like HBoxes/ VBoxes.
+
+Another selector is `.classX.classY` which means nothing else, than they apply to the same thing. Since it is possible to add multiple style classes to a component, you can use this selection, to find a specific class in combination with another class. This allows you to set a differentiated styling of e.g. .button.alert and .text-field.alert.
+
+## adding style classes to controls
+
+So, how to add a class to control? The simplest way is `controlInstance.getStyleClass().add("my-style-class");` and for this control, styles defined in `.control-class.my-style-class { ... }` will be applied.
+
+## the difference between :armed and :pressed
+
+Another (maybe obvious) information is the difference between the pseudo-class `:armed` and `:pressed`.
+
+`:pressed` applies, when you press the mouse button on the control and stays applied, as long as the mouse remains being pressed, no matter whether you stay in the component with your cursor.
+
+`:armed` does the same, but is not applied any more when the cursor leaves the component. If mouse is still pressed and you enter component, it is applied again.
+
+## using relative units for dynamic sizing
+
+When using Mac OS X, you will find dialogs, where controls have a smaller size than usual. This is a point, which is adopted to AquaFX. With relative units, it is pretty easy to style size-independend.
+
+AquaFX uses a font size of 13px. The two size variants use 11px and 9px. All style definitions, which have to be dynamic, are defined in `em`. In my case especially `-fx-padding`.
+
+This makes my controls to shrink/grow, when the font size changes:
+
+
+
+## NEVER EVER DO THIS
+
+AquaFX is based on Caspian.css, which means I took the CSS and reworked it completely. This assures, that no component state is overseen. When working on so much components and details, the moment comes, when you loose attention for a moment and assign wrong values to properties.
+
+So, in my code there showed up the following line without being recognized:
+
+```css-fx-text-fill : -fx-text-fill;
```
+
+As soon as the component, it belonged to, was used in a dialog my VM crashed and a nice greeting from Mac OS X welcomed me:
+
+
+
+Never, ever do this bad assignment... So, if something like this happens, CHECK YOUR CSS! ;-)
+
+## SVGs and icons
+
+I prefered using SVG paths for all tiny icons and symbols, so I'd love to share my way of working on those things. Like everything written here, this is no rule, just a description to show how some details are realized.
+
+### create SVG-paths
+
+To create and edit the SVG paths, I am using the open source SVG graphics editor [Inkscape](http://inkscape.org/download/?lang=de). Graphics can be created and the path can then be copied by selecting the graphic and choosing edit > XML-Editor:
+
+
+
+In this pop up the path for CSS is shown and can be copied:
+
+
+
+ready to use in CSS by setting `-fx-shape: ;`
+
+### the indeterminate ProgressIndicator
+
+One control, which require SVG paths is the indeterminate ProgressIndicator.
+
+
+
+Caspian has a different number of 'rotating' graphics. But, no problem for JavaFX!
+
+```css-fx-indeterminate-segment-count: 12.0;
```
+
+This solves the problem.. What you have to do then, is defining every single path with:
+
+```css.progress-indicator:indeterminate .segment0 { -fx-shape:"...";}
+.progress-indicator:indeterminate .segment1 { -fx-shape:"...";}
+...
+.progress-indicator:indeterminate .segment11 { -fx-shape:"...";}
```
+
+and a little color
+
+```css.progress-indicator:indeterminate .segment { -fx-background-color: ...;}
```
+
+and you are done.
+
+In the next part I write more about some specific controls, like Buttons/ PillButtons, Lists vs. Tables, ToolBars, etc. So visit us again :-)
diff --git a/content/posts/2013-08-29-boxfx-javaone-preview-1.md b/content/posts/2013-08-29-boxfx-javaone-preview-1.md
index 8d5edfbe..bf97a57b 100644
--- a/content/posts/2013-08-29-boxfx-javaone-preview-1.md
+++ b/content/posts/2013-08-29-boxfx-javaone-preview-1.md
@@ -30,5 +30,5 @@ You can control BoxFX with a remote. BoxFX will provide a open API for remotes s
I created a short movie about BoxFX. Hope you like it:
-{{< youtube w3r3hzJs2W0 >}}
+
diff --git a/content/posts/2013-08-30-pimp-your-app-by-using-the-blurpane.md b/content/posts/2013-08-30-pimp-your-app-by-using-the-blurpane.md
index 75be344b..a71a48c6 100644
--- a/content/posts/2013-08-30-pimp-your-app-by-using-the-blurpane.md
+++ b/content/posts/2013-08-30-pimp-your-app-by-using-the-blurpane.md
@@ -1,65 +1,63 @@
----
-outdated: true
-showInBlog: false
-title: 'Pimp your App by using the BlurPane'
-date: "2013-08-30"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'For a skin we needed a special blur effect. Our goal was to blur the complete application once a message is shown on the screen. By doing so the user is targeted only to the displayed message because the rest of the application is blured.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-For a skin we needed a special blur effect. Our goal was to blur the complete application once a message is shown on the screen. By doing so the user is targeted only to the displayed message because the rest of the application is blured. Here is a short example:
-
-
-
-Whenever a message will be shown the complete applications will become blurred:
-
-
-
-We have choosen a similar approach as it is done in the JXLayer in Swing. A invisible StackPane is placed on top of the application as an overlay. When a message appears the StackPane will become visible. The StackPane contains a ImageView that shows a blurred snapshot of the complete area under the Pane. By doing so the applications seams to be blurred. The BlurPane will be part in one of our next open source libs. But because this class has only dependencies to the JDK we want to share it here with you:
-
-{{< highlight java >}}
-import javafx.geometry.Point2D;
-import javafx.geometry.Rectangle2D;
-import javafx.scene.SnapshotParameters;
-import javafx.scene.effect.BoxBlur;
-import javafx.scene.image.ImageView;
-import javafx.scene.image.WritableImage;
-import javafx.scene.layout.StackPane;
-import javafx.scene.shape.Rectangle;
-
-public class BlurPane extends StackPane {
-
- private ImageView imageView;
-
- public BlurPane() {
- imageView = new ImageView();
- imageView.setFocusTraversable(false);
- BoxBlur bb = new BoxBlur();
- bb.setWidth(8);
- bb.setHeight(8);
- bb.setIterations(3);
- imageView.setEffect(bb);
- }
-
- @Override
- protected void layoutChildren() {
- super.layoutChildren();
- if (getParent() != null && isVisible()) {
- setVisible(false);
- getChildren().remove(imageView);
- SnapshotParameters parameters = new SnapshotParameters();
- Point2D startPointInScene = this.localToScene(0, 0);
- Rectangle2D toPaint = new Rectangle2D(startPointInScene.getX(), startPointInScene.getY(), getLayoutBounds().getWidth(), getLayoutBounds().getHeight());
- parameters.setViewport(toPaint);
- WritableImage image = new WritableImage((int) toPaint.getWidth(), (int) toPaint.getHeight());
- image = getScene().getRoot().snapshot(parameters, image);
- imageView.setImage(image);
- getChildren().add(imageView);
- imageView.toBack();
- setClip(new Rectangle(toPaint.getWidth(), toPaint.getHeight()));
- setVisible(true);
- }
- }
-}
-{{< / highlight >}}
+---
+outdated: true
+showInBlog: false
+title: 'Pimp your App by using the BlurPane'
+date: "2013-08-30"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'For a skin we needed a special blur effect. Our goal was to blur the complete application once a message is shown on the screen. By doing so the user is targeted only to the displayed message because the rest of the application is blured.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+For a skin we needed a special blur effect. Our goal was to blur the complete application once a message is shown on the screen. By doing so the user is targeted only to the displayed message because the rest of the application is blured. Here is a short example:
+
+
+
+Whenever a message will be shown the complete applications will become blurred:
+
+
+
+We have choosen a similar approach as it is done in the JXLayer in Swing. A invisible StackPane is placed on top of the application as an overlay. When a message appears the StackPane will become visible. The StackPane contains a ImageView that shows a blurred snapshot of the complete area under the Pane. By doing so the applications seams to be blurred. The BlurPane will be part in one of our next open source libs. But because this class has only dependencies to the JDK we want to share it here with you:
+
+```javaimport javafx.geometry.Point2D;
+import javafx.geometry.Rectangle2D;
+import javafx.scene.SnapshotParameters;
+import javafx.scene.effect.BoxBlur;
+import javafx.scene.image.ImageView;
+import javafx.scene.image.WritableImage;
+import javafx.scene.layout.StackPane;
+import javafx.scene.shape.Rectangle;
+
+public class BlurPane extends StackPane {
+
+ private ImageView imageView;
+
+ public BlurPane() {
+ imageView = new ImageView();
+ imageView.setFocusTraversable(false);
+ BoxBlur bb = new BoxBlur();
+ bb.setWidth(8);
+ bb.setHeight(8);
+ bb.setIterations(3);
+ imageView.setEffect(bb);
+ }
+
+ @Override
+ protected void layoutChildren() {
+ super.layoutChildren();
+ if (getParent() != null && isVisible()) {
+ setVisible(false);
+ getChildren().remove(imageView);
+ SnapshotParameters parameters = new SnapshotParameters();
+ Point2D startPointInScene = this.localToScene(0, 0);
+ Rectangle2D toPaint = new Rectangle2D(startPointInScene.getX(), startPointInScene.getY(), getLayoutBounds().getWidth(), getLayoutBounds().getHeight());
+ parameters.setViewport(toPaint);
+ WritableImage image = new WritableImage((int) toPaint.getWidth(), (int) toPaint.getHeight());
+ image = getScene().getRoot().snapshot(parameters, image);
+ imageView.setImage(image);
+ getChildren().add(imageView);
+ imageView.toBack();
+ setClip(new Rectangle(toPaint.getWidth(), toPaint.getHeight()));
+ setVisible(true);
+ }
+ }
+}
```
diff --git a/content/posts/2013-09-13-datafx-controller-api.md b/content/posts/2013-09-13-datafx-controller-api.md
index cffc714a..67155b8d 100644
--- a/content/posts/2013-09-13-datafx-controller-api.md
+++ b/content/posts/2013-09-13-datafx-controller-api.md
@@ -1,51 +1,45 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX Controller API'
-date: "2013-09-13"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'The DataFX team will show some cool new APIs at JavaOne this year. Today I will give a short preview to another part of the new DataFX APIs.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-The [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) team will show some cool new APIs at [JavaOne](http://www.oracle.com/javaone/index.html) this year. Johan has written [a post about writeback support in the new DataFX](http://www.lodgon.com/dali/blog/entry/Writeback_support_in_DataFX) version some days ago. Today I will give a short preview to another part of the new DataFX APIs.
-
-## The Controller API
-
-The base of the API is the inversion of control for JavaFX controllers. The API offers the annotation `FXMLController` that can be assigned to any controller class. By using this annotation you can define the FXML-View that should be used by this controller. If you don‘t define the name of the FXML-File the API will try to find the view by using a convention over configuration approach. By doing so you do not need to add Java class information in your FXML file. You can use all default FXML annotations that are defined by JavaFX. By doing so you can inject all your nodes that are defined in the fxml-file in the controller by simply adding the `@FXML` annotation. Additionally you can use the `@PostConstruct` annotation. A simple Controller that is created by this API can look like this one:
-
-{{< highlight java >}}
-@FXMLController("Details.fxml")
-public class DetailViewController {
- @FXML
- private TextField myTextfield;
- @FXML
- private Button backButton;
- @PostConstruct
- public void init() {
- myTextfield.setText("Hello!");
- }
-}
-{{< / highlight >}}
-
-To load the view and the controller DataFX-Controller offers a simple HelperClass called `ViewFactory`. This is the default entry point to the complete DataFX-Controller API. You can create a view and controller by using this class:
-
-{{< highlight java >}}
-ViewFactory.getInstance().createByController(DetailViewController.class);
-{{< / highlight >}}
-
-The FXML-file that is used by this controller can look like this one:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-If you want to see more code check out the [DataFX 2.0 repository at bitbucket](https://bitbucket.org/datafx/datafx).
-
-We will provide more samples and tutorials later, and you are very welcome to join us at JavaOne [(CON3202, Wednesday Sep 25, 08:30 am, Hilton - Plaza B)](https://oracleus.activeevents.com/2013/connect/sessionDetail.ww?SESSION_ID=3202).
+---
+outdated: true
+showInBlog: false
+title: 'DataFX Controller API'
+date: "2013-09-13"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'The DataFX team will show some cool new APIs at JavaOne this year. Today I will give a short preview to another part of the new DataFX APIs.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+The [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) team will show some cool new APIs at [JavaOne](http://www.oracle.com/javaone/index.html) this year. Johan has written [a post about writeback support in the new DataFX](http://www.lodgon.com/dali/blog/entry/Writeback_support_in_DataFX) version some days ago. Today I will give a short preview to another part of the new DataFX APIs.
+
+## The Controller API
+
+The base of the API is the inversion of control for JavaFX controllers. The API offers the annotation `FXMLController` that can be assigned to any controller class. By using this annotation you can define the FXML-View that should be used by this controller. If you don‘t define the name of the FXML-File the API will try to find the view by using a convention over configuration approach. By doing so you do not need to add Java class information in your FXML file. You can use all default FXML annotations that are defined by JavaFX. By doing so you can inject all your nodes that are defined in the fxml-file in the controller by simply adding the `@FXML` annotation. Additionally you can use the `@PostConstruct` annotation. A simple Controller that is created by this API can look like this one:
+
+```java@FXMLController("Details.fxml")
+public class DetailViewController {
+ @FXML
+ private TextField myTextfield;
+ @FXML
+ private Button backButton;
+ @PostConstruct
+ public void init() {
+ myTextfield.setText("Hello!");
+ }
+}
```
+
+To load the view and the controller DataFX-Controller offers a simple HelperClass called `ViewFactory`. This is the default entry point to the complete DataFX-Controller API. You can create a view and controller by using this class:
+
+```javaViewFactory.getInstance().createByController(DetailViewController.class);
```
+
+The FXML-file that is used by this controller can look like this one:
+
+```xml
+
+
+
+
+
+
```
+
+If you want to see more code check out the [DataFX 2.0 repository at bitbucket](https://bitbucket.org/datafx/datafx).
+
+We will provide more samples and tutorials later, and you are very welcome to join us at JavaOne [(CON3202, Wednesday Sep 25, 08:30 am, Hilton - Plaza B)](https://oracleus.activeevents.com/2013/connect/sessionDetail.ww?SESSION_ID=3202).
diff --git a/content/posts/2013-09-24-flatter.md b/content/posts/2013-09-24-flatter.md
index c5922d9c..95b44a59 100644
--- a/content/posts/2013-09-24-flatter.md
+++ b/content/posts/2013-09-24-flatter.md
@@ -8,7 +8,7 @@ categories: [Flatter, JavaFX]
excerpt: "For our JavaOne talk Claudine and I created a new JavaFX skin called Flatter. While AquaFX has it's main focus on desktop applications running on a Mac, Flatter is made for touch and embedded devices."
preview_image: "/posts/preview-images/software-development-green.svg"
---
-For our [JavaOne talk]({{< ref "/posts/2013-09-24-lets-get-wet" >}}) Claudine and I created a new JavaFX skin called Flatter. While [AquaFX](http://aquafx-project.com) has it's main focus on desktop applications running on a Mac, Flatter is made for touch and embedded devices.
+For our [JavaOne talk](/posts/2013-09-24-lets-get-wet) Claudine and I created a new JavaFX skin called Flatter. While [AquaFX](http://aquafx-project.com) has it's main focus on desktop applications running on a Mac, Flatter is made for touch and embedded devices.
Flatter is a skin that is as simple as it can be. There are no gradients or shiny effects in the skin of all the controls. Next to this the controls of flatter have a bigger appearance than all controls in the desktop skins. By doing so, they are prepared for touch. Here is a first screenshot of some of the default JavaFX controls skinned by Flatter:
@@ -26,4 +26,4 @@ As I mentioned before we created some special skins. This skins can be used for

-Flatter is still in progress, but we will open source it in the next weeks after JavaOne. You can find more information about Flatter in our ["Let's get wet" JavaOne presentation]({{< ref "/posts/2013-09-24-lets-get-wet" >}}). So if you want a flat user experience stay tuned for this one ;)
+Flatter is still in progress, but we will open source it in the next weeks after JavaOne. You can find more information about Flatter in our ["Let's get wet" JavaOne presentation](/posts/2013-09-24-lets-get-wet). So if you want a flat user experience stay tuned for this one ;)
diff --git a/content/posts/2013-09-24-make-your-app-smile-d.md b/content/posts/2013-09-24-make-your-app-smile-d.md
index b6212782..2cd10e20 100644
--- a/content/posts/2013-09-24-make-your-app-smile-d.md
+++ b/content/posts/2013-09-24-make-your-app-smile-d.md
@@ -14,4 +14,4 @@ I think most of you know the emoji icons that are used in WhatsApp and other soc
We took this control and added Emoji support to it. All the Emojis are part of the unicode standard and can be defined by simple using a char. The alien emoji is defined by char 0xF47D for example.
-You can find out more about the emoji text flow in our [JavaOne slides]({{< ref "/posts/2013-09-24-lets-get-wet" >}}). Because this is still in progress we will post a more detailed description later.
+You can find out more about the emoji text flow in our [JavaOne slides](/posts/2013-09-24-lets-get-wet). Because this is still in progress we will post a more detailed description later.
diff --git a/content/posts/2013-12-27-datafx-controller-framework-preview.md b/content/posts/2013-12-27-datafx-controller-framework-preview.md
index fb2f12aa..eaf99aa9 100644
--- a/content/posts/2013-12-27-datafx-controller-framework-preview.md
+++ b/content/posts/2013-12-27-datafx-controller-framework-preview.md
@@ -1,438 +1,390 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX Controller Framework Preview'
-date: "2013-12-27"
-author: hendrik
-categories: [DataFX, General, JavaFX]
-excerpt: 'Today we released the version 2.0 of DataFX. As a next step we will work on DataFX 8.0 that will use Java 8 and JavaFX 8.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Today we released the version 2.0 of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}). Thanks for all the feedback that we received with the last release candidates. As a next step we will work on DataFX 8.0 that will use Java 8 and JavaFX 8. One of the new features that will be part of the next release are currently in development. Today I will show a first preview to DataFX 8.0.
-
-The last month I added a new framework to DataFX. This framework should help to create the views of applications, define actions on them and create flows that contain a subset of views.
-
-To show the features of the framework I will create a simple JavaFX application. The app should manage persons. Persons can be loaded, created, edited and deleted by the app. Let's have a first look on the general concept of the application:
-
-
-
-As you can see the app contains 3 different views:
-
-* a master view that shows all persons in a list
-* a create view that can add a new person
-* a edit view to edit a person
-
-All this views are linked by actions ("save", "add", etc.) that will manipulate the data or show another view. First of all we want to take a look on the data model. Here a simple Person class is defined:
-
-{{< highlight java >}}
-public class Person {
- private StringProperty name;
- private StringProperty notes;
- public Person() {
- }
- public Person (String name, String notes) {
- setName(name);
- setNotes(notes);
- }
- public String getName() {
- return nameProperty().get();
- }
- public StringProperty nameProperty() {
- if(name == null) {
- name = new SimpleStringProperty();
- }
- return name;
- }
- public final void setName(String name) {
- this.nameProperty().set(name);
- }
- public String getNotes() {
- return notesProperty().get();
- }
- public StringProperty notesProperty() {
- if(notes == null) {
- notes = new SimpleStringProperty();
- }
- return notes;
- }
- public final void setNotes(String notes) {
- this.notesProperty().set(notes);
- }
- @Override
- public String toString() {
- return getName();
- }
-}
-{{< / highlight >}}
-
-This class defines a person. Because we want to handle a list of persons we need another class that in our case defines the global data model:
-
-{{< highlight java >}}
-public class DataModel {
- private ListProperty persons;
- private IntegerProperty selectedPersonIndex;
- public ListProperty getPersons() {
- if (persons == null) {
- ObservableList innerList = FXCollections.observableArrayList();
- persons = new SimpleListProperty<>(innerList);
- }
- return persons;
- }
- public int getSelectedPersonIndex() {
- return selectedPersonIndexProperty().get();
- }
- public void setSelectedPersonIndex(int selectedPersonIndex) {
- this.selectedPersonIndex.set(selectedPersonIndex);
- }
- public IntegerProperty selectedPersonIndexProperty() {
- if (selectedPersonIndex == null) {
- selectedPersonIndex = new SimpleIntegerProperty();
- }
- return selectedPersonIndex;
- }
-}
-{{< / highlight >}}
-
-This class defines a list of persons and the currently selected person by an index. To create a first default set of persons that can be loaded we define a additional class. In a real world application this class could wrap a database connection, for example:
-
-{{< highlight java >}}
-public class LoadPersonsTask implements Runnable {
- Person[] persons = {
- new Person("Johan Vos", "Johan is CTO at LodgON, a Java Champion, a member of the BeJUG steering group, the Devoxx steering group and he is a JCP member."),
- new Person("Jonathan Giles", "Jonathan Giles is the JavaFX UI controls technical lead at Oracle, where he has been involved with JavaFX since 2009."),
- new Person("Hendrik Ebbers", "Hendrik Ebbers is Senior Java Architect at Materna GmbH in Dortmund, Germany.")};
- @Inject
- private DataModel model;
- @Override
- public void run() {
- model.getPersons().clear();
- ListDataProvider ldp = ListDataProviderBuilder
- .create()
- .dataReader(new ArrayDataReader(persons))
- .resultList(model.getPersons())
- .build();
- ldp.retrieve();
- }
-}
-{{< / highlight >}}
-
-After the data model is defined we can create the first view. Let's start with the master view. To create the view Scene Builder can be used. Here we can easily design the following view:
-
-
-
-For all needed controls IDs are defined in the FXML. Normally you need to define a controller class in FXML. This is not needed for the DataFX Controller API. Instead of this we can bind a controller and a FXML view by the use of an annotation. As the next step a controller is needed. As a first step we create a small controller with some additional annotations:
-
-{{< highlight java >}}
-@FXMLController("listView.fxml")
-public class MasterViewController {
-@FXML
-private Button editButton;
-@FXML
-private Button removeButton;
-@FXML
-private Button addButton;
-@FXML
-private Button loadButton;
-@FXML
-private ListView dataList;
-}
-{{< / highlight >}}
-
-In this first version there is only one difference to the default JavaFX APIs: The FXMLController annotation is added. This annotation defines the link between the controller class and the FXML file. As a next step we want to create a data model. Here the next benefit of the framework can be used: Context Dependency Injection. To add a model to the the controller we can simple inject it:
-
-{{< highlight java >}}
-@Inject
-private DataModel model;
-{{< / highlight >}}
-
-To explain what happens here the CDI module in DataFX need to be described a little bit more. As in JEE CDI different scopes are supported in DataFX:
-
-* ViewScope
-* FlowScope
-* ApplicationScope
-
-All this scopes have a different context is is managed by the framework. All items that are part of the ViewScope have a lifetime of one view. A view is for example the master view in our example. The Application scope is defined as a global scope. All items in this scopes are singletons. The Singleton scope that is already defined in javax.inject can be used here, too. The flow scope defines a flow of views. In our example we will create one flow that handles all the defines views. In a more complex applications different flows can be handled. You can easily create a flow for each tap in a business application, for example. Additionally DataFX supports the dependent scope as it is defined in JEE.
-
-The data model in our application need to be defined in the flow scope. It should be accessed from all views in this scope. To do so a scope annotation need to be added to the class:
-
-{{< highlight java >}}
-@FlowScoped
-public class DataModel {
-...
-}
-{{< / highlight >}}
-
-Once this is done we can easily inject the data model in our view:
-
-{{< highlight java >}}
-@FXMLController("listView.fxml")
-public class MasterViewController {
- ...
- @Inject
- private DataModel model;
-}
-{{< / highlight >}}
-
-As a next step some initial setup is needed. To do so the PostConstruct annotation is supported by the DataFX framework:
-
-{{< highlight java >}}
-@FXMLController("listView.fxml")
-public class MasterViewController {
- ....
- @PostConstruct
- public void init() {
- dataList.itemsProperty().bind(model.getPersons());
- model.selectedPersonIndexProperty().bind(dataList.getSelectionModel().selectedIndexProperty());
- }
-}
-{{< / highlight >}}
-
-Now the ListView is bounded to the data model. To create some basic data a action is needed. This action should fire when the "load" button is pressed. First we create a simple class that handles the action:
-
-{{< highlight java >}}
-public class LoadPersonsTask implements Runnable {
- Person[] persons = {
- new Person("Johan Vos", "Johan is CTO at LodgON, a Java Champion, a member of the BeJUG steering group, the Devoxx steering group and he is a JCP member."),
- new Person("Jonathan Giles", "Jonathan Giles is the JavaFX UI controls technical lead at Oracle, where he has been involved with JavaFX since 2009."),
- new Person("Hendrik Ebbers", "Hendrik Ebbers is Senior Java Architect at Materna GmbH in Dortmund, Germany.")};
- @Inject
- private DataModel model;
- @Override
- public void run() {
- model.getPersons().clear();
- ListDataProvider ldp = ListDataProviderBuilder
- .create()
- .dataReader(new ArrayDataReader(persons))
- .resultList(model.getPersons())
- .build();
- ldp.retrieve();
- }
-}
-{{< / highlight >}}
-
-As you can see the injected model is used here, too. This task can be added to the button by the use of the Flow API. This API defines a flow through all views. The first very simply version of our flow looks like this:
-
-{{< highlight java >}}
-Flow flow = new Flow(MasterViewController.class).
- withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
-{{< / highlight >}}
-
-This defines a flow that starts with the master view and adds a task action to this view. The action is defined by the id "load". To bind this action to the load button only a additional annotation is needed in the controller:
-
-{{< highlight java >}}
-@FXML
-@FXMLFlowAction("load")
-private Button loadButton;
-{{< / highlight >}}
-
-Now the first version of the application can be started. To do so we need a main class that adds the flow to a JavaFX scene:
-
-{{< highlight java >}}
-public class DataFXDemo extends Application {
- public static void main(String[] args) {
- launch(args);
- }
- @Override
- public void start(Stage stage) throws Exception {
- Flow flow = new Flow(MasterViewController.class).
- withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
- DefaultFlowContainer container = new DefaultFlowContainer();
- flow.createHandler().start(container);
- Scene scene = new Scene(container.getPane());
- stage.setScene(scene);
- stage.show();
- }
-}
-{{< / highlight >}}
-
-The DefaultFlowContainer class is used in the code. This class is a default implementation of a Pane that wraps a flow. When you start the application the "load" button can be used to load the list of persons. Because of the JavaFX binding the result will be shown directly:
-
-
-
-As a next step we want to add the edit action to the application. Here an additional view need to be created by Scene Builder:
-
-
-
-Additionally a controller class is needed. This class uses the described features:
-
-{{< highlight java >}}
-@FXMLController("detailView.fxml")
-public class EditViewController {
- @FXML
- @FXMLFlowAction("save")
- private Button saveButton;
- @FXML
- private TextField nameField;
- @FXML
- private TextArea notesTextArea;
- @Inject
- private DataModel model;
- @PostConstruct
- public void init() {
- Person p = model.getPersons().get(model.getSelectedPersonIndex());
- nameField.textProperty().bindBidirectional(p.nameProperty());
- notesTextArea.textProperty().bindBidirectional(p.notesProperty());
- }
-}
-{{< / highlight >}}
-
-The data model is injected to the controller. Because it is defined in the flow scope it will be the same instance as in the master view. Additionally some bindings will be created to bind the UI controls to the data model. A flow action is added to the save button. This action is defined by the "save" ID. To add this view to the flow only some additional code is needed:
-
-{{< highlight java >}}
-Flow flow = new Flow(MasterViewController.class).
- withLink(MasterViewController.class, "edit", EditViewController.class).
- withLink(EditViewController.class, "save", MasterViewController.class).
- withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
-{{< / highlight >}}
-
-As you can see two links are added to the flow. This links are actions that will change the current view of the flow. In this cases we want to link from the master page to the edit page and vice versa. When you start the application now you can edit all persons that are part of the list:
-
-
-
-As a next step we want to add the remove action to the master view. This can be easily done by adding another action:
-
-{{< highlight java >}}
-public class RemoveActionTask implements Runnable {
- @Inject
- private DataModel model;
- @Override
- public void run() {
- model.getPersons().remove(model.getSelectedPersonIndex());
- }
-}
-{{< / highlight >}}
-
-As the import action this action need to be defined in the flow and bound to a button:
-
-{{< highlight java >}}
-@FXML
-@FXMLFlowAction("remove")
-private Button removeButton;
-{{< / highlight >}}
-
-Additionally the flow need to be changed:
-
-{{< highlight java >}}
-Flow flow = new Flow(MasterViewController.class).
- withLink(MasterViewController.class, "edit", EditViewController.class).
- withLink(EditViewController.class, "save", MasterViewController.class).
- withTaskAction(MasterViewController.class, "remove", RemoveActionTask.class).
- withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
-{{< / highlight >}}
-
-The Flow API of DataFX supports different types of actions. The link action and the task action are used in this example until now. As a next step we want to add the view to create new persons. Here we will use some additional features of the framework.
-
-Because the view should look like the edit view we can reuse the FXML here. Additonally a controller is needed. Here is a first basic version:
-
-{{< highlight java >}}
-@FXMLController("detailView.fxml")
-public class AddViewController {
- @FXML
- @FXMLFlowAction("save")
- private Button saveButton;
- @FXML
- private TextField nameField;
- @FXML
- private TextArea notesTextArea;
- private StringProperty nameProperty = new SimpleStringProperty();
- private StringProperty noteProperty = new SimpleStringProperty();
- @Inject
- private DataModel model;
- @PostConstruct
- public void init() {
- nameField.textProperty().bindBidirectional(nameProperty);
- notesTextArea.textProperty().bindBidirectional(noteProperty);
- }
-}
-{{< / highlight >}}
-
-The data that is added in the view will be stored in the two properties that are defined in the view. Once everything is fine a new person should be created and added to the data model. To do so we use a new action type: The MethodAction. With this type a method of the controller can easily bound to an button. To do so we add a method with the needed annotation in the controller class:
-
-{{< highlight java >}}
-@FXMLController("detailView.fxml")
-public class AddViewController {
-@FXML
-@FXMLFlowAction("save")
-private Button saveButton;
-...
-@ActionMethod("addPerson")
- public void addPerson() {
- Person p = new Person();
- p.setName(nameProperty.get());
- model.getPersons().add(p);
- }
-}
-{{< / highlight >}}
-
-Like all other actions this action need to be added to the flow. Because we want to add the person to the data model and then jump back to the master view a action chain is used here:
-
-{{< highlight java >}}
-Flow flow = new Flow(MasterViewController.class).
- withLink(MasterViewController.class, "edit", EditViewController.class).
- withLink(MasterViewController.class, "add", AddViewController.class).
- withLink(EditViewController.class, "save", MasterViewController.class).
- withTaskAction(MasterViewController.class, "remove", RemoveActionTask.class).
- withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class).
- withAction(AddViewController.class, "save", new FlowActionChain(new FlowMethodAction("addPerson"), new FlowLink(MasterViewController.class)));
-{{< / highlight >}}
-
-A action chain defines a list of actions that will be handled. In this example the "save" button is bound to an action chain that first calls the "addPerson" method and then links to the master view. By doing so new persons can be created.
-
-Next to all the action types that are shown in this example DataFX will provide additional ones and the ability to add custom action classes.
-
-As a last step we want to add validation. When a new person is created we want to check if the name is not null. The DataFX API supports the default Java Bean Validation and adds to support for JavaFX properties. Because of this we can easily add a NotNull annotation to the name property:
-
-{{< highlight java >}}
-@NotNull
-private StringProperty nameProperty = new SimpleStringProperty();
-{{< / highlight >}}
-
-To validate the data of the view a validation action can be added to the action chain that is bound to the "save" button:
-
-{{< highlight java >}}
-Flow flow = new Flow(MasterViewController.class).
- ...
- withAction(AddViewController.class, "save", new FlowActionChain(new ValidationFlowAction(), new FlowMethodAction("addPerson"), new FlowLink(MasterViewController.class)));
-{{< / highlight >}}
-
-The validation action automatically validates all validatable fields that are defined in the controller. Groups, as defined in the Java Bean Valdidation, are supported, too. When any data is not valid the action chain will stop.
-
-To provide feedback to the user some additional code is needed. The validator can be injected to the controller:
-
-{{< highlight java >}}
-@Validator
-private ValidatorFX validator;
-{{< / highlight >}}
-
-Now we can add a event handler to the validator that will show violations on screen:
-
-{{< highlight java >}}
-@FXMLController("detailView.fxml")
-public class AddViewController {
-...
- @FXML
- private Label violationLabel;
- @Validator
- private ValidatorFX validator;
- @PostConstruct
- public void init() {
- ...
- validator.setOnValidationFinished(event -> handleViolations(event.getViolations());
- }
- private void handleViolations(Set> violations) {
- if(violations.isEmpty()) {
- violationLabel.setVisible(false);
- } else {
- ConstraintViolation violation = violations.iterator().next();
- violationLabel.setText(violation.getPropertyPath() + " " + violation.getMessage());
- violationLabel.setVisible(true);
- }
- }
-}
-{{< / highlight >}}
-
-Once this is done the view will show violations on the screen:
-
-
-
-This example shows some of the DataFX Controller features. The complete API is not finished yet and can be found in a branch of the DataFX repository. I hope to receive some feedback about this example.
+---
+outdated: true
+showInBlog: false
+title: 'DataFX Controller Framework Preview'
+date: "2013-12-27"
+author: hendrik
+categories: [DataFX, General, JavaFX]
+excerpt: 'Today we released the version 2.0 of DataFX. As a next step we will work on DataFX 8.0 that will use Java 8 and JavaFX 8.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Today we released the version 2.0 of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}). Thanks for all the feedback that we received with the last release candidates. As a next step we will work on DataFX 8.0 that will use Java 8 and JavaFX 8. One of the new features that will be part of the next release are currently in development. Today I will show a first preview to DataFX 8.0.
+
+The last month I added a new framework to DataFX. This framework should help to create the views of applications, define actions on them and create flows that contain a subset of views.
+
+To show the features of the framework I will create a simple JavaFX application. The app should manage persons. Persons can be loaded, created, edited and deleted by the app. Let's have a first look on the general concept of the application:
+
+
+
+As you can see the app contains 3 different views:
+
+* a master view that shows all persons in a list
+* a create view that can add a new person
+* a edit view to edit a person
+
+All this views are linked by actions ("save", "add", etc.) that will manipulate the data or show another view. First of all we want to take a look on the data model. Here a simple Person class is defined:
+
+```javapublic class Person {
+ private StringProperty name;
+ private StringProperty notes;
+ public Person() {
+ }
+ public Person (String name, String notes) {
+ setName(name);
+ setNotes(notes);
+ }
+ public String getName() {
+ return nameProperty().get();
+ }
+ public StringProperty nameProperty() {
+ if(name == null) {
+ name = new SimpleStringProperty();
+ }
+ return name;
+ }
+ public final void setName(String name) {
+ this.nameProperty().set(name);
+ }
+ public String getNotes() {
+ return notesProperty().get();
+ }
+ public StringProperty notesProperty() {
+ if(notes == null) {
+ notes = new SimpleStringProperty();
+ }
+ return notes;
+ }
+ public final void setNotes(String notes) {
+ this.notesProperty().set(notes);
+ }
+ @Override
+ public String toString() {
+ return getName();
+ }
+}
```
+
+This class defines a person. Because we want to handle a list of persons we need another class that in our case defines the global data model:
+
+```javapublic class DataModel {
+ private ListProperty persons;
+ private IntegerProperty selectedPersonIndex;
+ public ListProperty getPersons() {
+ if (persons == null) {
+ ObservableList innerList = FXCollections.observableArrayList();
+ persons = new SimpleListProperty<>(innerList);
+ }
+ return persons;
+ }
+ public int getSelectedPersonIndex() {
+ return selectedPersonIndexProperty().get();
+ }
+ public void setSelectedPersonIndex(int selectedPersonIndex) {
+ this.selectedPersonIndex.set(selectedPersonIndex);
+ }
+ public IntegerProperty selectedPersonIndexProperty() {
+ if (selectedPersonIndex == null) {
+ selectedPersonIndex = new SimpleIntegerProperty();
+ }
+ return selectedPersonIndex;
+ }
+}
```
+
+This class defines a list of persons and the currently selected person by an index. To create a first default set of persons that can be loaded we define a additional class. In a real world application this class could wrap a database connection, for example:
+
+```javapublic class LoadPersonsTask implements Runnable {
+ Person[] persons = {
+ new Person("Johan Vos", "Johan is CTO at LodgON, a Java Champion, a member of the BeJUG steering group, the Devoxx steering group and he is a JCP member."),
+ new Person("Jonathan Giles", "Jonathan Giles is the JavaFX UI controls technical lead at Oracle, where he has been involved with JavaFX since 2009."),
+ new Person("Hendrik Ebbers", "Hendrik Ebbers is Senior Java Architect at Materna GmbH in Dortmund, Germany.")};
+ @Inject
+ private DataModel model;
+ @Override
+ public void run() {
+ model.getPersons().clear();
+ ListDataProvider ldp = ListDataProviderBuilder
+ .create()
+ .dataReader(new ArrayDataReader(persons))
+ .resultList(model.getPersons())
+ .build();
+ ldp.retrieve();
+ }
+}
```
+
+After the data model is defined we can create the first view. Let's start with the master view. To create the view Scene Builder can be used. Here we can easily design the following view:
+
+
+
+For all needed controls IDs are defined in the FXML. Normally you need to define a controller class in FXML. This is not needed for the DataFX Controller API. Instead of this we can bind a controller and a FXML view by the use of an annotation. As the next step a controller is needed. As a first step we create a small controller with some additional annotations:
+
+```java@FXMLController("listView.fxml")
+public class MasterViewController {
+@FXML
+private Button editButton;
+@FXML
+private Button removeButton;
+@FXML
+private Button addButton;
+@FXML
+private Button loadButton;
+@FXML
+private ListView dataList;
+}
```
+
+In this first version there is only one difference to the default JavaFX APIs: The FXMLController annotation is added. This annotation defines the link between the controller class and the FXML file. As a next step we want to create a data model. Here the next benefit of the framework can be used: Context Dependency Injection. To add a model to the the controller we can simple inject it:
+
+```java@Inject
+private DataModel model;
```
+
+To explain what happens here the CDI module in DataFX need to be described a little bit more. As in JEE CDI different scopes are supported in DataFX:
+
+* ViewScope
+* FlowScope
+* ApplicationScope
+
+All this scopes have a different context is is managed by the framework. All items that are part of the ViewScope have a lifetime of one view. A view is for example the master view in our example. The Application scope is defined as a global scope. All items in this scopes are singletons. The Singleton scope that is already defined in javax.inject can be used here, too. The flow scope defines a flow of views. In our example we will create one flow that handles all the defines views. In a more complex applications different flows can be handled. You can easily create a flow for each tap in a business application, for example. Additionally DataFX supports the dependent scope as it is defined in JEE.
+
+The data model in our application need to be defined in the flow scope. It should be accessed from all views in this scope. To do so a scope annotation need to be added to the class:
+
+```java@FlowScoped
+public class DataModel {
+...
+}
```
+
+Once this is done we can easily inject the data model in our view:
+
+```java@FXMLController("listView.fxml")
+public class MasterViewController {
+ ...
+ @Inject
+ private DataModel model;
+}
```
+
+As a next step some initial setup is needed. To do so the PostConstruct annotation is supported by the DataFX framework:
+
+```java@FXMLController("listView.fxml")
+public class MasterViewController {
+ ....
+ @PostConstruct
+ public void init() {
+ dataList.itemsProperty().bind(model.getPersons());
+ model.selectedPersonIndexProperty().bind(dataList.getSelectionModel().selectedIndexProperty());
+ }
+}
```
+
+Now the ListView is bounded to the data model. To create some basic data a action is needed. This action should fire when the "load" button is pressed. First we create a simple class that handles the action:
+
+```javapublic class LoadPersonsTask implements Runnable {
+ Person[] persons = {
+ new Person("Johan Vos", "Johan is CTO at LodgON, a Java Champion, a member of the BeJUG steering group, the Devoxx steering group and he is a JCP member."),
+ new Person("Jonathan Giles", "Jonathan Giles is the JavaFX UI controls technical lead at Oracle, where he has been involved with JavaFX since 2009."),
+ new Person("Hendrik Ebbers", "Hendrik Ebbers is Senior Java Architect at Materna GmbH in Dortmund, Germany.")};
+ @Inject
+ private DataModel model;
+ @Override
+ public void run() {
+ model.getPersons().clear();
+ ListDataProvider ldp = ListDataProviderBuilder
+ .create()
+ .dataReader(new ArrayDataReader(persons))
+ .resultList(model.getPersons())
+ .build();
+ ldp.retrieve();
+ }
+}
```
+
+As you can see the injected model is used here, too. This task can be added to the button by the use of the Flow API. This API defines a flow through all views. The first very simply version of our flow looks like this:
+
+```javaFlow flow = new Flow(MasterViewController.class).
+ withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
```
+
+This defines a flow that starts with the master view and adds a task action to this view. The action is defined by the id "load". To bind this action to the load button only a additional annotation is needed in the controller:
+
+```java@FXML
+@FXMLFlowAction("load")
+private Button loadButton;
```
+
+Now the first version of the application can be started. To do so we need a main class that adds the flow to a JavaFX scene:
+
+```javapublic class DataFXDemo extends Application {
+ public static void main(String[] args) {
+ launch(args);
+ }
+ @Override
+ public void start(Stage stage) throws Exception {
+ Flow flow = new Flow(MasterViewController.class).
+ withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
+ DefaultFlowContainer container = new DefaultFlowContainer();
+ flow.createHandler().start(container);
+ Scene scene = new Scene(container.getPane());
+ stage.setScene(scene);
+ stage.show();
+ }
+}
```
+
+The DefaultFlowContainer class is used in the code. This class is a default implementation of a Pane that wraps a flow. When you start the application the "load" button can be used to load the list of persons. Because of the JavaFX binding the result will be shown directly:
+
+
+
+As a next step we want to add the edit action to the application. Here an additional view need to be created by Scene Builder:
+
+
+
+Additionally a controller class is needed. This class uses the described features:
+
+```java@FXMLController("detailView.fxml")
+public class EditViewController {
+ @FXML
+ @FXMLFlowAction("save")
+ private Button saveButton;
+ @FXML
+ private TextField nameField;
+ @FXML
+ private TextArea notesTextArea;
+ @Inject
+ private DataModel model;
+ @PostConstruct
+ public void init() {
+ Person p = model.getPersons().get(model.getSelectedPersonIndex());
+ nameField.textProperty().bindBidirectional(p.nameProperty());
+ notesTextArea.textProperty().bindBidirectional(p.notesProperty());
+ }
+}
```
+
+The data model is injected to the controller. Because it is defined in the flow scope it will be the same instance as in the master view. Additionally some bindings will be created to bind the UI controls to the data model. A flow action is added to the save button. This action is defined by the "save" ID. To add this view to the flow only some additional code is needed:
+
+```javaFlow flow = new Flow(MasterViewController.class).
+ withLink(MasterViewController.class, "edit", EditViewController.class).
+ withLink(EditViewController.class, "save", MasterViewController.class).
+ withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
```
+
+As you can see two links are added to the flow. This links are actions that will change the current view of the flow. In this cases we want to link from the master page to the edit page and vice versa. When you start the application now you can edit all persons that are part of the list:
+
+
+
+As a next step we want to add the remove action to the master view. This can be easily done by adding another action:
+
+```javapublic class RemoveActionTask implements Runnable {
+ @Inject
+ private DataModel model;
+ @Override
+ public void run() {
+ model.getPersons().remove(model.getSelectedPersonIndex());
+ }
+}
```
+
+As the import action this action need to be defined in the flow and bound to a button:
+
+```java@FXML
+@FXMLFlowAction("remove")
+private Button removeButton;
```
+
+Additionally the flow need to be changed:
+
+```javaFlow flow = new Flow(MasterViewController.class).
+ withLink(MasterViewController.class, "edit", EditViewController.class).
+ withLink(EditViewController.class, "save", MasterViewController.class).
+ withTaskAction(MasterViewController.class, "remove", RemoveActionTask.class).
+ withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
```
+
+The Flow API of DataFX supports different types of actions. The link action and the task action are used in this example until now. As a next step we want to add the view to create new persons. Here we will use some additional features of the framework.
+
+Because the view should look like the edit view we can reuse the FXML here. Additonally a controller is needed. Here is a first basic version:
+
+```java@FXMLController("detailView.fxml")
+public class AddViewController {
+ @FXML
+ @FXMLFlowAction("save")
+ private Button saveButton;
+ @FXML
+ private TextField nameField;
+ @FXML
+ private TextArea notesTextArea;
+ private StringProperty nameProperty = new SimpleStringProperty();
+ private StringProperty noteProperty = new SimpleStringProperty();
+ @Inject
+ private DataModel model;
+ @PostConstruct
+ public void init() {
+ nameField.textProperty().bindBidirectional(nameProperty);
+ notesTextArea.textProperty().bindBidirectional(noteProperty);
+ }
+}
```
+
+The data that is added in the view will be stored in the two properties that are defined in the view. Once everything is fine a new person should be created and added to the data model. To do so we use a new action type: The MethodAction. With this type a method of the controller can easily bound to an button. To do so we add a method with the needed annotation in the controller class:
+
+```java@FXMLController("detailView.fxml")
+public class AddViewController {
+@FXML
+@FXMLFlowAction("save")
+private Button saveButton;
+...
+@ActionMethod("addPerson")
+ public void addPerson() {
+ Person p = new Person();
+ p.setName(nameProperty.get());
+ model.getPersons().add(p);
+ }
+}
```
+
+Like all other actions this action need to be added to the flow. Because we want to add the person to the data model and then jump back to the master view a action chain is used here:
+
+```javaFlow flow = new Flow(MasterViewController.class).
+ withLink(MasterViewController.class, "edit", EditViewController.class).
+ withLink(MasterViewController.class, "add", AddViewController.class).
+ withLink(EditViewController.class, "save", MasterViewController.class).
+ withTaskAction(MasterViewController.class, "remove", RemoveActionTask.class).
+ withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class).
+ withAction(AddViewController.class, "save", new FlowActionChain(new FlowMethodAction("addPerson"), new FlowLink(MasterViewController.class)));
```
+
+A action chain defines a list of actions that will be handled. In this example the "save" button is bound to an action chain that first calls the "addPerson" method and then links to the master view. By doing so new persons can be created.
+
+Next to all the action types that are shown in this example DataFX will provide additional ones and the ability to add custom action classes.
+
+As a last step we want to add validation. When a new person is created we want to check if the name is not null. The DataFX API supports the default Java Bean Validation and adds to support for JavaFX properties. Because of this we can easily add a NotNull annotation to the name property:
+
+```java@NotNull
+private StringProperty nameProperty = new SimpleStringProperty();
```
+
+To validate the data of the view a validation action can be added to the action chain that is bound to the "save" button:
+
+```javaFlow flow = new Flow(MasterViewController.class).
+ ...
+ withAction(AddViewController.class, "save", new FlowActionChain(new ValidationFlowAction(), new FlowMethodAction("addPerson"), new FlowLink(MasterViewController.class)));
```
+
+The validation action automatically validates all validatable fields that are defined in the controller. Groups, as defined in the Java Bean Valdidation, are supported, too. When any data is not valid the action chain will stop.
+
+To provide feedback to the user some additional code is needed. The validator can be injected to the controller:
+
+```java@Validator
+private ValidatorFX validator;
```
+
+Now we can add a event handler to the validator that will show violations on screen:
+
+```java@FXMLController("detailView.fxml")
+public class AddViewController {
+...
+ @FXML
+ private Label violationLabel;
+ @Validator
+ private ValidatorFX validator;
+ @PostConstruct
+ public void init() {
+ ...
+ validator.setOnValidationFinished(event -> handleViolations(event.getViolations());
+ }
+ private void handleViolations(Set> violations) {
+ if(violations.isEmpty()) {
+ violationLabel.setVisible(false);
+ } else {
+ ConstraintViolation violation = violations.iterator().next();
+ violationLabel.setText(violation.getPropertyPath() + " " + violation.getMessage());
+ violationLabel.setVisible(true);
+ }
+ }
+}
```
+
+Once this is done the view will show violations on the screen:
+
+
+
+This example shows some of the DataFX Controller features. The complete API is not finished yet and can be found in a branch of the DataFX repository. I hope to receive some feedback about this example.
diff --git a/content/posts/2014-01-23-datafx-8-preview-2-processchain.md b/content/posts/2014-01-23-datafx-8-preview-2-processchain.md
index c4651c4b..641586a6 100644
--- a/content/posts/2014-01-23-datafx-8-preview-2-processchain.md
+++ b/content/posts/2014-01-23-datafx-8-preview-2-processchain.md
@@ -1,57 +1,55 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX 8 Preview 2: The ProcessChain'
-date: "2014-01-23"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'This DataFX 8 preview introduces the ProcessChain. This uses Java 8 features like Lambda to provide multi threaded functionality in JavaFX'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Some time ago I gave a [first preview of the new APIs and functions]({{< ref "/posts/2013-12-27-datafx-controller-framework-preview" >}}) in [DataFX 8]({{ site.baseurl }}{% link pages/projects/datafx.md %}). We are currently plan to release DataFX 8 once JavaFX 8 is released. I plan to blog about the new features in DataFX in the next weeks. By doing so we hope to receive some useful feedback. In the last preview I described the [controller and flow API]({{< ref "/posts/2013-12-27-datafx-controller-framework-preview" >}}) of DataFX. Today I will show you only only small class :)
-
-Next to new APIs we added some helpful classes to the DataFX core packages. The class that I want to show you today is one of these new classes: The ProcessChain.
-
-The ProcessChain can be used to create a task chain. A task can be run on the "JavaFX Application Thread" or on a background thread. Some of you may know the SwingWorker class that was a important tool when working with background tasks in Swing. With the ProcessChain you can do similar stuff but thanks to Java 8, Lambdas and functional interfaces this class is more powerful that SwingWorker ever was.
-
-Let's think about a dialog that loads some data from a server. This can be done by clicking a button. Whenever the button is pressed the following workflow should be executed:
-
-* Disable Button
-* Communicate with Server
-* Enable Button
-
-The button must enabled and disabled on the "JavaFX Application Thread" but you should not communicate with the server on this thread cause it will freeze the application. Because of that the communication must be executed on a extra thread:
-
-* Disable Button (Application Thread)
-* Communicate with Server (Background-Thread)
-* Enable Button (Application Thread)
-
-The ProcessChain is a fluent API that can be used to create this workflows in JavaFX. Because its a chain you can add as many task as you want. The ProcessChain can use Lambdas and pass task results to the next Task. The following default interfaces can be used here:
-
-* java.util.function.Function
-* java.util.function.Supplier
-* java.util.function.Consumer
-* java.lang.Runnable
-
-Here is a simple example:
-
-{{< highlight java >}}
-Label label = new Label("No data");
-Button button = new Button("Press me“);
-button.setOnAction(new EventHandler() {
- public void handle(ActionEvent event) {
- new ProcessChain().inPlatformThread(() -> button.setDisable(true))
- .inExecutor(() -> communicateWithServer())
- .inExecutor(() -> {return "Time in Millis: " + System.currentTimeMillis();})
- .inPlatformThread((Consumer) (t) -> label.setText(t.toString()))
- .inPlatformThread(() -> button.setDisable(false))
- .run();
- }
-});
-{{< / highlight >}}
-
-As you can see in the example it is very easy to create a chain with the API. By using the `inExecutor(...)` or `inPlatformThread(...)` method a developer can choose if a task should run on the "JavaFX Application Thread" or in background.
-
-In addition tasks can publish its result and use the result of the previous one. Here the new Java 8 interfaces Function, Supplier and Consumer can be used to define tasks with an input or output value.
-
-The DataReader API is still part of DataFX of course. If you use DataReaders you shouldn't need the shown API or can add all tasks to the Platform thread. But sometimes there are issues where you need to create your own custom background tasks. In these cases the ProcessChain is your friend ;)
+---
+outdated: true
+showInBlog: false
+title: 'DataFX 8 Preview 2: The ProcessChain'
+date: "2014-01-23"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'This DataFX 8 preview introduces the ProcessChain. This uses Java 8 features like Lambda to provide multi threaded functionality in JavaFX'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Some time ago I gave a [first preview of the new APIs and functions](/posts/2013-12-27-datafx-controller-framework-preview) in [DataFX 8]({{ site.baseurl }}{% link pages/projects/datafx.md %}). We are currently plan to release DataFX 8 once JavaFX 8 is released. I plan to blog about the new features in DataFX in the next weeks. By doing so we hope to receive some useful feedback. In the last preview I described the [controller and flow API](/posts/2013-12-27-datafx-controller-framework-preview) of DataFX. Today I will show you only only small class :)
+
+Next to new APIs we added some helpful classes to the DataFX core packages. The class that I want to show you today is one of these new classes: The ProcessChain.
+
+The ProcessChain can be used to create a task chain. A task can be run on the "JavaFX Application Thread" or on a background thread. Some of you may know the SwingWorker class that was a important tool when working with background tasks in Swing. With the ProcessChain you can do similar stuff but thanks to Java 8, Lambdas and functional interfaces this class is more powerful that SwingWorker ever was.
+
+Let's think about a dialog that loads some data from a server. This can be done by clicking a button. Whenever the button is pressed the following workflow should be executed:
+
+* Disable Button
+* Communicate with Server
+* Enable Button
+
+The button must enabled and disabled on the "JavaFX Application Thread" but you should not communicate with the server on this thread cause it will freeze the application. Because of that the communication must be executed on a extra thread:
+
+* Disable Button (Application Thread)
+* Communicate with Server (Background-Thread)
+* Enable Button (Application Thread)
+
+The ProcessChain is a fluent API that can be used to create this workflows in JavaFX. Because its a chain you can add as many task as you want. The ProcessChain can use Lambdas and pass task results to the next Task. The following default interfaces can be used here:
+
+* java.util.function.Function
+* java.util.function.Supplier
+* java.util.function.Consumer
+* java.lang.Runnable
+
+Here is a simple example:
+
+```javaLabel label = new Label("No data");
+Button button = new Button("Press me“);
+button.setOnAction(new EventHandler() {
+ public void handle(ActionEvent event) {
+ new ProcessChain().inPlatformThread(() -> button.setDisable(true))
+ .inExecutor(() -> communicateWithServer())
+ .inExecutor(() -> {return "Time in Millis: " + System.currentTimeMillis();})
+ .inPlatformThread((Consumer) (t) -> label.setText(t.toString()))
+ .inPlatformThread(() -> button.setDisable(false))
+ .run();
+ }
+});
```
+
+As you can see in the example it is very easy to create a chain with the API. By using the `inExecutor(...)` or `inPlatformThread(...)` method a developer can choose if a task should run on the "JavaFX Application Thread" or in background.
+
+In addition tasks can publish its result and use the result of the previous one. Here the new Java 8 interfaces Function, Supplier and Consumer can be used to define tasks with an input or output value.
+
+The DataReader API is still part of DataFX of course. If you use DataReaders you shouldn't need the shown API or can add all tasks to the Platform thread. But sometimes there are issues where you need to create your own custom background tasks. In these cases the ProcessChain is your friend ;)
diff --git a/content/posts/2014-01-24-javafx-meets-javaee.md b/content/posts/2014-01-24-javafx-meets-javaee.md
index ef9a7135..df8e8ccc 100644
--- a/content/posts/2014-01-24-javafx-meets-javaee.md
+++ b/content/posts/2014-01-24-javafx-meets-javaee.md
@@ -12,7 +12,7 @@ At [JavaOne](http://www.oracle.com/javaone/) [Arun Gupta](https://www.java.net//

-After reading the book you are ready to develop a web application that is based on JEE 7. Most of this applications will have a web frontend that is based on JSF as it is shown in the book, too. But as I mentioned in a [earlier post]({{< ref "/posts/2013-05-11-designing-javafx-business-applications-part-1" >}}), a modern business applications often needs support for mobile or desktop applications:
+After reading the book you are ready to develop a web application that is based on JEE 7. Most of this applications will have a web frontend that is based on JSF as it is shown in the book, too. But as I mentioned in a [earlier post](/posts/2013-05-11-designing-javafx-business-applications-part-1), a modern business applications often needs support for mobile or desktop applications:

@@ -61,7 +61,7 @@ With DataFX 2.0 we will introduce the flow API. By using this API you can simply
## Contexts and Dependency Injection
-As shown in [one of my last posts]({{< ref "/posts/2013-12-27-datafx-controller-framework-preview" >}}) DataFX supports context dependency injection in controllers. Currently Providers, etc. are not supported. This will be one of the next features that we want to add. DataFX currently support the following scopes:
+As shown in [one of my last posts](/posts/2013-12-27-datafx-controller-framework-preview) DataFX supports context dependency injection in controllers. Currently Providers, etc. are not supported. This will be one of the next features that we want to add. DataFX currently support the following scopes:
* viewScope
* flowScope
@@ -69,12 +69,12 @@ As shown in [one of my last posts]({{< ref "/posts/2013-12-27-datafx-controller-
## Concurrency Utilities
-With JEE 7 you can use Executor instances in your business app. In DataFX we provide different classes and utility functions to provide a great support for concurrency. Next to invokeLater(...) method that is part of JavaFX you can find [invokeAndWait(...) utility methods in DataFX-core]({{< ref "/posts/2013-01-01-invokeandwait-for-javafx" >}}). These can be used to create your own background task API. In addition DataFX provides a [new Executor class]({{< ref "/posts/2013-02-09-datafx-observableexecutor-preview" >}}) that supports JavaFX properties. In most cases you can use the DataReader API of DataFX to handle background tasks. In some special cases you can use the [ProcessChain class]({{ site.baseurl }}{% post_url 2014-01-23-datafx-8-preview-2-processchain %}
+With JEE 7 you can use Executor instances in your business app. In DataFX we provide different classes and utility functions to provide a great support for concurrency. Next to invokeLater(...) method that is part of JavaFX you can find [invokeAndWait(...) utility methods in DataFX-core](/posts/2013-01-01-invokeandwait-for-javafx). These can be used to create your own background task API. In addition DataFX provides a [new Executor class](/posts/2013-02-09-datafx-observableexecutor-preview) that supports JavaFX properties. In most cases you can use the DataReader API of DataFX to handle background tasks. In some special cases you can use the [ProcessChain class]({{ site.baseurl }}{% post_url 2014-01-23-datafx-8-preview-2-processchain %}
) that will be new in DataFX 8.
## Bean Validation
-Thanks to JEE we have a [default specification](http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html) for bean validation. DataFX uses this specification, too. By doing so a developer doesn't need to learn new APIs. All the annotations and interfaces that are part of [JSR 303](http://beanvalidation.org/1.0/spec/) can be used in DataFX. A first example how bean validation works in DataFX can be found [here]({{< ref "/posts/2013-12-27-datafx-controller-framework-preview" >}}).
+Thanks to JEE we have a [default specification](http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html) for bean validation. DataFX uses this specification, too. By doing so a developer doesn't need to learn new APIs. All the annotations and interfaces that are part of [JSR 303](http://beanvalidation.org/1.0/spec/) can be used in DataFX. A first example how bean validation works in DataFX can be found [here](/posts/2013-12-27-datafx-controller-framework-preview).
## Java Persistence
diff --git a/content/posts/2014-03-27-datafx-8-nighthacking.md b/content/posts/2014-03-27-datafx-8-nighthacking.md
index 6de4c7d2..2d9f7c8b 100644
--- a/content/posts/2014-03-27-datafx-8-nighthacking.md
+++ b/content/posts/2014-03-27-datafx-8-nighthacking.md
@@ -10,5 +10,5 @@ preview_image: "/posts/preview-images/software-development-green.svg"
---
[Stephen Chin](https://twitter.com/steveonjava) has interviewed me yesterday for [http://nighthacking.com](http://nighthacking.com) about DataFX 8. In the interview I show a lot of new features and APIs of DataFX. Have fun :)
-{{< youtube 94oUnzlPUyQ >}}
+
diff --git a/content/posts/2014-03-28-reactive-programming-javafx.md b/content/posts/2014-03-28-reactive-programming-javafx.md
index fd146724..1c72c9b2 100644
--- a/content/posts/2014-03-28-reactive-programming-javafx.md
+++ b/content/posts/2014-03-28-reactive-programming-javafx.md
@@ -1,55 +1,49 @@
----
-outdated: true
-showInBlog: false
-title: 'Reactive Programming with JavaFX'
-date: "2014-03-28"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'Because the JavaFX API was designed for Java 8 it provides a lot of Lambda support and callbacks are used a lot. But next to the default JavaFX APIs there are currently an open source projects that adds a lot of reactive design and architecture to the JavaFX basics: ReactFX.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Java 8 is finally released and Lambda expression are an official part of Java. Thanks to this it's much easier to write applications in a reactive way. One of the main concepts in reactive architecture is an __event driven design__. [The reactive manifesto](http://www.reactivemanifesto.org/) contains the following about event driven design:
-
-> In an event-driven application, the components interact with each other through the production and consumption of events—discrete pieces of information describing facts. These events are sent and received in an asynchronous and non-blocking fashion.
-
-## Reactive Programming with Java
-
-By using Lambdas it's very easy to define callbacks that can react on specific events. Here is a short example about an event driven design without the usage of Lambda expressions:
-
-{{< highlight java >}}
-public static void hello(String... names) {
- Observable.from(names).subscribe(new Action() {
- @Override
- public void call(String s) {
- System.out.println("Hello " + s + "!");
- }
- });
-}
-{{< / highlight >}}
-
-Thanks to Lambda expressions the same functionallity can be coded in Java 8 this way:
-
-{{< highlight java >}}
-public static void hello(String... names) {
- Observable.from(names).subscribe((s) -> System.out.println("Hello " + s + "!"));
-}
-{{< / highlight >}}
-
-The example is part of the [RxJava tutorial](https://github.com/Netflix/RxJava/wiki/Getting-Started).
-
-## Reactive Programming with JavaFX
-
-Let's take a look at JavaFX. Because the JavaFX API was designed for Java 8 it provides a lot of Lambda support and callbacks are used a lot. But next to the default JavaFX APIs there are currently an open source projects that adds a lot of reactive design and architecture to the JavaFX basics: [ReactFX](https://github.com/TomasMikula/ReactFX).
-
-By using ReactFX you can do a lot of cool event driven stuff with only a few lines of code. Here is an example how event handlers can be designed to react on user inputs:
-
-{{< highlight java >}}
-EventStream clicks = EventStreams.eventsOf(node, MouseEvent.MOUSE_CLICKED);
-clicks.subscribe(click -> System.out.println("Click!"));
-{{< / highlight >}}
-
-I think the API provides a lot of cool functionallity that let you design JavaFX applications that are more reactive and I hope to see a lot of more code like shown in the example above.
-
-## Summery
-
-The are currently 2 cool reactive APIs for Java out there: [RxJava](https://github.com/Netflix/RxJava/wiki/Getting-Started) for a basic use in Java and [ReactFX](https://github.com/TomasMikula/ReactFX) that is specialized for JavaFX. Theoretically you can do everything (or most of the stuff) you can do with ReactFXwith the help of RxJava, too. But here you need to concern about the JavaFX Application Thread. Because ReactFX is implementated for JavaFX (or a single threaded environment) you don't need to handle this. A first comparison of this two libraries can be found [here](https://gist.github.com/timyates/fd6904dcca366d50729c#comment-1198536).
+---
+outdated: true
+showInBlog: false
+title: 'Reactive Programming with JavaFX'
+date: "2014-03-28"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'Because the JavaFX API was designed for Java 8 it provides a lot of Lambda support and callbacks are used a lot. But next to the default JavaFX APIs there are currently an open source projects that adds a lot of reactive design and architecture to the JavaFX basics: ReactFX.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Java 8 is finally released and Lambda expression are an official part of Java. Thanks to this it's much easier to write applications in a reactive way. One of the main concepts in reactive architecture is an __event driven design__. [The reactive manifesto](http://www.reactivemanifesto.org/) contains the following about event driven design:
+
+> In an event-driven application, the components interact with each other through the production and consumption of events—discrete pieces of information describing facts. These events are sent and received in an asynchronous and non-blocking fashion.
+
+## Reactive Programming with Java
+
+By using Lambdas it's very easy to define callbacks that can react on specific events. Here is a short example about an event driven design without the usage of Lambda expressions:
+
+```javapublic static void hello(String... names) {
+ Observable.from(names).subscribe(new Action() {
+ @Override
+ public void call(String s) {
+ System.out.println("Hello " + s + "!");
+ }
+ });
+}
```
+
+Thanks to Lambda expressions the same functionallity can be coded in Java 8 this way:
+
+```javapublic static void hello(String... names) {
+ Observable.from(names).subscribe((s) -> System.out.println("Hello " + s + "!"));
+}
```
+
+The example is part of the [RxJava tutorial](https://github.com/Netflix/RxJava/wiki/Getting-Started).
+
+## Reactive Programming with JavaFX
+
+Let's take a look at JavaFX. Because the JavaFX API was designed for Java 8 it provides a lot of Lambda support and callbacks are used a lot. But next to the default JavaFX APIs there are currently an open source projects that adds a lot of reactive design and architecture to the JavaFX basics: [ReactFX](https://github.com/TomasMikula/ReactFX).
+
+By using ReactFX you can do a lot of cool event driven stuff with only a few lines of code. Here is an example how event handlers can be designed to react on user inputs:
+
+```javaEventStream clicks = EventStreams.eventsOf(node, MouseEvent.MOUSE_CLICKED);
+clicks.subscribe(click -> System.out.println("Click!"));
```
+
+I think the API provides a lot of cool functionallity that let you design JavaFX applications that are more reactive and I hope to see a lot of more code like shown in the example above.
+
+## Summery
+
+The are currently 2 cool reactive APIs for Java out there: [RxJava](https://github.com/Netflix/RxJava/wiki/Getting-Started) for a basic use in Java and [ReactFX](https://github.com/TomasMikula/ReactFX) that is specialized for JavaFX. Theoretically you can do everything (or most of the stuff) you can do with ReactFXwith the help of RxJava, too. But here you need to concern about the JavaFX Application Thread. Because ReactFX is implementated for JavaFX (or a single threaded environment) you don't need to handle this. A first comparison of this two libraries can be found [here](https://gist.github.com/timyates/fd6904dcca366d50729c#comment-1198536).
diff --git a/content/posts/2014-03-29-javafx-css-utilities.md b/content/posts/2014-03-29-javafx-css-utilities.md
index 49efe152..9ba4e41b 100644
--- a/content/posts/2014-03-29-javafx-css-utilities.md
+++ b/content/posts/2014-03-29-javafx-css-utilities.md
@@ -1,106 +1,100 @@
----
-outdated: true
-showInBlog: false
-title: 'JavaFX CSS Utilities'
-date: "2014-03-29"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'Ever tried to add a Styleable property to a JavaFX Control or Skin? By doing so you can add additional CSS support to a Control type.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Ever tried to add a Styleable property to a JavaFX Control or Skin? By doing so you can add additional CSS support to a Control type. [Gerrit Grunwald](https://twitter.com/hansolo_) has described the benefits of styleable properties in a [blog post](http://harmoniccode.blogspot.de/2013/05/css-confusing-style-sheets.html). One big problem is the boilerplate code that will be created when implementing these properties in a Control class. Here is an example how a Control with only one property will look like:
-
-{{< highlight java >}}
-public class MyControl extends Control {
- private StyleableObjectProperty backgroundFill;
- public Paint getBackgroundFill() {
- return backgroundFill == null ? Color.GRAY : backgroundFill.get();
- }
- public void setBackgroundFill(Paint backgroundFill) {
- this.backgroundFill.set(backgroundFill);
- }
- public StyleableObjectProperty backgroundFillProperty() {
- if (backgroundFill == null) {
- backgroundFill = new SimpleStyleableObjectProperty(StyleableProperties.BACKGROUND_FILL, MyControl.this, "backgroundFill", Color.GRAY);
- }
- return backgroundFill;
- }
- private static class StyleableProperties {
- private static final CssMetaData< MyControl, Paint> BACKGROUND_FILL =
- new CssMetaData< MyControl, Paint>("-fx-background-fill",
- PaintConverter.getInstance(), Color.GRAY) {
- @Override
- public boolean isSettable(MyControl control) {
- return control.backgroundFill == null || !control.backgroundFill.isBound();
- }
- @Override
- public StyleableProperty getStyleableProperty(MyControl control) {
- return control.backgroundFillProperty();
- }
- };
- private static final List> STYLEABLES;
- static {
- final List> styleables =
- new ArrayList>(Control.getClassCssMetaData());
- Collections.addAll(styleables,
- BACKGROUND_FILL
- );
- STYLEABLES = Collections.unmodifiableList(styleables);
- }
- }
- @Override
- public List> getControlCssMetaData() {
- return getClassCssMetaData();
- }
- public static List> getClassCssMetaData() {
- return StyleableProperties.STYLEABLES;
- }
-}
-{{< / highlight >}}
-
-That's a lot of code for only one property. Therefore I created some helper classes to do all the work. These classes are part of the "css-helper" library that I released today.
-
-Here is an example how the Control will look like when using the "css-helper" library:
-
-{{< highlight java >}}
-public class MyControl extends Control {
- private StyleableObjectProperty backgroundFill;
- public Paint getBackgroundFill() {
- return backgroundFill == null ? Color.GRAY : backgroundFill.get();
- }
- public void setBackgroundFill(Paint backgroundFill) {
- this.backgroundFill.set(backgroundFill);
- }
- public StyleableObjectProperty backgroundFillProperty() {
- if (backgroundFill == null) {
- backgroundFill = CssHelper.createProperty(StyleableProperties.BACKGROUND_FILL, MyControl);
- }
- return backgroundFill;
- }
- private static class StyleableProperties {
- private static final CssHelper.PropertyBasedCssMetaData BACKGROUND_FILL = CssHelper.createMetaData("-fx-background-fill", PaintConverter.getInstance(), "backgroundFill", Color.LIGHTGREEN);
- private static final List> STYLEABLES = CssHelper.createCssMetaDataList(Control.getClassCssMetaData(), BACKGROUND_FILL);
- }
- @Override
- public List> getControlCssMetaData() {
- return getClassCssMetaData();
- }
- public static List> getClassCssMetaData() {
- return StyleableProperties.STYLEABLES;
- }
-}
-{{< / highlight >}}
-
-By using the static methods of the CssHelper class the code is much more readable.
-
-But there is one problem with the API: It uses reflection internally and because of this the CSS algorithm will be slower as when using the first aproach. So the CssHelper should only be used for Controls that should not be part of an open source library and don't appear often in the scene graph. If you need a special Control in your application or add a CSS property to an existing one you can use these classes to minimize the source code.
-
-The Library is deployed to [Maven Central](http://search.maven.org/#artifactdetails%7Ccom.guigarage%7Ccss-helper%7C0.1%7Cjar) and can be easily added to a Maven project:
-
-{{< highlight xml >}}
-
- com.guigarage
- css-helper
- 0.1
-
-{{< / highlight >}}
+---
+outdated: true
+showInBlog: false
+title: 'JavaFX CSS Utilities'
+date: "2014-03-29"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'Ever tried to add a Styleable property to a JavaFX Control or Skin? By doing so you can add additional CSS support to a Control type.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Ever tried to add a Styleable property to a JavaFX Control or Skin? By doing so you can add additional CSS support to a Control type. [Gerrit Grunwald](https://twitter.com/hansolo_) has described the benefits of styleable properties in a [blog post](http://harmoniccode.blogspot.de/2013/05/css-confusing-style-sheets.html). One big problem is the boilerplate code that will be created when implementing these properties in a Control class. Here is an example how a Control with only one property will look like:
+
+```javapublic class MyControl extends Control {
+ private StyleableObjectProperty backgroundFill;
+ public Paint getBackgroundFill() {
+ return backgroundFill == null ? Color.GRAY : backgroundFill.get();
+ }
+ public void setBackgroundFill(Paint backgroundFill) {
+ this.backgroundFill.set(backgroundFill);
+ }
+ public StyleableObjectProperty backgroundFillProperty() {
+ if (backgroundFill == null) {
+ backgroundFill = new SimpleStyleableObjectProperty(StyleableProperties.BACKGROUND_FILL, MyControl.this, "backgroundFill", Color.GRAY);
+ }
+ return backgroundFill;
+ }
+ private static class StyleableProperties {
+ private static final CssMetaData< MyControl, Paint> BACKGROUND_FILL =
+ new CssMetaData< MyControl, Paint>("-fx-background-fill",
+ PaintConverter.getInstance(), Color.GRAY) {
+ @Override
+ public boolean isSettable(MyControl control) {
+ return control.backgroundFill == null || !control.backgroundFill.isBound();
+ }
+ @Override
+ public StyleableProperty getStyleableProperty(MyControl control) {
+ return control.backgroundFillProperty();
+ }
+ };
+ private static final List> STYLEABLES;
+ static {
+ final List> styleables =
+ new ArrayList>(Control.getClassCssMetaData());
+ Collections.addAll(styleables,
+ BACKGROUND_FILL
+ );
+ STYLEABLES = Collections.unmodifiableList(styleables);
+ }
+ }
+ @Override
+ public List> getControlCssMetaData() {
+ return getClassCssMetaData();
+ }
+ public static List> getClassCssMetaData() {
+ return StyleableProperties.STYLEABLES;
+ }
+}
```
+
+That's a lot of code for only one property. Therefore I created some helper classes to do all the work. These classes are part of the "css-helper" library that I released today.
+
+Here is an example how the Control will look like when using the "css-helper" library:
+
+```javapublic class MyControl extends Control {
+ private StyleableObjectProperty backgroundFill;
+ public Paint getBackgroundFill() {
+ return backgroundFill == null ? Color.GRAY : backgroundFill.get();
+ }
+ public void setBackgroundFill(Paint backgroundFill) {
+ this.backgroundFill.set(backgroundFill);
+ }
+ public StyleableObjectProperty backgroundFillProperty() {
+ if (backgroundFill == null) {
+ backgroundFill = CssHelper.createProperty(StyleableProperties.BACKGROUND_FILL, MyControl);
+ }
+ return backgroundFill;
+ }
+ private static class StyleableProperties {
+ private static final CssHelper.PropertyBasedCssMetaData BACKGROUND_FILL = CssHelper.createMetaData("-fx-background-fill", PaintConverter.getInstance(), "backgroundFill", Color.LIGHTGREEN);
+ private static final List> STYLEABLES = CssHelper.createCssMetaDataList(Control.getClassCssMetaData(), BACKGROUND_FILL);
+ }
+ @Override
+ public List> getControlCssMetaData() {
+ return getClassCssMetaData();
+ }
+ public static List> getClassCssMetaData() {
+ return StyleableProperties.STYLEABLES;
+ }
+}
```
+
+By using the static methods of the CssHelper class the code is much more readable.
+
+But there is one problem with the API: It uses reflection internally and because of this the CSS algorithm will be slower as when using the first aproach. So the CssHelper should only be used for Controls that should not be part of an open source library and don't appear often in the scene graph. If you need a special Control in your application or add a CSS property to an existing one you can use these classes to minimize the source code.
+
+The Library is deployed to [Maven Central](http://search.maven.org/#artifactdetails%7Ccom.guigarage%7Ccss-helper%7C0.1%7Cjar) and can be easily added to a Maven project:
+
+```xml
+ com.guigarage
+ css-helper
+ 0.1
+
```
diff --git a/content/posts/2014-05-15-javafx-8-interview-jax-2014.md b/content/posts/2014-05-15-javafx-8-interview-jax-2014.md
index 12d2e549..715cfaf7 100644
--- a/content/posts/2014-05-15-javafx-8-interview-jax-2014.md
+++ b/content/posts/2014-05-15-javafx-8-interview-jax-2014.md
@@ -10,5 +10,5 @@ preview_image: "/posts/preview-images/software-development-green.svg"
---
I was interviewed at [JAX Conference](http://jax.de/2014/) this week. The [interview](http://jaxenter.de/videos/JavaFX-8-wo-stehen-wir-wo-geht-hin-173516) is in German and I talk about the current state of JavaFX and if it's ready for the use in enterprise:
-{{< youtube 43wcPNo1U4Y >}}
+
diff --git a/content/posts/2014-05-19-datafx-8-0-tutorials.md b/content/posts/2014-05-19-datafx-8-0-tutorials.md
index 058ce35e..eda25549 100644
--- a/content/posts/2014-05-19-datafx-8-0-tutorials.md
+++ b/content/posts/2014-05-19-datafx-8-0-tutorials.md
@@ -16,10 +16,10 @@ I will introduce all DataFX tutorials first here in my blog. Later I will add th
The first tutorials are only. Here is a short list:
-* [How to set up a DataFX application]({{< ref "/posts/2015-01-28-set-datafx-application" >}})
-* [Tutorial 1]({{< ref "/posts/2014-05-20-datafx-tutorial-1" >}})
-* [Tutorial 2]({{< ref "/posts/2014-05-22-datafx-tutorial-2" >}})
-* [Tutorial 3]({{< ref "/posts/2014-05-31-datafx-tutorial-3" >}})
-* [Tutorial 4]({{< ref "/posts/2014-06-08-datafx-tutorial-4" >}})
-* [Tutorial 5]({{< ref "/posts/2014-06-27-datafx-tutorial-5" >}})
-* [Tutorial 6]({{< ref "/posts/2015-01-22-datafx-tutorial-6" >}})
+* [How to set up a DataFX application](/posts/2015-01-28-set-datafx-application)
+* [Tutorial 1](/posts/2014-05-20-datafx-tutorial-1)
+* [Tutorial 2](/posts/2014-05-22-datafx-tutorial-2)
+* [Tutorial 3](/posts/2014-05-31-datafx-tutorial-3)
+* [Tutorial 4](/posts/2014-06-08-datafx-tutorial-4)
+* [Tutorial 5](/posts/2014-06-27-datafx-tutorial-5)
+* [Tutorial 6](/posts/2015-01-22-datafx-tutorial-6)
diff --git a/content/posts/2014-05-20-datafx-tutorial-1.md b/content/posts/2014-05-20-datafx-tutorial-1.md
index dce12b5a..772d6424 100644
--- a/content/posts/2014-05-20-datafx-tutorial-1.md
+++ b/content/posts/2014-05-20-datafx-tutorial-1.md
@@ -1,151 +1,137 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX 8 Tutorial 1'
-date: "2014-05-20"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'In this post I want to show you the first simple tutorial for DataFX 8. In thetutorial we want to create a simple view with only one point of interaction.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-As mentioned [here]({{< ref "/posts/2014-05-19-datafx-8-0-tutorials" >}}) I started a series of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) tutorials. In this post I want to show you the first simple tutorial.
-
-In this tutorial we want to create a simple view with only one point of interaction. The source of the tutorial can be found [here](https://bitbucket.org/datafx/datafx/src/940c9c9556c6/datafx-tutorial1/?at=default). The following figure shows how the example will look like:
-
-
-
-Every time the button in the view is clicked the text in the top label should change. To create this application we will start with the layout of the view. To do so we need a [FXML](http://docs.oracle.com/javafx/2/fxml_get_started/jfxpub-fxml_get_started.htm) file that defines the JavaFX view of the application. This can easily be created with [Scene Builder](http://www.oracle.com/technetwork/java/javase/downloads/javafxscenebuilder-info-2157684.html). The FXML file ([simpleView.fxml](https://bitbucket.org/datafx/datafx/src/940c9c9556c662760a39830d05c9a4519eea3832/datafx-tutorial1/src/main/resources/org/datafx/tutorial/simpleView.fxml?at=default)) of the tutorial will look like this:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-Once this is created we need a controller class for the view. A first simple version that only uses JavaFX basic API will look like this:
-
-{{< highlight java >}}
-public class SimpleController {
- @FXML
- private Label resultLabel;
- @FXML
- private Button actionButton;
-}
-{{< / highlight >}}
-
-Like it is defined in the JavaFX basic API the two fields `resultLabel` and `actionButton` are named as the components defined in the FXML file by its `fx:id` attribute. BY adding the `@FXML` annotation to these fields they will be automatically injected once the controller will be instantiated.
-Until now only JavaFX basic APIs are used. Now we want to add some DataFX magic. As mentioned we need some interaction every time the button is pressed. Because of that we want to trigger an action by the button. DataFX provides two annotations to handle this approach: `@ActionTrigger` and `@ActionMethod`.
-
-The `@ActionTrigger` annotation can be added to a field of the controller that defines a Node in the view. The DataFX container will automatically add an action handler to the Node. Any method that should be called once an action is triggered must be annotated with the `@ActionMethod` annotation. For both Annotations you must specify a value that defines the unique action id of the action that is handled by the annotation. In this case I used the id `myAction` and added the annotations to the class:
-
-{{< highlight java >}}
-public class SimpleController {
- @FXML
- private Label resultLabel;
- @FXML
- @ActionTrigger("myAction")
- private Button actionButton;
- @ActionMethod("myAction")
- public void onAction() {
- // DO some action...
- }
-}
-{{< / highlight >}}
-
-So whenever the `actionButton` will be pressed the `onAction()` method will be called because they are bound by the same id. The id must be unique in view controller. As you will see in following tutorials there are other types of actions than simply calling a method. For now the most important point is that a component that is annotated with `@ActionTrigger` can trigger a method that is annotated with `@ActionMethod` if both annotations define the same unique action id.
-
-As a next step we will implement the action and define a default text for the label:
-
-{{< highlight java >}}
-public class SimpleController {
- @FXML
- private Label resultLabel;
- @FXML
- @ActionTrigger("myAction")
- private Button actionButton;
- private int clickCount = 0;
- @PostConstruct
- public void init() {
- resultLabel.setText("Button was clicked " + clickCount + " times");
- }
- @ActionMethod("myAction")
- public void onAction() {
- clickCount++;
- resultLabel.setText("Button was clicked " + clickCount + " times");
- }
-}
-{{< / highlight >}}
-
-As you can see in the code a new method called `init()` was added. This method should be called after the controller has been initialized and the fields that are annotated with `@FXML` are injected. In DataFX this can be done by adding the `@PostConstruct` Annotation to the method. By doing so the DataFX flow container will call this method once all injectable values of the controller instance are injected. There three different types of values / fields that can be injected:
-
-* UI components that are annotated by `@FXML`
-* DataFX objects. Here DataFX provides several annotations
-* Custom implementations. These will be injected by using the `@Inject` annotation
-
-The method that is annotated by `@PostContruct` will be called when all injections are finished. In this first example we will only use `@FXML` to inject FXML UI components to the controller.
-
-One thing that is still missing is the binding between the controller class and the FXML file. DataFX provides the `@FXMLController` annotation for this purpose. By using this annotation the controller class defines its FXML file that contains the layout of the view. After adding the annotation the final controller class will look like this:
-
-{{< highlight java >}}
-@FXMLController("simpleView.fxml")
-public class SimpleController {
- @FXML
- private Label resultLabel;
- @FXML
- @ActionTrigger("myAction")
- private Button actionButton;
- private int clickCount = 0;
- @PostConstruct
- public void init() {
- resultLabel.setText("Button was clicked " + clickCount + " times");
- }
- @ActionMethod("myAction")
- public void onAction() {
- clickCount++;
- resultLabel.setText("Button was clicked " + clickCount + " times");
- }
-}
-{{< / highlight >}}
-
-Once this is done we need a main class to start the application and show the view on screen. We can't use the basic FXMLLoader class here because we used some annotations that must be handled by the DataFX container. But since the last preview of DataFX 8.0 the Flow API provides a very simple way to show the view on screen. Here is the complete main class that will start the application:
-
-{{< highlight java >}}
-public class Tutorial1Main extends Application {
- public static void main(String[] args) {
- launch(args);
- }
- @Override
- public void start(Stage primaryStage) throws Exception {
- new Flow(SimpleController.class).startInStage(primaryStage);
- }
-}
-{{< / highlight >}}
-
- The shown way is the most simple way to start a flow: the controller class of the start view is always passed as parameter to the constructor of the `Flow` class. Because in this demo we have only one view we simply pass the `SimpleController` class to the flow. The `Flow` class provides a utility method called `startInStage()` that renders the Flow in a `Stage`. By doing so the `Scene` will be created automatically and the `Stage` will contain a `Scene` that only contains the defined flow. In this first tutorial the flow will only contain one view.
-
-This first example is quite easy and normally you could define the action binding by only one line of Java code in the `init()` method:
-
-{{< highlight java >}}
-actionButton.setOnAction((e) -> onAction());
-{{< / highlight >}}
-
-So why are all these annotations used here? As you will see in further tutorials that are more complex than this one it will make sense to use the annotations to provide more readable code.
-
-I hope you liked this first tutorial. I plan to add the second one at the end of the week.
+---
+outdated: true
+showInBlog: false
+title: 'DataFX 8 Tutorial 1'
+date: "2014-05-20"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'In this post I want to show you the first simple tutorial for DataFX 8. In thetutorial we want to create a simple view with only one point of interaction.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+As mentioned [here](/posts/2014-05-19-datafx-8-0-tutorials) I started a series of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) tutorials. In this post I want to show you the first simple tutorial.
+
+In this tutorial we want to create a simple view with only one point of interaction. The source of the tutorial can be found [here](https://bitbucket.org/datafx/datafx/src/940c9c9556c6/datafx-tutorial1/?at=default). The following figure shows how the example will look like:
+
+
+
+Every time the button in the view is clicked the text in the top label should change. To create this application we will start with the layout of the view. To do so we need a [FXML](http://docs.oracle.com/javafx/2/fxml_get_started/jfxpub-fxml_get_started.htm) file that defines the JavaFX view of the application. This can easily be created with [Scene Builder](http://www.oracle.com/technetwork/java/javase/downloads/javafxscenebuilder-info-2157684.html). The FXML file ([simpleView.fxml](https://bitbucket.org/datafx/datafx/src/940c9c9556c662760a39830d05c9a4519eea3832/datafx-tutorial1/src/main/resources/org/datafx/tutorial/simpleView.fxml?at=default)) of the tutorial will look like this:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+Once this is created we need a controller class for the view. A first simple version that only uses JavaFX basic API will look like this:
+
+```javapublic class SimpleController {
+ @FXML
+ private Label resultLabel;
+ @FXML
+ private Button actionButton;
+}
```
+
+Like it is defined in the JavaFX basic API the two fields `resultLabel` and `actionButton` are named as the components defined in the FXML file by its `fx:id` attribute. BY adding the `@FXML` annotation to these fields they will be automatically injected once the controller will be instantiated.
+Until now only JavaFX basic APIs are used. Now we want to add some DataFX magic. As mentioned we need some interaction every time the button is pressed. Because of that we want to trigger an action by the button. DataFX provides two annotations to handle this approach: `@ActionTrigger` and `@ActionMethod`.
+
+The `@ActionTrigger` annotation can be added to a field of the controller that defines a Node in the view. The DataFX container will automatically add an action handler to the Node. Any method that should be called once an action is triggered must be annotated with the `@ActionMethod` annotation. For both Annotations you must specify a value that defines the unique action id of the action that is handled by the annotation. In this case I used the id `myAction` and added the annotations to the class:
+
+```javapublic class SimpleController {
+ @FXML
+ private Label resultLabel;
+ @FXML
+ @ActionTrigger("myAction")
+ private Button actionButton;
+ @ActionMethod("myAction")
+ public void onAction() {
+ // DO some action...
+ }
+}
```
+
+So whenever the `actionButton` will be pressed the `onAction()` method will be called because they are bound by the same id. The id must be unique in view controller. As you will see in following tutorials there are other types of actions than simply calling a method. For now the most important point is that a component that is annotated with `@ActionTrigger` can trigger a method that is annotated with `@ActionMethod` if both annotations define the same unique action id.
+
+As a next step we will implement the action and define a default text for the label:
+
+```javapublic class SimpleController {
+ @FXML
+ private Label resultLabel;
+ @FXML
+ @ActionTrigger("myAction")
+ private Button actionButton;
+ private int clickCount = 0;
+ @PostConstruct
+ public void init() {
+ resultLabel.setText("Button was clicked " + clickCount + " times");
+ }
+ @ActionMethod("myAction")
+ public void onAction() {
+ clickCount++;
+ resultLabel.setText("Button was clicked " + clickCount + " times");
+ }
+}
```
+
+As you can see in the code a new method called `init()` was added. This method should be called after the controller has been initialized and the fields that are annotated with `@FXML` are injected. In DataFX this can be done by adding the `@PostConstruct` Annotation to the method. By doing so the DataFX flow container will call this method once all injectable values of the controller instance are injected. There three different types of values / fields that can be injected:
+
+* UI components that are annotated by `@FXML`
+* DataFX objects. Here DataFX provides several annotations
+* Custom implementations. These will be injected by using the `@Inject` annotation
+
+The method that is annotated by `@PostContruct` will be called when all injections are finished. In this first example we will only use `@FXML` to inject FXML UI components to the controller.
+
+One thing that is still missing is the binding between the controller class and the FXML file. DataFX provides the `@FXMLController` annotation for this purpose. By using this annotation the controller class defines its FXML file that contains the layout of the view. After adding the annotation the final controller class will look like this:
+
+```java@FXMLController("simpleView.fxml")
+public class SimpleController {
+ @FXML
+ private Label resultLabel;
+ @FXML
+ @ActionTrigger("myAction")
+ private Button actionButton;
+ private int clickCount = 0;
+ @PostConstruct
+ public void init() {
+ resultLabel.setText("Button was clicked " + clickCount + " times");
+ }
+ @ActionMethod("myAction")
+ public void onAction() {
+ clickCount++;
+ resultLabel.setText("Button was clicked " + clickCount + " times");
+ }
+}
```
+
+Once this is done we need a main class to start the application and show the view on screen. We can't use the basic FXMLLoader class here because we used some annotations that must be handled by the DataFX container. But since the last preview of DataFX 8.0 the Flow API provides a very simple way to show the view on screen. Here is the complete main class that will start the application:
+
+```javapublic class Tutorial1Main extends Application {
+ public static void main(String[] args) {
+ launch(args);
+ }
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ new Flow(SimpleController.class).startInStage(primaryStage);
+ }
+}
```
+
+ The shown way is the most simple way to start a flow: the controller class of the start view is always passed as parameter to the constructor of the `Flow` class. Because in this demo we have only one view we simply pass the `SimpleController` class to the flow. The `Flow` class provides a utility method called `startInStage()` that renders the Flow in a `Stage`. By doing so the `Scene` will be created automatically and the `Stage` will contain a `Scene` that only contains the defined flow. In this first tutorial the flow will only contain one view.
+
+This first example is quite easy and normally you could define the action binding by only one line of Java code in the `init()` method:
+
+```javaactionButton.setOnAction((e) -> onAction());
```
+
+So why are all these annotations used here? As you will see in further tutorials that are more complex than this one it will make sense to use the annotations to provide more readable code.
+
+I hope you liked this first tutorial. I plan to add the second one at the end of the week.
diff --git a/content/posts/2014-05-22-datafx-tutorial-2.md b/content/posts/2014-05-22-datafx-tutorial-2.md
index 682b7390..1c88353b 100644
--- a/content/posts/2014-05-22-datafx-tutorial-2.md
+++ b/content/posts/2014-05-22-datafx-tutorial-2.md
@@ -1,145 +1,131 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX 8 Tutorial 2'
-date: "2014-05-22"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'In this DataFX tutorial I will show how navigation between different views can easily be managed with DataFX and its Flow API.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-As I mentioned [here]({{< ref "/posts/2014-05-19-datafx-8-0-tutorials" >}}) I started a series of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) tutorials. The first tutorial can be found [here]({{< ref "/posts/2014-05-20-datafx-tutorial-1" >}}).
-
-In this second tutorial I will show you the basics about __navigation in a DataFX flow__. In this example we will define two different views that are part of a flow and then navigate from one view to the other one. The source of the tutorial can be found[here](https://bitbucket.org/datafx/datafx/src/a92bddc1904a905be89205d5edf3a39015149227/datafx-tutorial2/?at=default).
-
-The following pictures shows the two views of the tutorial and its interaction:
-
-
-
-As shown in the first tutorial we want to start by defining the views in __FXML__. Here is the __FXML__ file for the first view:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-This defines a view that looks like this:
-
-
-
-The second view differ only in a few points from the first one. Here is the FXML definition of the second view:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-As you can see in the code there is a style addition in the __VBox__ tag. Here the red background color of the view is defined by __CSS__. The rendered view will look like this:
-
-
-
-As a next step we create __view controllers__ for the views. As shown in the last tutorial you have to define a class for each view that acts as its controller. In a first step we create some empty controller classes that are only annotated by `@FXMLController`:
-
-{{< highlight java >}}
-@FXMLController("view1.fxml")
-public class View1Controller {
- @FXML
- private Button actionButton;
-}
-{{< / highlight >}}
-
-Only the button that is defined by the `fx:id` attribute in the FXML file is part of the first controller class. The second one will look similar:
-
-{{< highlight java >}}
-@FXMLController("view2.fxml")
-public class View2Controller {
- @FXML
- private Button actionButton;
-}
-{{< / highlight >}}
-
-Once this is done an application that is based on a flow can be created. As learned in tutorial 1 there is an easy way to create an application that only contains one flow. We will use it here, too. The main class of this example will look like this:
-
-{{< highlight java >}}
-public class Tutorial2Main extends Application {
- public static void main(String[] args) {
- launch(args);
- }
- @Override
- public void start(Stage primaryStage) throws Exception {
- new Flow(View1Controller.class).startInStage(primaryStage);
- }
-}
-{{< / highlight >}}
-
-By doing so a new flow is created that defines `view1` as its start view. If you start the application you will already see the first view but the button won't trigger any action. To add an action that links to the second view DataFX provides a special annotation called <`@LinkAction`. This annotation is working like the `@ActionTrigger` annotation that was introduced in tutorial 1. Once the button is clicked an action event will be fired and handled by the DataFX container. When using the `@LinkAction` annotation the controller of the target view must be specified. Therefore the Annotations provides a value that can be defined as the controller class. Here is the updated code of the first controller class:
-
-{{< highlight java >}}
-@FXMLController("view1.fxml")
-public class View1Controller {
- @FXML
- @LinkAction(View2Controller.class)
- private Button actionButton;
-}
-{{< / highlight >}}
-
-Whenever the button is pressed the flow will navigate to the second view that is defined by the `View2Controller` class. The `@LinkAction` can be added to any JavaFX Node. If the component extends the `ButtonBase` class or the `MenuItem` class a handler for action events will be added to the control. Otherwise the action will be called once the control is clicked by mouse. By using the annotation a developer doesn't need to handle the complete navigation like changing the view or create a new data model. DataFX will handle all these steps automatically and the defined view will appear on screen once the action is triggered.
-
-Maybe you can already imagine how the final code for the second view controller will look like ;)
-
-{{< highlight java >}}
-@FXMLController("view2.fxml")
-public class View2Controller {
- @FXML
- @LinkAction(View1Controller.class)
- private Button actionButton;
-}
-{{< / highlight >}}
-
-Once this is done you have created the first simply flow with DataFX. By using the `@LinkAction` annotation you can create big flows that contain a lot different views. In later tutorials you will that DataFX provides some other cool features to manage the navigation in a flow.
-
-As said in the first example each action in DataFX is defined by an unique ID. In the case of a LinkAction, the developer doesn't need to define an ID on its own. DataFX will create a unique ID once the controller will be initialized. By doing so the source code is much shorter and cleaner. As you will see later in the tutorials there are several other ways to define a navigation in a flow. Some of these work with an unique ID as shown in tutorial 1.
+---
+outdated: true
+showInBlog: false
+title: 'DataFX 8 Tutorial 2'
+date: "2014-05-22"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'In this DataFX tutorial I will show how navigation between different views can easily be managed with DataFX and its Flow API.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+As I mentioned [here](/posts/2014-05-19-datafx-8-0-tutorials) I started a series of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) tutorials. The first tutorial can be found [here](/posts/2014-05-20-datafx-tutorial-1).
+
+In this second tutorial I will show you the basics about __navigation in a DataFX flow__. In this example we will define two different views that are part of a flow and then navigate from one view to the other one. The source of the tutorial can be found[here](https://bitbucket.org/datafx/datafx/src/a92bddc1904a905be89205d5edf3a39015149227/datafx-tutorial2/?at=default).
+
+The following pictures shows the two views of the tutorial and its interaction:
+
+
+
+As shown in the first tutorial we want to start by defining the views in __FXML__. Here is the __FXML__ file for the first view:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+This defines a view that looks like this:
+
+
+
+The second view differ only in a few points from the first one. Here is the FXML definition of the second view:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+As you can see in the code there is a style addition in the __VBox__ tag. Here the red background color of the view is defined by __CSS__. The rendered view will look like this:
+
+
+
+As a next step we create __view controllers__ for the views. As shown in the last tutorial you have to define a class for each view that acts as its controller. In a first step we create some empty controller classes that are only annotated by `@FXMLController`:
+
+```java@FXMLController("view1.fxml")
+public class View1Controller {
+ @FXML
+ private Button actionButton;
+}
```
+
+Only the button that is defined by the `fx:id` attribute in the FXML file is part of the first controller class. The second one will look similar:
+
+```java@FXMLController("view2.fxml")
+public class View2Controller {
+ @FXML
+ private Button actionButton;
+}
```
+
+Once this is done an application that is based on a flow can be created. As learned in tutorial 1 there is an easy way to create an application that only contains one flow. We will use it here, too. The main class of this example will look like this:
+
+```javapublic class Tutorial2Main extends Application {
+ public static void main(String[] args) {
+ launch(args);
+ }
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ new Flow(View1Controller.class).startInStage(primaryStage);
+ }
+}
```
+
+By doing so a new flow is created that defines `view1` as its start view. If you start the application you will already see the first view but the button won't trigger any action. To add an action that links to the second view DataFX provides a special annotation called <`@LinkAction`. This annotation is working like the `@ActionTrigger` annotation that was introduced in tutorial 1. Once the button is clicked an action event will be fired and handled by the DataFX container. When using the `@LinkAction` annotation the controller of the target view must be specified. Therefore the Annotations provides a value that can be defined as the controller class. Here is the updated code of the first controller class:
+
+```java@FXMLController("view1.fxml")
+public class View1Controller {
+ @FXML
+ @LinkAction(View2Controller.class)
+ private Button actionButton;
+}
```
+
+Whenever the button is pressed the flow will navigate to the second view that is defined by the `View2Controller` class. The `@LinkAction` can be added to any JavaFX Node. If the component extends the `ButtonBase` class or the `MenuItem` class a handler for action events will be added to the control. Otherwise the action will be called once the control is clicked by mouse. By using the annotation a developer doesn't need to handle the complete navigation like changing the view or create a new data model. DataFX will handle all these steps automatically and the defined view will appear on screen once the action is triggered.
+
+Maybe you can already imagine how the final code for the second view controller will look like ;)
+
+```java@FXMLController("view2.fxml")
+public class View2Controller {
+ @FXML
+ @LinkAction(View1Controller.class)
+ private Button actionButton;
+}
```
+
+Once this is done you have created the first simply flow with DataFX. By using the `@LinkAction` annotation you can create big flows that contain a lot different views. In later tutorials you will that DataFX provides some other cool features to manage the navigation in a flow.
+
+As said in the first example each action in DataFX is defined by an unique ID. In the case of a LinkAction, the developer doesn't need to define an ID on its own. DataFX will create a unique ID once the controller will be initialized. By doing so the source code is much shorter and cleaner. As you will see later in the tutorials there are several other ways to define a navigation in a flow. Some of these work with an unique ID as shown in tutorial 1.
diff --git a/content/posts/2014-05-31-datafx-tutorial-3.md b/content/posts/2014-05-31-datafx-tutorial-3.md
index 4a688316..7732dc37 100644
--- a/content/posts/2014-05-31-datafx-tutorial-3.md
+++ b/content/posts/2014-05-31-datafx-tutorial-3.md
@@ -1,173 +1,157 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX Tutorial 3'
-date: "2014-05-31"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'In this tutorial I want to show how a wizard dialog can be created with DataFX.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this tutorial I want to show how a wizard dialog can be created with [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}). This example depends on 2 other tutorials that can be found [here]({{< ref "/posts/2014-05-20-datafx-tutorial-1" >}}) and [here]({{< ref "/posts/2014-05-22-datafx-tutorial-2" >}}).
-
-The wizard that will be created in this tutorial contains 5 different views that are linked to each other:
-
-
-
-Next to the "next" action that navigates to the following view the wizard should support a "back" action that navigates to the last displayed view and a "finish" action that directly navigates to the last view:
-
-
-
-__Note:__ The last diagram doesn't contain all possible links. Because the "back" action navigates always the last visible view you could navigate directly from the last view to the first view if the "finish" action was triggered in the first view and then the back action is triggered.
-
-As shown in the other tutorials we will start the the view layout and generate all views by using __FXML__ and Scene Builder. All the views of the wizard will contain a toolbar with some buttons to trigger the defined action. Here are some previews how the views will look like:
-
-
-
-Thanks to FXML we don't need to implement the toolbar for every view. For this purpose FXML provides the `fx:include` tag that can be used to interleave vxml defined views. So we can define the toolbar as a separate FXML file:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-As you can see the buttons for the 3 defined actions ("back", "next" and "finish") are defined in the toolbar. As described in the earlier tutorials these components can be injected in the controller class instances by using the `@FXML` annotation and a field name that matches the value of the `fx:id` attribute.
-
-The FXML of the toolbar (actionBar.fxml) can now included in all the FXML files that defines the different views of the wizard. Here is the code of the first view as an example:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-As you can see the toolbar is integrated in the bottom of the central `BorderPane`.
-Once all FXML files are created we can start to create the view controller as described in the earlier tutorials. Therefore we create a Java class for each view and bind the class to the corresponding FXML file by using the `@FXMLController` annotation:
-
-{{< highlight java >}}
-@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
-public class Wizard1Controller {
-}
-{{< / highlight >}}
-
-When looking at the `@FXMLController` annotation of the class you can find a new feature. Next to the fxml file that defines the view of the wizard step a `title` attribute is added. This defines the title of the view. Because the wizard will be added to a `Stage` by using the `Flow.startInStage()` method (see [tutorial 1]({{< ref "/posts/2014-05-20-datafx-tutorial-1" >}})) the title of the flow is automatically bound to the window title of the `Stage`. So whenever the view in the flow changes the title of the application window will change to the defined title of the view. As you will learn in future tutorial you can easily change the title of a view in code. In addition to the title other metadata like a icon can be defined for a view or flow.
-As a next step the buttons of the toolbar should be injected in the controller classes and the specific actions for them should be defined. Here a new annotation will be introduced: By using the `@BackAction` annotation the flow will automatically handle an action that navigates to the last visible view. The annotation can be used like the `@ActionTrigger` and `@LinkAction` annotations that were introduced in tutorial 1 and 2. Therefore the controller class for the a view in the wizard could be defined like this:
-
-{{< highlight java >}}
-@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
-public class Wizard1Controller {
- @FXML
- @LinkAction(Wizard2Controller.class)
- private Button nextButton;
- @FXML
- @BackAction
- private Button backButton;
- @FXML
- @LinkAction(WizardDoneController.class)
- private Button finishButton;
-}
-{{< / highlight >}}
-
-When all controllers would be designed like this we would create some duplicate code. The definition of the back button and the finish button would look the same in each controller class. Therefore we will create an abstract class that contains these definitions and all other view controllers will depend on it:
-
-{{< highlight java >}}
-public class AbstractWizardController {
- @FXML
- @BackAction
- private Button backButton;
- @FXML
- @LinkAction(WizardDoneController.class)
- private Button finishButton;
- public Button getBackButton() {
- return backButton;
- }
- public Button getFinishButton() {
- return finishButton;
- }
-}
-{{< / highlight >}}
-
-Now a controller for the wizard will look like this:
-
-{{< highlight java >}}
-@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
-public class Wizard1Controller extends AbstractWizardController {
- @FXML
- @LinkAction(Wizard2Controller.class)
- private Button nextButton;
-}
-{{< / highlight >}}
-
-Note: The injection of private nodes in super classes is a feature of DataFX. So if you will try this by using the default `FXMLLoader` of JavaFX this won't work. In addition the `FXMLLoader` doesn't support the injection of FXML nodes that are defined in a sub-fxml that is included by using the `fx:include` tag. As a limitation this nodes must not have a CSS id defined because this will override the `fx:id` in the java object and in that case DataFX can't inject them. I plan to open a issue at OpenJFX for this.
-As a last step we need to disable the "back" button on the first view and the "next" and "finish" buttons on the last view. This can be done in the view controller by defining a method with the `@PostConstruct` annotation that will be called once the controller instance is created:
-
-{{< highlight java >}}
-@FXMLController(value="wizardDone.fxml", title = "Wizard: Finish")
-public class WizardDoneController extends AbstractWizardController {
- @FXML
- private Button nextButton;
- @PostConstruct
- public void init() {
- nextButton.setDisable(true);
- getFinishButton().setDisable(true);
- }
-}
-{{< / highlight >}}
-
-Once this is done the wizard is completed an can be displayed in a JavaFX application. Therefore we define the following main class:
-
-{{< highlight java >}}
-public class Tutorial3Main extends Application {
- public static void main(String[] args) {
- launch(args);
- }
- @Override
- public void start(Stage primaryStage) throws Exception {
- new Flow(WizardStartController.class).startInStage(primaryStage);
- }
-}
-{{< / highlight >}}
-
-The complete source of this tutorial can be found [here](https://bitbucket.org/datafx/datafx/src/b25aa30116e80c83d02a4b2a46c76fd603c0c7f4/datafx-tutorial3).
-
-Here is an movie of the finished wizard application:
-
-{{< youtube zGjc4VfcM9A >}}
-
+---
+outdated: true
+showInBlog: false
+title: 'DataFX Tutorial 3'
+date: "2014-05-31"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'In this tutorial I want to show how a wizard dialog can be created with DataFX.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this tutorial I want to show how a wizard dialog can be created with [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}). This example depends on 2 other tutorials that can be found [here](/posts/2014-05-20-datafx-tutorial-1) and [here](/posts/2014-05-22-datafx-tutorial-2).
+
+The wizard that will be created in this tutorial contains 5 different views that are linked to each other:
+
+
+
+Next to the "next" action that navigates to the following view the wizard should support a "back" action that navigates to the last displayed view and a "finish" action that directly navigates to the last view:
+
+
+
+__Note:__ The last diagram doesn't contain all possible links. Because the "back" action navigates always the last visible view you could navigate directly from the last view to the first view if the "finish" action was triggered in the first view and then the back action is triggered.
+
+As shown in the other tutorials we will start the the view layout and generate all views by using __FXML__ and Scene Builder. All the views of the wizard will contain a toolbar with some buttons to trigger the defined action. Here are some previews how the views will look like:
+
+
+
+Thanks to FXML we don't need to implement the toolbar for every view. For this purpose FXML provides the `fx:include` tag that can be used to interleave vxml defined views. So we can define the toolbar as a separate FXML file:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+As you can see the buttons for the 3 defined actions ("back", "next" and "finish") are defined in the toolbar. As described in the earlier tutorials these components can be injected in the controller class instances by using the `@FXML` annotation and a field name that matches the value of the `fx:id` attribute.
+
+The FXML of the toolbar (actionBar.fxml) can now included in all the FXML files that defines the different views of the wizard. Here is the code of the first view as an example:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+As you can see the toolbar is integrated in the bottom of the central `BorderPane`.
+Once all FXML files are created we can start to create the view controller as described in the earlier tutorials. Therefore we create a Java class for each view and bind the class to the corresponding FXML file by using the `@FXMLController` annotation:
+
+```java@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
+public class Wizard1Controller {
+}
```
+
+When looking at the `@FXMLController` annotation of the class you can find a new feature. Next to the fxml file that defines the view of the wizard step a `title` attribute is added. This defines the title of the view. Because the wizard will be added to a `Stage` by using the `Flow.startInStage()` method (see [tutorial 1](/posts/2014-05-20-datafx-tutorial-1)) the title of the flow is automatically bound to the window title of the `Stage`. So whenever the view in the flow changes the title of the application window will change to the defined title of the view. As you will learn in future tutorial you can easily change the title of a view in code. In addition to the title other metadata like a icon can be defined for a view or flow.
+As a next step the buttons of the toolbar should be injected in the controller classes and the specific actions for them should be defined. Here a new annotation will be introduced: By using the `@BackAction` annotation the flow will automatically handle an action that navigates to the last visible view. The annotation can be used like the `@ActionTrigger` and `@LinkAction` annotations that were introduced in tutorial 1 and 2. Therefore the controller class for the a view in the wizard could be defined like this:
+
+```java@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
+public class Wizard1Controller {
+ @FXML
+ @LinkAction(Wizard2Controller.class)
+ private Button nextButton;
+ @FXML
+ @BackAction
+ private Button backButton;
+ @FXML
+ @LinkAction(WizardDoneController.class)
+ private Button finishButton;
+}
```
+
+When all controllers would be designed like this we would create some duplicate code. The definition of the back button and the finish button would look the same in each controller class. Therefore we will create an abstract class that contains these definitions and all other view controllers will depend on it:
+
+```javapublic class AbstractWizardController {
+ @FXML
+ @BackAction
+ private Button backButton;
+ @FXML
+ @LinkAction(WizardDoneController.class)
+ private Button finishButton;
+ public Button getBackButton() {
+ return backButton;
+ }
+ public Button getFinishButton() {
+ return finishButton;
+ }
+}
```
+
+Now a controller for the wizard will look like this:
+
+```java@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
+public class Wizard1Controller extends AbstractWizardController {
+ @FXML
+ @LinkAction(Wizard2Controller.class)
+ private Button nextButton;
+}
```
+
+Note: The injection of private nodes in super classes is a feature of DataFX. So if you will try this by using the default `FXMLLoader` of JavaFX this won't work. In addition the `FXMLLoader` doesn't support the injection of FXML nodes that are defined in a sub-fxml that is included by using the `fx:include` tag. As a limitation this nodes must not have a CSS id defined because this will override the `fx:id` in the java object and in that case DataFX can't inject them. I plan to open a issue at OpenJFX for this.
+As a last step we need to disable the "back" button on the first view and the "next" and "finish" buttons on the last view. This can be done in the view controller by defining a method with the `@PostConstruct` annotation that will be called once the controller instance is created:
+
+```java@FXMLController(value="wizardDone.fxml", title = "Wizard: Finish")
+public class WizardDoneController extends AbstractWizardController {
+ @FXML
+ private Button nextButton;
+ @PostConstruct
+ public void init() {
+ nextButton.setDisable(true);
+ getFinishButton().setDisable(true);
+ }
+}
```
+
+Once this is done the wizard is completed an can be displayed in a JavaFX application. Therefore we define the following main class:
+
+```javapublic class Tutorial3Main extends Application {
+ public static void main(String[] args) {
+ launch(args);
+ }
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ new Flow(WizardStartController.class).startInStage(primaryStage);
+ }
+}
```
+
+The complete source of this tutorial can be found [here](https://bitbucket.org/datafx/datafx/src/b25aa30116e80c83d02a4b2a46c76fd603c0c7f4/datafx-tutorial3).
+
+Here is an movie of the finished wizard application:
+
+
+
diff --git a/content/posts/2014-06-08-datafx-tutorial-4.md b/content/posts/2014-06-08-datafx-tutorial-4.md
index 849a3b23..65e7610b 100644
--- a/content/posts/2014-06-08-datafx-tutorial-4.md
+++ b/content/posts/2014-06-08-datafx-tutorial-4.md
@@ -1,214 +1,192 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX Tutorial 4'
-date: "2014-06-08"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'This is the 4th tutorial about DataFX. In this tutorial I will show how you can manage central actions and navigation of a flow.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-This is the 4th tutorial about navigation with [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) and the DataFX flow API. An overview of all tutorials can be found [here]({{< ref "/posts/2014-05-19-datafx-8-0-tutorials" >}}). In this tutorial I will show how you can manage the action handling and navigation of a flow from outside of the flow. To do so we will refactor the wizard that was created in [tutorial 3]({{< ref "/posts/2014-05-31-datafx-tutorial-3" >}}).
-
-As described in tutorial 3 the wizard will be composed of some views that define the steps of the wizard. In addition a toolbar with some buttons is placed on the bottom. The views will look like this:
-
-
-
-All views of the wizard are linked by a navigation model. In tutorial 3 this was created by directly in the view controller classes so each view defines its navigation and actions. In this tutorial we will use the second approach that DataFX provides: All views doesn't know anything about there action and navigation model. Instead of this the actions are defined extern. The navigation and action behavior will be the same as in tutorial 3. Here is a short overview about the links between the views of the wizard:
-
-
-
-As always we want to start by defining the views in FXML. Because the toolbar will look the same on each view we can extract it in a seperate FXML file. As shown in tutorial 3 a FXML file can included in another one by using the `fx:include` tag. Here is the FXML definition of the toolbar:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-The definition of the toolbar is the same as in the last tutorial. The definition of the wizard steps is the same, too. Here is a FXML definition of one step:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-As a next step we need view controller classes for all views in the wizard. As a first step we will create empty classes that are annoted with the `FXMLController` annotation:
-
-{{< highlight java >}}
-@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
-public class Wizard1Controller {
-}
-{{< / highlight >}}
-
-All the actions of the wizard will be triggered by the toolbar. Because the toolbar is defined on each view we can create an abstract class for the toolbar components that can be used as a superclass for the view controller classes:
-
-{{< highlight java >}}
-public class AbstractWizardController {
- @FXML
- @ActionTrigger("back")
- private Button backButton;
- @FXML
- @ActionTrigger("finish")
- private Button finishButton;
- @FXML
- @ActionTrigger("next")
- private Button nextButton;
- public Button getBackButton() {
- return backButton;
- }
- public Button getFinishButton() {
- return finishButton;
- }
- public Button getNextButton() {
- return nextButton;
- }
-}
-{{< / highlight >}}
-
-All view controller classes can now extend the class:
-
-{{< highlight java >}}
-@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
-public class Wizard1Controller extends AbstractWizardController {
-}
-{{< / highlight >}}
-
-Mainly the same structure was created in tutorial 3 but here we have one big different. In Chapter 3 the next button can't be defined in the super class because it was annotated with the `@LinkAction` annotation. This must be done in each controller class because the target of the navigation must be defined as an parameter of the annotation definition (see tutorial 3 for a more detailed description). As already mentioned we want to extract the action handling in this tutorial. So all buttons can be defined and injected in the `AbstractWizardController` class. As you can see in the code the buttons are annoted by the `@ActionTrigger` annotation that was already used in some other tutorials. By using this annotation an action id is defined and the flow will trigger the action that is specified by this id each time the button will be pressed.
-
-The last thing that is missing is the main class. This class will look different to the main classes of the first three tutorials. Here we want to define all the actions of the wizard and link its views. To do so we start with a simple class and show the flow. You should know this kind of class from the other tutorials:
-
-{{< highlight java >}}
-public class Tutorial4Main extends Application {
- public static void main(String[] args) {
- launch(args);
- }
- @Override
- public void start(Stage primaryStage) throws Exception {
- new Flow(WizardStartController.class).startInStage(primaryStage);
- }
-}
-{{< / highlight >}}
-
-As a next step we want to bind all the different views and create a navigation model. To do so the `Flow` class contains some methods that can be used to define links between views of the flow. The `Flow` class is defined as a fluent API and navigation links or action can be simply added to it. Here is a example for a flow with one link:
-
-{{< highlight java >}}
-new Flow(View1Controller.class).
-withLink(View1Controller.class, "link-id", View2Controller.class).
-startInStage(primaryStage);
-{{< / highlight >}}
-
-In the flow a link from view 1 to view 2 is defined. Both views are specified by their controller classes (View1Controller.class and View2Controller.class) and the link is defined by the unique id "link-id". Once this is done you can simply add the `@ActionTrigger("link-id")` annotation to a defined node in the `View1Controller` class. DataFX will register the navigation to view 2 for this node. So whenever the node is clicked the navigation will be transformed.
-
-For the current example the code of the main class will look like this:
-
-{{< highlight java >}}
-public class Tutorial4Main extends Application {
- public static void main(String[] args) {
- launch(args);
- }
- @Override
- public void start(Stage primaryStage) throws Exception {
- new Flow(WizardStartController.class).
- withLink(WizardStartController.class, "next", Wizard1Controller.class).
- withLink(Wizard1Controller.class, "next", Wizard2Controller.class).
- withLink(Wizard2Controller.class, "next", Wizard3Controller.class).
- withLink(Wizard3Controller.class, "next", WizardDoneController.class).
- withGlobalBackAction("back").
- withGlobalLink("finish", WizardDoneController.class).
- startInStage(primaryStage);
- }
-}
-{{< / highlight >}}
-
-Next to the `withLink(...)` method two additional methods of the `Flow` class are used in the code. The withGlobalLink(...) method defines a navigation action that will be registered for each view in the flow. So the `@ActionTrigger("finish")` annotation can be used in each view and will navigate to the last view of the wizard. For each action type that can be registered to a DataFX flow the `Flow` class provides methods to register the action for only one view or as a global action for all views. This is done for the back action, too. The "back" button is visible on each view of the wizard and therefore the `withGlobalBackAction("back")` method is used here. So whenever a action with the id "back" is triggered in any view of the flow a back action will be called. This is exactly the same as adding a @BackAction annotation to the node that should trigger the back action.
-
-All these methods add a action to the DataFX flow. A action is defined by the interface org.datafx.controller.flow.action.FlowAction and all the shown methods will internally call the `Flow.addActionToView(Class> controllerClass, String actionId, FlowAction action)` method that will add a action instance for the defined id to a specific view. Methods that add global actions will call `Flow.addGlobalAction(String actionId, FlowAction action)` internally. As you can see even custom actions can be added to a flow by simply implementing the `FlowAction` interface. DataFX contains a set with all the most important actions types that can be added to a flow or a specific view. The following figure shows the inheritance of the `FlowAction` interface:
-
-
-
-Some of the actions in the diagram will be handled in future tutorials. First I will only explain the basic action types:
-
-* `FlowLink` defines a link to another view in the flow. In the example instances of this class will be registered to the flow whenever the `withLink(...)` method is called.
-* `FlowBackAction` handles a back navigation in the flow. This is the same as using the `@BackAction` annotation in a view controller
-* `FlowTaskAction` will execute a task that is defined as a `Runnable` on the Platform Application Thread. We will see an example of the action type after this overview.
-* `FlowAsyncTaskAction` will execute a task that is defined as a `Runnable` on a background thread.
-* `FlowMethodAction` will call a method in the given view. The same result can be created by using the `@ActionMethod` annotation as shown in the first tutorial.
-
-As you can see in this overview all the actions that were created by using annotations in the previous tutorials can be defined directly for the flow. By doing so a controller class doesn't need to now how an action is implemented. It must only now the specific id of the action and which node should trigger the action. This structure can be very helpful if default views should be used in multiple flows or if controller classes and / or action classes are part of different modules that don't depend on each other. Let's think about the following structure:
-
-
-
-In this example the ViewController1.class, ViewController2.class and CustomAction.class don't know each other. With the help of the DataFX flow API you can simply combine them by using:
-
-{{< highlight java >}}
-new Flow(View1Controller.class).
-withLink(View1Controller.class, "link-id", View2Controller.class).
-withAction(View2Controller.class "callAction", new CustomAction()).
-startInStage(primaryStage);
-{{< / highlight >}}
-
-As a last step I want to extent the example application and add a help output. This should be a global action that prints some help on the console. To do so the action is registered for the flow:
-
-{{< highlight java >}}
-new Flow(WizardStartController.class).
-withLink(WizardStartController.class, "next", Wizard1Controller.class).
-...
-withGlobalTaskAction("help", () -> System.out.println("## There is no help for the application :( ##")).
-startInStage(primaryStage);
-{{< / highlight >}}
-
-As you can see in the code you can simply pass a lambda expression as a action to the flow because the `FlowTaskAction` class that is used internally here defines the action as a `Runnable` that is a function interface since Java8.
-Once this is done the action can be triggered in any view:
-
-{{< highlight java >}}
-@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
-public class Wizard1Controller extends AbstractWizardController {
- @FXML
- @ActionTrigger("help")
- private Hyperlink helpLink;
-}
-{{< / highlight >}}
-
-When looking at the [source code of the tutorial](https://bitbucket.org/datafx/datafx/src/7c6009a86ac83709855bd75e9f795b68747756f4/datafx-tutorial4/?at=default) you will see that the "help" action isn't triggered in all views. That is no problem for DataFX. A global action mustn't be called in each view and even a normal action mustn't be called in the defined controller. The API only defines that there is an action with the given id that could be called. For this last step a hyperlink tag is added to the FXML files. Here is a screenshot of the final wizard:
-
-
+---
+outdated: true
+showInBlog: false
+title: 'DataFX Tutorial 4'
+date: "2014-06-08"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'This is the 4th tutorial about DataFX. In this tutorial I will show how you can manage central actions and navigation of a flow.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+This is the 4th tutorial about navigation with [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}) and the DataFX flow API. An overview of all tutorials can be found [here](/posts/2014-05-19-datafx-8-0-tutorials). In this tutorial I will show how you can manage the action handling and navigation of a flow from outside of the flow. To do so we will refactor the wizard that was created in [tutorial 3](/posts/2014-05-31-datafx-tutorial-3).
+
+As described in tutorial 3 the wizard will be composed of some views that define the steps of the wizard. In addition a toolbar with some buttons is placed on the bottom. The views will look like this:
+
+
+
+All views of the wizard are linked by a navigation model. In tutorial 3 this was created by directly in the view controller classes so each view defines its navigation and actions. In this tutorial we will use the second approach that DataFX provides: All views doesn't know anything about there action and navigation model. Instead of this the actions are defined extern. The navigation and action behavior will be the same as in tutorial 3. Here is a short overview about the links between the views of the wizard:
+
+
+
+As always we want to start by defining the views in FXML. Because the toolbar will look the same on each view we can extract it in a seperate FXML file. As shown in tutorial 3 a FXML file can included in another one by using the `fx:include` tag. Here is the FXML definition of the toolbar:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+The definition of the toolbar is the same as in the last tutorial. The definition of the wizard steps is the same, too. Here is a FXML definition of one step:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+As a next step we need view controller classes for all views in the wizard. As a first step we will create empty classes that are annoted with the `FXMLController` annotation:
+
+```java@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
+public class Wizard1Controller {
+}
```
+
+All the actions of the wizard will be triggered by the toolbar. Because the toolbar is defined on each view we can create an abstract class for the toolbar components that can be used as a superclass for the view controller classes:
+
+```javapublic class AbstractWizardController {
+ @FXML
+ @ActionTrigger("back")
+ private Button backButton;
+ @FXML
+ @ActionTrigger("finish")
+ private Button finishButton;
+ @FXML
+ @ActionTrigger("next")
+ private Button nextButton;
+ public Button getBackButton() {
+ return backButton;
+ }
+ public Button getFinishButton() {
+ return finishButton;
+ }
+ public Button getNextButton() {
+ return nextButton;
+ }
+}
```
+
+All view controller classes can now extend the class:
+
+```java@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
+public class Wizard1Controller extends AbstractWizardController {
+}
```
+
+Mainly the same structure was created in tutorial 3 but here we have one big different. In Chapter 3 the next button can't be defined in the super class because it was annotated with the `@LinkAction` annotation. This must be done in each controller class because the target of the navigation must be defined as an parameter of the annotation definition (see tutorial 3 for a more detailed description). As already mentioned we want to extract the action handling in this tutorial. So all buttons can be defined and injected in the `AbstractWizardController` class. As you can see in the code the buttons are annoted by the `@ActionTrigger` annotation that was already used in some other tutorials. By using this annotation an action id is defined and the flow will trigger the action that is specified by this id each time the button will be pressed.
+
+The last thing that is missing is the main class. This class will look different to the main classes of the first three tutorials. Here we want to define all the actions of the wizard and link its views. To do so we start with a simple class and show the flow. You should know this kind of class from the other tutorials:
+
+```javapublic class Tutorial4Main extends Application {
+ public static void main(String[] args) {
+ launch(args);
+ }
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ new Flow(WizardStartController.class).startInStage(primaryStage);
+ }
+}
```
+
+As a next step we want to bind all the different views and create a navigation model. To do so the `Flow` class contains some methods that can be used to define links between views of the flow. The `Flow` class is defined as a fluent API and navigation links or action can be simply added to it. Here is a example for a flow with one link:
+
+```javanew Flow(View1Controller.class).
+withLink(View1Controller.class, "link-id", View2Controller.class).
+startInStage(primaryStage);
```
+
+In the flow a link from view 1 to view 2 is defined. Both views are specified by their controller classes (View1Controller.class and View2Controller.class) and the link is defined by the unique id "link-id". Once this is done you can simply add the `@ActionTrigger("link-id")` annotation to a defined node in the `View1Controller` class. DataFX will register the navigation to view 2 for this node. So whenever the node is clicked the navigation will be transformed.
+
+For the current example the code of the main class will look like this:
+
+```javapublic class Tutorial4Main extends Application {
+ public static void main(String[] args) {
+ launch(args);
+ }
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ new Flow(WizardStartController.class).
+ withLink(WizardStartController.class, "next", Wizard1Controller.class).
+ withLink(Wizard1Controller.class, "next", Wizard2Controller.class).
+ withLink(Wizard2Controller.class, "next", Wizard3Controller.class).
+ withLink(Wizard3Controller.class, "next", WizardDoneController.class).
+ withGlobalBackAction("back").
+ withGlobalLink("finish", WizardDoneController.class).
+ startInStage(primaryStage);
+ }
+}
```
+
+Next to the `withLink(...)` method two additional methods of the `Flow` class are used in the code. The withGlobalLink(...) method defines a navigation action that will be registered for each view in the flow. So the `@ActionTrigger("finish")` annotation can be used in each view and will navigate to the last view of the wizard. For each action type that can be registered to a DataFX flow the `Flow` class provides methods to register the action for only one view or as a global action for all views. This is done for the back action, too. The "back" button is visible on each view of the wizard and therefore the `withGlobalBackAction("back")` method is used here. So whenever a action with the id "back" is triggered in any view of the flow a back action will be called. This is exactly the same as adding a @BackAction annotation to the node that should trigger the back action.
+
+All these methods add a action to the DataFX flow. A action is defined by the interface org.datafx.controller.flow.action.FlowAction and all the shown methods will internally call the `Flow.addActionToView(Class> controllerClass, String actionId, FlowAction action)` method that will add a action instance for the defined id to a specific view. Methods that add global actions will call `Flow.addGlobalAction(String actionId, FlowAction action)` internally. As you can see even custom actions can be added to a flow by simply implementing the `FlowAction` interface. DataFX contains a set with all the most important actions types that can be added to a flow or a specific view. The following figure shows the inheritance of the `FlowAction` interface:
+
+
+
+Some of the actions in the diagram will be handled in future tutorials. First I will only explain the basic action types:
+
+* `FlowLink` defines a link to another view in the flow. In the example instances of this class will be registered to the flow whenever the `withLink(...)` method is called.
+* `FlowBackAction` handles a back navigation in the flow. This is the same as using the `@BackAction` annotation in a view controller
+* `FlowTaskAction` will execute a task that is defined as a `Runnable` on the Platform Application Thread. We will see an example of the action type after this overview.
+* `FlowAsyncTaskAction` will execute a task that is defined as a `Runnable` on a background thread.
+* `FlowMethodAction` will call a method in the given view. The same result can be created by using the `@ActionMethod` annotation as shown in the first tutorial.
+
+As you can see in this overview all the actions that were created by using annotations in the previous tutorials can be defined directly for the flow. By doing so a controller class doesn't need to now how an action is implemented. It must only now the specific id of the action and which node should trigger the action. This structure can be very helpful if default views should be used in multiple flows or if controller classes and / or action classes are part of different modules that don't depend on each other. Let's think about the following structure:
+
+
+
+In this example the ViewController1.class, ViewController2.class and CustomAction.class don't know each other. With the help of the DataFX flow API you can simply combine them by using:
+
+```javanew Flow(View1Controller.class).
+withLink(View1Controller.class, "link-id", View2Controller.class).
+withAction(View2Controller.class "callAction", new CustomAction()).
+startInStage(primaryStage);
```
+
+As a last step I want to extent the example application and add a help output. This should be a global action that prints some help on the console. To do so the action is registered for the flow:
+
+```javanew Flow(WizardStartController.class).
+withLink(WizardStartController.class, "next", Wizard1Controller.class).
+...
+withGlobalTaskAction("help", () -> System.out.println("## There is no help for the application :( ##")).
+startInStage(primaryStage);
```
+
+As you can see in the code you can simply pass a lambda expression as a action to the flow because the `FlowTaskAction` class that is used internally here defines the action as a `Runnable` that is a function interface since Java8.
+Once this is done the action can be triggered in any view:
+
+```java@FXMLController(value="wizard1.fxml", title = "Wizard: Step 1")
+public class Wizard1Controller extends AbstractWizardController {
+ @FXML
+ @ActionTrigger("help")
+ private Hyperlink helpLink;
+}
```
+
+When looking at the [source code of the tutorial](https://bitbucket.org/datafx/datafx/src/7c6009a86ac83709855bd75e9f795b68747756f4/datafx-tutorial4/?at=default) you will see that the "help" action isn't triggered in all views. That is no problem for DataFX. A global action mustn't be called in each view and even a normal action mustn't be called in the defined controller. The API only defines that there is an action with the given id that could be called. For this last step a hyperlink tag is added to the FXML files. Here is a screenshot of the final wizard:
+
+
diff --git a/content/posts/2014-06-17-aerofx-getting-closer.md b/content/posts/2014-06-17-aerofx-getting-closer.md
index cc227167..55bdbd16 100644
--- a/content/posts/2014-06-17-aerofx-getting-closer.md
+++ b/content/posts/2014-06-17-aerofx-getting-closer.md
@@ -8,7 +8,7 @@ categories: [AeroFX, JavaFX]
excerpt: 'This is a new preview of the AeroFX Theme for JavaFX. The theme creates a native look and feel for JavaFX applications on Windows.'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-As shown in [the sneak peek last week]({{< ref "/posts/2014-06-10-sneak-peek-aerofx" >}}) a new JavaFX theme is in development. [Matthias Meidinger](http://sigpwr.de) is creating this skin as part of his bachelor thesis and since the last week he made some big improvements. So I think it's time for a new preview of the upcoming JavaFX theme. The following pics show dialogs that use the __AeroFX__ skin:
+As shown in [the sneak peek last week](/posts/2014-06-10-sneak-peek-aerofx) a new JavaFX theme is in development. [Matthias Meidinger](http://sigpwr.de) is creating this skin as part of his bachelor thesis and since the last week he made some big improvements. So I think it's time for a new preview of the upcoming JavaFX theme. The following pics show dialogs that use the __AeroFX__ skin:

diff --git a/content/posts/2014-06-27-datafx-tutorial-5.md b/content/posts/2014-06-27-datafx-tutorial-5.md
index dc010a6f..eb29faa3 100644
--- a/content/posts/2014-06-27-datafx-tutorial-5.md
+++ b/content/posts/2014-06-27-datafx-tutorial-5.md
@@ -1,276 +1,256 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX Tutorial 5'
-date: "2014-06-27"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'This is the last tutorial about the basic flow and action API of DataFX.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-This is the last tutorial about the basic flow and action API of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}). I plan to start a second tutorial series about injection and resources in DataFX. But in those parts of DataFX 8 the APIs aren't final at the moment. So it will sadly take one or two month before I can continue the tutorials. An overview of all tutorials can be found [here]({{< ref "/posts/2014-05-19-datafx-8-0-tutorials" >}}).
-
-In this tutorial I want to show how flows can be interlaced. Therefore we create a new variation of the wizard app that was shown in [tutorial 4]({{< ref "/posts/2014-06-08-datafx-tutorial-4" >}}). The application should provide a simple wizard with some steps. Here is an overview how the dialogs and the flow where defined in tutorial 4:
-
-
-
-Once the application is finished it will look like the own that was created last time:
-
-
-
-The last implementation of the wizard has one weak point in its architecture: Each step of the wizard is defined as a view in a flow. The view contains the complete view of the application and so also the action toolbar is part of each view. In the last tutorial we extracted the toolbar in a separate FXML file but the controls were created for each view individually. But the toolbar has the same functionality on each view and normally it should be one single instance and only the view in the center of the application should change:
-
-
-
-This more logical structure is part of this tutorial and by using interlaced flows the favored behavior can be created. As always we will start by creating the FXML files for the application. Because the top views of the wizard should be defined in a separate flow there will be FXML files for the views that only contain the content of one wizard step. Here is an example for the first step:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-{{< / highlight >}}
-
-As you can see the FXML is much shorter than in the other tutorials. It only contains the Label that will be shown on the first view of the wizard.
-
-For the toolbar we can use the same FXML file as in tutorial 4:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-The FXML defines a HBox that include the 3 action buttons.
-
-Once this is done the application is defined by the following FXML files:
-
-
-
-As a next step a master FXML file is needed that includes the different components. As shown in then last tutorial the fx:include tag can be used to include FXML files within each other. Because the toolbar will be static component and the bottom of the application it can be included in the main FXML file. The wizard views on the top will change. Therefore we add a StackPane to the main FXML file that will hold the views. Here is the FXML file:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-The StackPane that will hold the central views of the wizard is defined by the unique id "centerPane". Once this is done all FXML files are finished and we can start to code in JavaFX. Let's take a look at the general structure of the application before we start to define the needed flows. As said the application will contain two flows that are interlaced. Here is a graphic that shows the structure:
-
-
-
-We will start with the view controller classes for all the wizard steps. Because the action toolbars isn't part of this views anymore and they contain only a label the code is very short :) Here is the class for the first view controller:
-
-{{< highlight java >}}
-@FXMLController("wizardView1.fxml")
-public class WizardView1Controller {
-}
-{{< / highlight >}}
-
-Easy, isn't it? The class is only needed to specify the view in the Java code and create the binding between the class and the FXML file. As you can see in the code of the example all other controller classes will look like this.
-
-As a next step we will create the flow of for these views. Here we only need to link the view for navigation. Therefore the definition of the flow will look like this:
-
-{{< highlight java >}}
-Flow flow = new Flow(WizardView1Controller.class).
- withLink(WizardView1Controller.class, "next", WizardView2Controller.class).
- withLink(WizardView2Controller.class, "next", WizardView3Controller.class).
- withLink(WizardView3Controller.class, "next", WizardView4Controller.class).
- withLink(WizardView4Controller.class, "next", WizardView5Controller.class);
-{{< / highlight >}}
-
-Ok, but where should this flow be defined. Until now all flows were defined in the main class of the application but this flow is an inner flow that will be part of another flow. To better understand how this can be achieved we should have a look at the main class of the application:
-
-{{< highlight java >}}
-public class Tutorial5Main extends Application {
- public static void main(String[] args) {
- launch(args);
- }
- @Override
- public void start(Stage primaryStage) throws Exception {
- Flow flow = new Flow(WizardController.class);
- FlowHandler flowHandler = flow.createHandler();
- StackPane pane = flowHandler.start(new DefaultFlowContainer());
- primaryStage.setScene(new Scene(pane));
- primaryStage.show();
- }
-}
-{{< / highlight >}}
-
-As in all other tutorials a flow is defined and started in the application class. But as you can see this flow defines only one start view that is defined by its controller class (WizardController). This class defines the controller of the main view of the application that is defined by the main FXML file as already shown. The flow that defines the steps of the wizard will be an inner flow in this view. Therefore the inner flow is defined in the WizardController controller class:
-
-{{< highlight java >}}
-@FXMLController("wizard.fxml")
-public class WizardController {
- @FXML
- private StackPane centerPane;
- private FlowHandler flowHandler;
- @PostConstruct
- public void init() throws FlowException {
- Flow innerFlow = new Flow(WizardView1Controller.class).
- withLink(WizardView1Controller.class, "next", WizardView2Controller.class).
- withLink(WizardView2Controller.class, "next", WizardView3Controller.class).
- withLink(WizardView3Controller.class, "next", WizardView4Controller.class).
- withLink(WizardView4Controller.class, "next", WizardView5Controller.class);
- flowHandler = innerFlow.createHandler();
- centerPane.getChildren().add(flowHandler.start(new AnimatedFlowContainer(Duration.millis(320), ContainerAnimations.ZOOM_IN)));
- }
-}
-{{< / highlight >}}
-
-Here all the steps of the wizard are added and linked to the inner flow. As you can see in the code the flow is started in a difference way than it was done several times before. A FlowHandler instance is created and this instances is started. This is wrapped in the startInStage() method of the Flow class that was used in all the other tutorials. The FlowHandler instance represents a running flow. The Flow class only defines the structure of a flow and can be started several times in parallel. Each running flow instance is defined by a FlowHandler instance and The FlowHandler instance can be used to interact with the flow. In addition the start(...) method of the FlowHandler class needs a FlowContainer as parameter. The FlowContainer provides a parent node in that the flow will be shown. In this case we use an AnimatedFlowContainer that provides animations whenever the flow navigates to a different view. We will see the animations at the end of the tutorial. The flow will be placed in the centerPane that is defined by FXML and injected in the controller by using the @FXML annotation.
-
-As said the FlowHandler class provides methods to interact with the flow. We will use this methods in the tutorial to call the "next", "back" and "finish" actions of the flow. To do so we need the action buttons that can easily be injected in the controller class:
-
-{{< highlight java >}}
-@FXMLController("wizard.fxml")
-public class WizardController {
- @FXML
- @ActionTrigger("back")
- private Button backButton;
- @FXML
- @ActionTrigger("finish")
- private Button finishButton;
- @FXML
- @ActionTrigger("next")
- private Button nextButton;
- @FXML
- private StackPane centerPane;
- //init()...
-}
-{{< / highlight >}}
-
-All the Buttons are annotated by the @ActionTrigger annotation and will therefore trigger actions in the flow. But they won't trigger actions in the inner flow because they are defined in the global flow that is defined in the main class. To handle this actions we will create some methods that are annoted by the @ActionMethod() annotation. As seen in [tutorial 1]({{< ref "/posts/2014-05-20-datafx-tutorial-1" >}}) these methods will be called whenever the action with the matching unique id is called:
-
-{{< highlight java >}}
-@FXMLController("wizard.fxml")
-public class WizardController {
- @FXML
- @ActionTrigger("back")
- private Button backButton;
- @FXML
- @ActionTrigger("finish")
- private Button finishButton;
- @FXML
- @ActionTrigger("next")
- private Button nextButton;
- //init()...
- @ActionMethod("back")
- public void onBack() throws VetoException, FlowException {
- }
- @ActionMethod("next")
- public void onNext() throws VetoException, FlowException {
- }
- @ActionMethod("finish")
- public void onFinish() throws VetoException, FlowException {
- }
-}
-{{< / highlight >}}
-
-In these methods the FlowHandler instance of the inner flow can be used to interact with the inner flow and navigate to new views or trigger actions. In addition some logic is needed to enable and disable the action buttons depending on the state of the inner flow. Here is the complete code of the WizardController class with the final implementation of these methods:
-
-{{< highlight java >}}
-@FXMLController("wizard.fxml")
-public class WizardController {
- @FXML
- @ActionTrigger("back")
- private Button backButton;
- @FXML
- @ActionTrigger("finish")
- private Button finishButton;
- @FXML
- @ActionTrigger("next")
- private Button nextButton;
- @FXML
- private StackPane centerPane;
- private FlowHandler flowHandler;
- @PostConstruct
- public void init() throws FlowException {
- Flow flow = new Flow(WizardView1Controller.class).
- withLink(WizardView1Controller.class, "next", WizardView2Controller.class).
- withLink(WizardView2Controller.class, "next", WizardView3Controller.class).
- withLink(WizardView3Controller.class, "next", WizardView4Controller.class).
- withLink(WizardView4Controller.class, "next", WizardView5Controller.class);
- flowHandler = flow.createHandler();
- centerPane.getChildren().add(flowHandler.start(new AnimatedFlowContainer(Duration.millis(320), ContainerAnimations.ZOOM_IN)));
- backButton.setDisable(true);
- }
- @ActionMethod("back")
- public void onBack() throws VetoException, FlowException {
- flowHandler.navigateBack();
- if(flowHandler.getCurrentViewControllerClass().equals(WizardView1Controller.class)) {
- backButton.setDisable(true);
- } else {
- backButton.setDisable(false);
- }
- finishButton.setDisable(false);
- nextButton.setDisable(false);
- }
- @ActionMethod("next")
- public void onNext() throws VetoException, FlowException {
- flowHandler.handle("next");
- if(flowHandler.getCurrentViewControllerClass().equals(WizardView5Controller.class)) {
- nextButton.setDisable(true);
- finishButton.setDisable(true);
- } else {
- nextButton.setDisable(false);
- }
- backButton.setDisable(false);
- }
- @ActionMethod("finish")
- public void onFinish() throws VetoException, FlowException {
- flowHandler.navigateTo(WizardView5Controller.class);
- finishButton.setDisable(true);
- nextButton.setDisable(true);
- backButton.setDisable(false);
- }
-}
-{{< / highlight >}}
-
-Once this is done you can start the flow and navigate through all the steps of the wizard. Thanks to the AnimatedFlowContainer container each link will be animated:
-
-{{< youtube uNX7VGtL2PY >}}
-
-As I said this is the final tutorial about the Flow API. From our point of view the API is finshed and we only plan to polish some stuff and add documentation. But we plan to release DataFX 8 at JavaOne and so there is still some time to change things. So if you have any questions, feedback or improvements please let us now. The next step is the CDI part of DataFX and once the APIs are stable I will continue this tutorial series.
+---
+outdated: true
+showInBlog: false
+title: 'DataFX Tutorial 5'
+date: "2014-06-27"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'This is the last tutorial about the basic flow and action API of DataFX.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+This is the last tutorial about the basic flow and action API of [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}). I plan to start a second tutorial series about injection and resources in DataFX. But in those parts of DataFX 8 the APIs aren't final at the moment. So it will sadly take one or two month before I can continue the tutorials. An overview of all tutorials can be found [here](/posts/2014-05-19-datafx-8-0-tutorials).
+
+In this tutorial I want to show how flows can be interlaced. Therefore we create a new variation of the wizard app that was shown in [tutorial 4](/posts/2014-06-08-datafx-tutorial-4). The application should provide a simple wizard with some steps. Here is an overview how the dialogs and the flow where defined in tutorial 4:
+
+
+
+Once the application is finished it will look like the own that was created last time:
+
+
+
+The last implementation of the wizard has one weak point in its architecture: Each step of the wizard is defined as a view in a flow. The view contains the complete view of the application and so also the action toolbar is part of each view. In the last tutorial we extracted the toolbar in a separate FXML file but the controls were created for each view individually. But the toolbar has the same functionality on each view and normally it should be one single instance and only the view in the center of the application should change:
+
+
+
+This more logical structure is part of this tutorial and by using interlaced flows the favored behavior can be created. As always we will start by creating the FXML files for the application. Because the top views of the wizard should be defined in a separate flow there will be FXML files for the views that only contain the content of one wizard step. Here is an example for the first step:
+
+```xml
+
+
+
+
+
```
+
+As you can see the FXML is much shorter than in the other tutorials. It only contains the Label that will be shown on the first view of the wizard.
+
+For the toolbar we can use the same FXML file as in tutorial 4:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+The FXML defines a HBox that include the 3 action buttons.
+
+Once this is done the application is defined by the following FXML files:
+
+
+
+As a next step a master FXML file is needed that includes the different components. As shown in then last tutorial the fx:include tag can be used to include FXML files within each other. Because the toolbar will be static component and the bottom of the application it can be included in the main FXML file. The wizard views on the top will change. Therefore we add a StackPane to the main FXML file that will hold the views. Here is the FXML file:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+The StackPane that will hold the central views of the wizard is defined by the unique id "centerPane". Once this is done all FXML files are finished and we can start to code in JavaFX. Let's take a look at the general structure of the application before we start to define the needed flows. As said the application will contain two flows that are interlaced. Here is a graphic that shows the structure:
+
+
+
+We will start with the view controller classes for all the wizard steps. Because the action toolbars isn't part of this views anymore and they contain only a label the code is very short :) Here is the class for the first view controller:
+
+```java@FXMLController("wizardView1.fxml")
+public class WizardView1Controller {
+}
```
+
+Easy, isn't it? The class is only needed to specify the view in the Java code and create the binding between the class and the FXML file. As you can see in the code of the example all other controller classes will look like this.
+
+As a next step we will create the flow of for these views. Here we only need to link the view for navigation. Therefore the definition of the flow will look like this:
+
+```javaFlow flow = new Flow(WizardView1Controller.class).
+ withLink(WizardView1Controller.class, "next", WizardView2Controller.class).
+ withLink(WizardView2Controller.class, "next", WizardView3Controller.class).
+ withLink(WizardView3Controller.class, "next", WizardView4Controller.class).
+ withLink(WizardView4Controller.class, "next", WizardView5Controller.class);
```
+
+Ok, but where should this flow be defined. Until now all flows were defined in the main class of the application but this flow is an inner flow that will be part of another flow. To better understand how this can be achieved we should have a look at the main class of the application:
+
+```javapublic class Tutorial5Main extends Application {
+ public static void main(String[] args) {
+ launch(args);
+ }
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ Flow flow = new Flow(WizardController.class);
+ FlowHandler flowHandler = flow.createHandler();
+ StackPane pane = flowHandler.start(new DefaultFlowContainer());
+ primaryStage.setScene(new Scene(pane));
+ primaryStage.show();
+ }
+}
```
+
+As in all other tutorials a flow is defined and started in the application class. But as you can see this flow defines only one start view that is defined by its controller class (WizardController). This class defines the controller of the main view of the application that is defined by the main FXML file as already shown. The flow that defines the steps of the wizard will be an inner flow in this view. Therefore the inner flow is defined in the WizardController controller class:
+
+```java@FXMLController("wizard.fxml")
+public class WizardController {
+ @FXML
+ private StackPane centerPane;
+ private FlowHandler flowHandler;
+ @PostConstruct
+ public void init() throws FlowException {
+ Flow innerFlow = new Flow(WizardView1Controller.class).
+ withLink(WizardView1Controller.class, "next", WizardView2Controller.class).
+ withLink(WizardView2Controller.class, "next", WizardView3Controller.class).
+ withLink(WizardView3Controller.class, "next", WizardView4Controller.class).
+ withLink(WizardView4Controller.class, "next", WizardView5Controller.class);
+ flowHandler = innerFlow.createHandler();
+ centerPane.getChildren().add(flowHandler.start(new AnimatedFlowContainer(Duration.millis(320), ContainerAnimations.ZOOM_IN)));
+ }
+}
```
+
+Here all the steps of the wizard are added and linked to the inner flow. As you can see in the code the flow is started in a difference way than it was done several times before. A FlowHandler instance is created and this instances is started. This is wrapped in the startInStage() method of the Flow class that was used in all the other tutorials. The FlowHandler instance represents a running flow. The Flow class only defines the structure of a flow and can be started several times in parallel. Each running flow instance is defined by a FlowHandler instance and The FlowHandler instance can be used to interact with the flow. In addition the start(...) method of the FlowHandler class needs a FlowContainer as parameter. The FlowContainer provides a parent node in that the flow will be shown. In this case we use an AnimatedFlowContainer that provides animations whenever the flow navigates to a different view. We will see the animations at the end of the tutorial. The flow will be placed in the centerPane that is defined by FXML and injected in the controller by using the @FXML annotation.
+
+As said the FlowHandler class provides methods to interact with the flow. We will use this methods in the tutorial to call the "next", "back" and "finish" actions of the flow. To do so we need the action buttons that can easily be injected in the controller class:
+
+```java@FXMLController("wizard.fxml")
+public class WizardController {
+ @FXML
+ @ActionTrigger("back")
+ private Button backButton;
+ @FXML
+ @ActionTrigger("finish")
+ private Button finishButton;
+ @FXML
+ @ActionTrigger("next")
+ private Button nextButton;
+ @FXML
+ private StackPane centerPane;
+ //init()...
+}
```
+
+All the Buttons are annotated by the @ActionTrigger annotation and will therefore trigger actions in the flow. But they won't trigger actions in the inner flow because they are defined in the global flow that is defined in the main class. To handle this actions we will create some methods that are annoted by the @ActionMethod() annotation. As seen in [tutorial 1](/posts/2014-05-20-datafx-tutorial-1) these methods will be called whenever the action with the matching unique id is called:
+
+```java@FXMLController("wizard.fxml")
+public class WizardController {
+ @FXML
+ @ActionTrigger("back")
+ private Button backButton;
+ @FXML
+ @ActionTrigger("finish")
+ private Button finishButton;
+ @FXML
+ @ActionTrigger("next")
+ private Button nextButton;
+ //init()...
+ @ActionMethod("back")
+ public void onBack() throws VetoException, FlowException {
+ }
+ @ActionMethod("next")
+ public void onNext() throws VetoException, FlowException {
+ }
+ @ActionMethod("finish")
+ public void onFinish() throws VetoException, FlowException {
+ }
+}
```
+
+In these methods the FlowHandler instance of the inner flow can be used to interact with the inner flow and navigate to new views or trigger actions. In addition some logic is needed to enable and disable the action buttons depending on the state of the inner flow. Here is the complete code of the WizardController class with the final implementation of these methods:
+
+```java@FXMLController("wizard.fxml")
+public class WizardController {
+ @FXML
+ @ActionTrigger("back")
+ private Button backButton;
+ @FXML
+ @ActionTrigger("finish")
+ private Button finishButton;
+ @FXML
+ @ActionTrigger("next")
+ private Button nextButton;
+ @FXML
+ private StackPane centerPane;
+ private FlowHandler flowHandler;
+ @PostConstruct
+ public void init() throws FlowException {
+ Flow flow = new Flow(WizardView1Controller.class).
+ withLink(WizardView1Controller.class, "next", WizardView2Controller.class).
+ withLink(WizardView2Controller.class, "next", WizardView3Controller.class).
+ withLink(WizardView3Controller.class, "next", WizardView4Controller.class).
+ withLink(WizardView4Controller.class, "next", WizardView5Controller.class);
+ flowHandler = flow.createHandler();
+ centerPane.getChildren().add(flowHandler.start(new AnimatedFlowContainer(Duration.millis(320), ContainerAnimations.ZOOM_IN)));
+ backButton.setDisable(true);
+ }
+ @ActionMethod("back")
+ public void onBack() throws VetoException, FlowException {
+ flowHandler.navigateBack();
+ if(flowHandler.getCurrentViewControllerClass().equals(WizardView1Controller.class)) {
+ backButton.setDisable(true);
+ } else {
+ backButton.setDisable(false);
+ }
+ finishButton.setDisable(false);
+ nextButton.setDisable(false);
+ }
+ @ActionMethod("next")
+ public void onNext() throws VetoException, FlowException {
+ flowHandler.handle("next");
+ if(flowHandler.getCurrentViewControllerClass().equals(WizardView5Controller.class)) {
+ nextButton.setDisable(true);
+ finishButton.setDisable(true);
+ } else {
+ nextButton.setDisable(false);
+ }
+ backButton.setDisable(false);
+ }
+ @ActionMethod("finish")
+ public void onFinish() throws VetoException, FlowException {
+ flowHandler.navigateTo(WizardView5Controller.class);
+ finishButton.setDisable(true);
+ nextButton.setDisable(true);
+ backButton.setDisable(false);
+ }
+}
```
+
+Once this is done you can start the flow and navigate through all the steps of the wizard. Thanks to the AnimatedFlowContainer container each link will be animated:
+
+
+
+As I said this is the final tutorial about the Flow API. From our point of view the API is finshed and we only plan to polish some stuff and add documentation. But we plan to release DataFX 8 at JavaOne and so there is still some time to change things. So if you have any questions, feedback or improvements please let us now. The next step is the CDI part of DataFX and once the APIs are stable I will continue this tutorial series.
diff --git a/content/posts/2014-09-09-javaone-2014-preview.md b/content/posts/2014-09-09-javaone-2014-preview.md
index 23a11033..65b0cdf3 100644
--- a/content/posts/2014-09-09-javaone-2014-preview.md
+++ b/content/posts/2014-09-09-javaone-2014-preview.md
@@ -8,9 +8,9 @@ categories: [JavaFX]
excerpt: 'I recorded a short video in that I introduce the talks and show a short preview of some JavaFX demos'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-As I mentioned [last week]({{< ref "/posts/2014-08-26-javaone-2014-sessions" >}}) I will give 6 talks at [JavaOne](https://www.oracle.com/javaone/) this year. To get a better overview of this talks I recorded a short video in that I introduce the talks and show a short preview of some JavaFX demos:
+As I mentioned [last week](/posts/2014-08-26-javaone-2014-sessions) I will give 6 talks at [JavaOne](https://www.oracle.com/javaone/) this year. To get a better overview of this talks I recorded a short video in that I introduce the talks and show a short preview of some JavaFX demos:
-{{< youtube 6Qp5mezk4dA >}}
+
Most of the talks will be hold with other speakers. Here is a list of all the people I'm currently working on cool stuff for JavaOne:
diff --git a/content/posts/2014-09-11-javaone-preview-enterprise-javafx.md b/content/posts/2014-09-11-javaone-preview-enterprise-javafx.md
index ac82bbf2..949dcc6d 100644
--- a/content/posts/2014-09-11-javaone-preview-enterprise-javafx.md
+++ b/content/posts/2014-09-11-javaone-preview-enterprise-javafx.md
@@ -19,5 +19,5 @@ Date and Time: 9/29/14, 16:00 - 17:00
Because I think a good talk must contain cool demos, I created some examples especially for my talks. Today I will introduce one of them with a short video. The video shows how you can login with Twitter in JavaFX. You can use this as an alternative workflow for users to login or register in your application. If you want to know how this is done you should visit my "Enterprise JavaFX" talk :)
-{{< youtube RTdQjxaH_wY >}}
+
diff --git a/content/posts/2014-09-30-enrich-list-ui-using-medialistcell.md b/content/posts/2014-09-30-enrich-list-ui-using-medialistcell.md
index eb138563..eb8b23b4 100644
--- a/content/posts/2014-09-30-enrich-list-ui-using-medialistcell.md
+++ b/content/posts/2014-09-30-enrich-list-ui-using-medialistcell.md
@@ -1,118 +1,110 @@
----
-outdated: true
-showInBlog: false
-title: 'Enrich your List UI by using the MediaListCell'
-date: "2014-09-30"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'For JavaOne I created some JavaFX APIs that contains basic utilities and controls that can be easily integrated in any JavaFX application. The ui-basics module contains some custom list cells that can be used to enrich your JavaFX application.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-By default the cells of a `ListView` will show only a string representation of your data on screen. This is ok for a basic implementation and will work for a lot of use cases. But if you have a application that contains a big list like a news feed or a chat you need a better skin for the cells. For JavaOne I created some JavaFX APIs that contains basic utilities and controls that can be easily integrated in any JavaFX application. The `ui-basics` module contains some custom list cells that can be used to enrich your JavaFX application. By using this cells we can achieve the following UI change with only a few lines of Java code:
-
-
-
-The following graphics shows the inheritance of the new cell classes:
-
-
-
-The `StructuredListCell` defines a cell that splits a cell in 3 regions: left, center and right. The center region will grow by default:
-
-
-
-You can add any content to the cell by calling the following methods:
-
-{{< highlight java >}}
-setRightContent(Node node)
-setRightContent(Node node)
-setRightContent(Node node)
-{{< / highlight >}}
-
-In addition the cell provides some new CSS attributes to style it:
-
-* `-fx-left-alignment`: Defines the vertical alignment of the left content
-* `-fx-center-alignment`: Defines the vertical alignment of the center content
-* `-fx-right-alignment`: Defines the vertical alignment of the right content
-* `-fx-spacing`: Defines the spacing between the 3 regions
-* `-fx-height-rule`: Defines which region should be used for the height calculation. By default the center content is used. This means that the cell will be as high as the center content.
-
-The `MediaListCell` extends this cell definition. It sets the center content to a a title and a description label. If you want to use the cell you only need to call `setTitle(...)` and `setDescription(...)` to define the center content:
-
-
-
-The class provides default style classes for both labels:
-
-* `media-cell-title`
-* `media-cell-description`
-
-In addition the class provides two new CSS properties:
-
-* `-fx-show-description`: Defines if the description label should be visible
-* `-fx-text-spacing`: Defines the spacing between the title and description label
-
-If you want the UI as shown in the demo you should use the `SimpleMediaListCell` class. This adds a rounded image view as the left content. By using this cell its very easy to create a list view like you know from many modern applications. To make the use of the cell even easier I introduced the `Media` interface. The `SimpleMediaListCell` is defined as `SimpleMediaListCell` and therefore it can only used with data that implements the `Media` interface. This interface is quite simple as you can see in its source:
-
-{{< highlight java >}}
-public interface Media {
-
- StringProperty titleProperty();
-
- StringProperty descriptionProperty();
-
- ObjectProperty imageProperty();
-}
-{{< / highlight >}}
-
-The properties of the nodes in the cell are automatically bound to the properties that are provided by the interface and therefore the `SimpleMediaListCell` class can be used like shown in the following example:
-
-{{< highlight java >}}
-public class Album implements Media {
-
- private String artist;
-
- private String coverUrl;
-
- private String name;
-
- //getter & setter
-
- @Override
- public StringProperty titleProperty() {
- return new SimpleStringProperty(getName());
- }
-
- @Override
- public StringProperty descriptionProperty() {
- return new SimpleStringProperty(getArtist());
- }
-
- @Override
- public ObjectProperty imageProperty() {
- return new SimpleObjectProperty<>(new Image(getCoverUrl(), true));
- }
-}
-
-//In View class...
-
-ListViewlistView = new ListView<>();
-listView.setCellFactory(v -> new SimpleMediaListCell<>());
-listView.setItems(dataModel.getAlbums());
-{{< / highlight >}}
-
-All the cell classes are part of the `ui-basics` module that can be found at github:
-
-{{< highlight xml >}}
-
- com.guigarage
- ui-basics
- X.Y
-
-{{< / highlight >}}
-
-## further development
-
-At the moment I plan some new features for the cells. As you might have registered the right region wasn't used in this example. In most UIs this is used to define a user action or hint like shown in this image:
-
-
-
-I plan to add this as a default feature. In addition I will provide different styles for the image view. Maybe you don't want a rounded view. In this case it would be perfect to define a style by css. Please ping me if you have some other cool improvements :)
+---
+outdated: true
+showInBlog: false
+title: 'Enrich your List UI by using the MediaListCell'
+date: "2014-09-30"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'For JavaOne I created some JavaFX APIs that contains basic utilities and controls that can be easily integrated in any JavaFX application. The ui-basics module contains some custom list cells that can be used to enrich your JavaFX application.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+By default the cells of a `ListView` will show only a string representation of your data on screen. This is ok for a basic implementation and will work for a lot of use cases. But if you have a application that contains a big list like a news feed or a chat you need a better skin for the cells. For JavaOne I created some JavaFX APIs that contains basic utilities and controls that can be easily integrated in any JavaFX application. The `ui-basics` module contains some custom list cells that can be used to enrich your JavaFX application. By using this cells we can achieve the following UI change with only a few lines of Java code:
+
+
+
+The following graphics shows the inheritance of the new cell classes:
+
+
+
+The `StructuredListCell` defines a cell that splits a cell in 3 regions: left, center and right. The center region will grow by default:
+
+
+
+You can add any content to the cell by calling the following methods:
+
+```javasetRightContent(Node node)
+setRightContent(Node node)
+setRightContent(Node node)
```
+
+In addition the cell provides some new CSS attributes to style it:
+
+* `-fx-left-alignment`: Defines the vertical alignment of the left content
+* `-fx-center-alignment`: Defines the vertical alignment of the center content
+* `-fx-right-alignment`: Defines the vertical alignment of the right content
+* `-fx-spacing`: Defines the spacing between the 3 regions
+* `-fx-height-rule`: Defines which region should be used for the height calculation. By default the center content is used. This means that the cell will be as high as the center content.
+
+The `MediaListCell` extends this cell definition. It sets the center content to a a title and a description label. If you want to use the cell you only need to call `setTitle(...)` and `setDescription(...)` to define the center content:
+
+
+
+The class provides default style classes for both labels:
+
+* `media-cell-title`
+* `media-cell-description`
+
+In addition the class provides two new CSS properties:
+
+* `-fx-show-description`: Defines if the description label should be visible
+* `-fx-text-spacing`: Defines the spacing between the title and description label
+
+If you want the UI as shown in the demo you should use the `SimpleMediaListCell` class. This adds a rounded image view as the left content. By using this cell its very easy to create a list view like you know from many modern applications. To make the use of the cell even easier I introduced the `Media` interface. The `SimpleMediaListCell` is defined as `SimpleMediaListCell` and therefore it can only used with data that implements the `Media` interface. This interface is quite simple as you can see in its source:
+
+```javapublic interface Media {
+
+ StringProperty titleProperty();
+
+ StringProperty descriptionProperty();
+
+ ObjectProperty imageProperty();
+}
```
+
+The properties of the nodes in the cell are automatically bound to the properties that are provided by the interface and therefore the `SimpleMediaListCell` class can be used like shown in the following example:
+
+```javapublic class Album implements Media {
+
+ private String artist;
+
+ private String coverUrl;
+
+ private String name;
+
+ //getter & setter
+
+ @Override
+ public StringProperty titleProperty() {
+ return new SimpleStringProperty(getName());
+ }
+
+ @Override
+ public StringProperty descriptionProperty() {
+ return new SimpleStringProperty(getArtist());
+ }
+
+ @Override
+ public ObjectProperty imageProperty() {
+ return new SimpleObjectProperty<>(new Image(getCoverUrl(), true));
+ }
+}
+
+//In View class...
+
+ListViewlistView = new ListView<>();
+listView.setCellFactory(v -> new SimpleMediaListCell<>());
+listView.setItems(dataModel.getAlbums());
```
+
+All the cell classes are part of the `ui-basics` module that can be found at github:
+
+```xml
+ com.guigarage
+ ui-basics
+ X.Y
+
```
+
+## further development
+
+At the moment I plan some new features for the cells. As you might have registered the right region wasn't used in this example. In most UIs this is used to define a user action or hint like shown in this image:
+
+
+
+I plan to add this as a default feature. In addition I will provide different styles for the image view. Maybe you don't want a rounded view. In this case it would be perfect to define a style by css. Please ping me if you have some other cool improvements :)
diff --git a/content/posts/2014-10-01-dialog-objects-pattern-automated-tests-testfx.md b/content/posts/2014-10-01-dialog-objects-pattern-automated-tests-testfx.md
index 20e732e3..e1f55824 100644
--- a/content/posts/2014-10-01-dialog-objects-pattern-automated-tests-testfx.md
+++ b/content/posts/2014-10-01-dialog-objects-pattern-automated-tests-testfx.md
@@ -1,102 +1,94 @@
----
-outdated: true
-showInBlog: false
-title: 'The View Objects Pattern & automated tests with TestFX'
-date: "2014-10-01"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'When developing an application you should add automated tests. Oh, sorry - I mean you MUST add automated test. This post introduces a pattern that help to create reuaseable and maintainable tests'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-When developing an application you should add automated tests. Oh, sorry - I mean you MUST add automated test. So when developing a JavaFX application there will come the moment when you ask yourself "How should I test this UI? A normal JUnit tests won't work here..."
-
-## TestFX basics
-
-That's right but the JavaFX community is prepared for this problem by offering [TestFX](https://github.com/TestFX/TestFX). With TestFX you can create unit tests for JavaFX applications. Let's imagine you have an application that only contains a login dialog:
-
-
-
-You can automatically test this dialog by using the TestFX API. I coded test might look like this:
-
-{{< highlight java >}}
-click(".text-field").type("steve");
-click(".password-field").type("duke4ever");
-click(".button:default");
-
-assertNodeExists( ".dialog" );
-{{< / highlight >}}
-
-As you can see you can control and fake all user events by using TestFX. At [github](https://github.com/TestFX/TestFX/wiki) you can find a general documentation of the API.
-
-## Dialog Objects Pattern
-
-Mostly your application will contain more than a simple login dialog and in that case a test could become confusing:
-
-{{< highlight java >}}
-click("#user-field").type("steve");
-click("#password-field").type("duke4ever");
-click("#login-button");
-click("#menu-button");
-click("#action-35");
-click("#tab-5");
-click("#next");
-click("#next");
-click("#next");
-click("#details");
-assertNodeExists( "#user-picture" );
-{{< / highlight >}}
-
-Web developers already know this problem and introduced a pattern to avoid it: [PageObject](http://martinfowler.com/bliki/PageObject.html)
-
-Since we don't have pages in JavaFX applications I would call it __"View Objects Pattern"__ instead. By using this pattern you will define a class / object for each view in your application. Let's image we have a music application with the following workflow:
-
-
-
-The applications contains 4 different views. To write tests for the application we should create a view object for each view. Here is an pseudo code example for the album overview:
-
-{{< highlight java >}}
-public class AlbumOverviewView extends ViewObject {
-
- public AlbumDetailView openAlbum(String name) {
- click((Text t) -> t.getText().contains(name));
- return new AlbumDetailView(getTestHandler());
- }
-
- public AlbumOverviewView checkAlbumCount(int count) {
- assertEquals(count, getList().size());
- return this;
- }
-
-
- public AlbumOverviewView assertContainsAlbum(String name) {
- assertTrue(getAlbums().filtered(a -> a.getName().equals(name)).isEmpty());
- return this;
- }
-}
-{{< / highlight >}}
-
-You can see some important facts in the code:
-
-* Each user interaction is defined as a method
-* The class provides methods to check important states
-* Each method returns the view object for the page that is visible after the method has been executed
-* If the view won't change by calling a method the method will return `this`
-
-By doing so it is very easy to write understandable tests. Because all the methods will return a view object you can use it as a fluent API:
-
-{{< highlight java >}}
-@Test
-public void checkSearchResult() {
- new SearchView(this).search("Rise Against").assertContainsAlbum("The Black Market");
-}
-
-@Test
-public void checkTrackCount() {
- new SearchView(this).search("Rise Against").openAlbum("The Black Market").checkTrackCountOfSelectedAlbum(12);
-}
-
-@Test
-public void checkPlayWorkflow() {
- new SearchView(this).search("Rise Against").openAlbum("The Black Market").play(1);
-}
-{{< / highlight >}}
+---
+outdated: true
+showInBlog: false
+title: 'The View Objects Pattern & automated tests with TestFX'
+date: "2014-10-01"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'When developing an application you should add automated tests. Oh, sorry - I mean you MUST add automated test. This post introduces a pattern that help to create reuaseable and maintainable tests'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+When developing an application you should add automated tests. Oh, sorry - I mean you MUST add automated test. So when developing a JavaFX application there will come the moment when you ask yourself "How should I test this UI? A normal JUnit tests won't work here..."
+
+## TestFX basics
+
+That's right but the JavaFX community is prepared for this problem by offering [TestFX](https://github.com/TestFX/TestFX). With TestFX you can create unit tests for JavaFX applications. Let's imagine you have an application that only contains a login dialog:
+
+
+
+You can automatically test this dialog by using the TestFX API. I coded test might look like this:
+
+```javaclick(".text-field").type("steve");
+click(".password-field").type("duke4ever");
+click(".button:default");
+
+assertNodeExists( ".dialog" );
```
+
+As you can see you can control and fake all user events by using TestFX. At [github](https://github.com/TestFX/TestFX/wiki) you can find a general documentation of the API.
+
+## Dialog Objects Pattern
+
+Mostly your application will contain more than a simple login dialog and in that case a test could become confusing:
+
+```javaclick("#user-field").type("steve");
+click("#password-field").type("duke4ever");
+click("#login-button");
+click("#menu-button");
+click("#action-35");
+click("#tab-5");
+click("#next");
+click("#next");
+click("#next");
+click("#details");
+assertNodeExists( "#user-picture" );
```
+
+Web developers already know this problem and introduced a pattern to avoid it: [PageObject](http://martinfowler.com/bliki/PageObject.html)
+
+Since we don't have pages in JavaFX applications I would call it __"View Objects Pattern"__ instead. By using this pattern you will define a class / object for each view in your application. Let's image we have a music application with the following workflow:
+
+
+
+The applications contains 4 different views. To write tests for the application we should create a view object for each view. Here is an pseudo code example for the album overview:
+
+```javapublic class AlbumOverviewView extends ViewObject {
+
+ public AlbumDetailView openAlbum(String name) {
+ click((Text t) -> t.getText().contains(name));
+ return new AlbumDetailView(getTestHandler());
+ }
+
+ public AlbumOverviewView checkAlbumCount(int count) {
+ assertEquals(count, getList().size());
+ return this;
+ }
+
+
+ public AlbumOverviewView assertContainsAlbum(String name) {
+ assertTrue(getAlbums().filtered(a -> a.getName().equals(name)).isEmpty());
+ return this;
+ }
+}
```
+
+You can see some important facts in the code:
+
+* Each user interaction is defined as a method
+* The class provides methods to check important states
+* Each method returns the view object for the page that is visible after the method has been executed
+* If the view won't change by calling a method the method will return `this`
+
+By doing so it is very easy to write understandable tests. Because all the methods will return a view object you can use it as a fluent API:
+
+```java@Test
+public void checkSearchResult() {
+ new SearchView(this).search("Rise Against").assertContainsAlbum("The Black Market");
+}
+
+@Test
+public void checkTrackCount() {
+ new SearchView(this).search("Rise Against").openAlbum("The Black Market").checkTrackCountOfSelectedAlbum(12);
+}
+
+@Test
+public void checkPlayWorkflow() {
+ new SearchView(this).search("Rise Against").openAlbum("The Black Market").play(1);
+}
```
diff --git a/content/posts/2014-10-01-integrate-custom-fonts-javafx-application-using-css.md b/content/posts/2014-10-01-integrate-custom-fonts-javafx-application-using-css.md
index a17fc6a0..2acb4af7 100644
--- a/content/posts/2014-10-01-integrate-custom-fonts-javafx-application-using-css.md
+++ b/content/posts/2014-10-01-integrate-custom-fonts-javafx-application-using-css.md
@@ -1,78 +1,68 @@
----
-outdated: true
-showInBlog: false
-title: 'How to integrate custom fonts in your JavaFX application by using CSS'
-date: "2014-10-01"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'This CSS trick will show how you can change to font for a complete application or only a specific control by using CSS.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-This is one of the CSS tips that were part of my "Extreme Guimaker" talk at JavaOne this year and will show how you can change the font for a complete application or only a specific control by using CSS.
-
-Before explaining the CSS solution I want to show a short example in Java code:
-
-{{< highlight java >}}
-Button b = new Button("Text");
-b.setFont(new Font("Arial", 24));
-{{< / highlight >}}
-
-In the code, the font of a button is set to "Arial" with a size of 24. All basic nodes in JavaFX that contains a text provide a font property that can be simply used to define a new font for the node. I don't think that this is a best practice because the font is an attribute that styles the application and therefore it should be separated from the application code.
-
-## Set fonts by CSS
-
-Fortunately JavaFX supports CSS and therefore we can extract the font specification from the Java code and add it to CSS. I won't discuss how IDs and style classes in CSS work in this post (If you not familiar with CSS you should have a look in [my book]({{ site.baseurl }}{% link pages/mastering-javafx-controls.md %})). The font of a node can be defined by using the `-fx-font-*` attributes in CSS. You can find a documentation of these attributes [here](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html#typefont). Here is an example that defines the font for a button:
-
-{{< highlight css >}}
-#my-button {
- -fx-font-family: "Arial";
- -fx-font-size: 24;
-}
-{{< / highlight >}}
-
-If you want to define a global font for all controls in your application you can simply set the font to the `.text` style class. The Text shape in JavaFX contains this pseudo class by default and all nodes that render a text on the screen use the Text shape internally. Here is the css rule that will set the font for a complete application:
-
-{{< highlight css >}}
-.text {
- -fx-font-family: "Asap";
-}
-{{< / highlight >}}
-
-## Adding custom fonts
-
-In the examples "Arial" is used as the custom font. Normally you can assume that this font will be installed on a client system. But sometimes you want to use a custom font to create a unique UI. In the following example, I want to use the Roboto font that is the official font of [Googles Material Design](http://www.google.com/design/spec/style/typography.html#typography-roboto). Normally this font won't be installed on a client system. So if you define the font by CSS and a customer will run the application without installing the specific font on the OS JavaFX will select a system font as a fallback and the cool UI of the app is broken. But thankfully there is a good solution for this problem. Since Java 8 JavaFX supports the `@font-face` rule that can be used to add fonts. As a first step, the font file must be added to the application. As a best practice the file should be added to the resources folder:
-
-
-
-Once this is done the font can be defined in CSS by using the `@font-face` rule:
-
-{{< highlight css >}}
-@font-face {
- font-family: 'Roboto';
- src: url('Roboto-Medium.ttf');
-}
-
-.text {
- -fx-font-family: "Roboto";
-}
-{{< / highlight >}}
-
-Now the font will be used in our application even if it isn't installed on the OS:
-
-
-
-## Update
-
-As I learned today the shown code isn't working in Java versions >= 1.8u60. Starting with this version the attribute “font-family” is ignored and you have to use the real name of the TTF.
-
-If you want to use the font “Birds of Paradis” that is contained in the file `demo.ttf`, for example, you have to use this CSS file:
-
-{{< highlight css >}}
-@font-face {
- src: url(“/ui/font/demo.ttf”);
-}
-
-.label {
- -fx-font-family: “Birds of Paradise”;
-}
-{{< / highlight >}}
+---
+outdated: true
+showInBlog: false
+title: 'How to integrate custom fonts in your JavaFX application by using CSS'
+date: "2014-10-01"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'This CSS trick will show how you can change to font for a complete application or only a specific control by using CSS.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+This is one of the CSS tips that were part of my "Extreme Guimaker" talk at JavaOne this year and will show how you can change the font for a complete application or only a specific control by using CSS.
+
+Before explaining the CSS solution I want to show a short example in Java code:
+
+```javaButton b = new Button("Text");
+b.setFont(new Font("Arial", 24));
```
+
+In the code, the font of a button is set to "Arial" with a size of 24. All basic nodes in JavaFX that contains a text provide a font property that can be simply used to define a new font for the node. I don't think that this is a best practice because the font is an attribute that styles the application and therefore it should be separated from the application code.
+
+## Set fonts by CSS
+
+Fortunately JavaFX supports CSS and therefore we can extract the font specification from the Java code and add it to CSS. I won't discuss how IDs and style classes in CSS work in this post (If you not familiar with CSS you should have a look in [my book]({{ site.baseurl }}{% link pages/mastering-javafx-controls.md %})). The font of a node can be defined by using the `-fx-font-*` attributes in CSS. You can find a documentation of these attributes [here](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html#typefont). Here is an example that defines the font for a button:
+
+```css#my-button {
+ -fx-font-family: "Arial";
+ -fx-font-size: 24;
+}
```
+
+If you want to define a global font for all controls in your application you can simply set the font to the `.text` style class. The Text shape in JavaFX contains this pseudo class by default and all nodes that render a text on the screen use the Text shape internally. Here is the css rule that will set the font for a complete application:
+
+```css.text {
+ -fx-font-family: "Asap";
+}
```
+
+## Adding custom fonts
+
+In the examples "Arial" is used as the custom font. Normally you can assume that this font will be installed on a client system. But sometimes you want to use a custom font to create a unique UI. In the following example, I want to use the Roboto font that is the official font of [Googles Material Design](http://www.google.com/design/spec/style/typography.html#typography-roboto). Normally this font won't be installed on a client system. So if you define the font by CSS and a customer will run the application without installing the specific font on the OS JavaFX will select a system font as a fallback and the cool UI of the app is broken. But thankfully there is a good solution for this problem. Since Java 8 JavaFX supports the `@font-face` rule that can be used to add fonts. As a first step, the font file must be added to the application. As a best practice the file should be added to the resources folder:
+
+
+
+Once this is done the font can be defined in CSS by using the `@font-face` rule:
+
+```css@font-face {
+ font-family: 'Roboto';
+ src: url('Roboto-Medium.ttf');
+}
+
+.text {
+ -fx-font-family: "Roboto";
+}
```
+
+Now the font will be used in our application even if it isn't installed on the OS:
+
+
+
+## Update
+
+As I learned today the shown code isn't working in Java versions >= 1.8u60. Starting with this version the attribute “font-family” is ignored and you have to use the real name of the TTF.
+
+If you want to use the font “Birds of Paradis” that is contained in the file `demo.ttf`, for example, you have to use this CSS file:
+
+```css@font-face {
+ src: url(“/ui/font/demo.ttf”);
+}
+
+.label {
+ -fx-font-family: “Birds of Paradise”;
+}
```
diff --git a/content/posts/2014-10-05-iconify-application-resolution-independent-way.md b/content/posts/2014-10-05-iconify-application-resolution-independent-way.md
index ea9daf1b..86732883 100644
--- a/content/posts/2014-10-05-iconify-application-resolution-independent-way.md
+++ b/content/posts/2014-10-05-iconify-application-resolution-independent-way.md
@@ -1,81 +1,71 @@
----
-outdated: true
-showInBlog: false
-title: 'Iconify your application the resolution independent way'
-date: "2014-10-05"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'Often icons are very important for a good UI. They will create a modern and professional look and will help the user to understand the meaning of actions.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Often icons are very important for a good UI. They will create a modern and professional look and will help the user to understand the meaning of actions. Especially on small screens icons are important. For a mobile application you won't create a toolbar with 5 actions that are described by a long text. In the following screenshot 3 actions are defined in the toolbar by using only icon:
-
-
-
-I think that mostly all users will understand that these actions defines a back action and 2 actions to change the volume.
-
-Today applications will be developed for different hardware and therefore for different screen resolutions. Let's think about the retina displays. Here you will have a 4x bigger resolution than on normal screens. In an ideal case an applications supports this devices and will fit its size and content. But that means, that all controls will have a 4x bigger size. Often you will use images for your icons. But resizing them will create a pixelated view. For a Mac retina display you can use the ["@2"-syntax](https://developer.apple.com/library/ios/qa/qa1686/_index.html) to provide retina images. But sometimes you want to scale an icon even bigger (Maybe you want to scale it in an animation, for example). Thats why you should use vector based icons:
-
-
-
-Ok, that sounds reasonable but where can we find vector based icons and how can we integrate them in JavaFX?
-
-For me the best resource for vector based icons is [Font Awesome](http://fortawesome.github.io/Font-Awesome/) that is a font which contains over 450 vector based icons. Here is a short extract:
-
-
-
-Because it is a font it can simply be integrated to any JavaFX application ([see this post]({{< ref "/posts/2014-10-01-integrate-custom-fonts-javafx-application-using-css" >}})). Once the font is assigned to a control you can define an icon by setting the text of the control. Here a special unicode character need to be set as the text. The following example describes how to set the pen icon to a button:
-
-{{< highlight java >}}
-button.setText('\uf040' + "");
-// \uf040 is the unicode char for the icon as defines here: http://fortawesome.github.io/Font-Awesome/icon/pencil/
-{{< / highlight >}}
-
-Once you now this trick you still need to do some steps to display a vector based icon:
-
-* add the font to the resources folder
-* define the font in CSS by using `@font-face`
-* set the font to the specific control (in CSS)
-* define the specific icon in java code
-
-Especially the last point isn't what I want. Icons are part of the style of an application and therefore it would be perfect if we could define them in CSS. There fore I created a new Skin for the JavaFX Button called `IconifiedButtonSkin`. By using the skin the handling of vector based icons in your JavaFX application is much easier. To use the skin you only need one line of Java code:
-
-{{< highlight java >}}
-IconifiedButtonSkin.addStyle(myButton);
-{{< / highlight >}}
-
-Once this is done the new skin for the button is set. This automatically contains the following steps:
-
-* add the font to the resources folder
-* define the font in CSS by using `@font-face`
-* set the font to the specific control in CSS by adding the `iconified-button` style class
-
-The last think that need to be done is setting the text of the button to define the wanted icon. Thankfully the new skin provides an additional CSS attribute that can be used. By using the -fx-icon-text attribute you can define the wanted icon directly in CSS:
-
-{{< highlight css >}}
-#myButton {
- -fx-icon-text: "\uf0a9";
-}
-{{< / highlight >}}
-
-The `IconifiedButtonSkin` class is part of the `ui-basics` module that will be found at Maven Central the next days:
-
-{{< highlight xml >}}
-
- com.guigarage
- ui-basics
- X.Y
-
-{{< / highlight >}}
-
-## further development
-
-I plan to add a special CSS Converter in Java to provide a better definition of the icons in CSS. Wouldn't it be cool if you could do the following:
-
-{{< highlight css >}}
-#myButton {
- -fx-icon: "fa fa-pencil";
-}
-{{< / highlight >}}
-
-Once this is done it would be cool to support more fonts like [ionicons](http://ionicons.com) by default.
+---
+outdated: true
+showInBlog: false
+title: 'Iconify your application the resolution independent way'
+date: "2014-10-05"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'Often icons are very important for a good UI. They will create a modern and professional look and will help the user to understand the meaning of actions.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Often icons are very important for a good UI. They will create a modern and professional look and will help the user to understand the meaning of actions. Especially on small screens icons are important. For a mobile application you won't create a toolbar with 5 actions that are described by a long text. In the following screenshot 3 actions are defined in the toolbar by using only icon:
+
+
+
+I think that mostly all users will understand that these actions defines a back action and 2 actions to change the volume.
+
+Today applications will be developed for different hardware and therefore for different screen resolutions. Let's think about the retina displays. Here you will have a 4x bigger resolution than on normal screens. In an ideal case an applications supports this devices and will fit its size and content. But that means, that all controls will have a 4x bigger size. Often you will use images for your icons. But resizing them will create a pixelated view. For a Mac retina display you can use the ["@2"-syntax](https://developer.apple.com/library/ios/qa/qa1686/_index.html) to provide retina images. But sometimes you want to scale an icon even bigger (Maybe you want to scale it in an animation, for example). Thats why you should use vector based icons:
+
+
+
+Ok, that sounds reasonable but where can we find vector based icons and how can we integrate them in JavaFX?
+
+For me the best resource for vector based icons is [Font Awesome](http://fortawesome.github.io/Font-Awesome/) that is a font which contains over 450 vector based icons. Here is a short extract:
+
+
+
+Because it is a font it can simply be integrated to any JavaFX application ([see this post](/posts/2014-10-01-integrate-custom-fonts-javafx-application-using-css)). Once the font is assigned to a control you can define an icon by setting the text of the control. Here a special unicode character need to be set as the text. The following example describes how to set the pen icon to a button:
+
+```javabutton.setText('\uf040' + "");
+// \uf040 is the unicode char for the icon as defines here: http://fortawesome.github.io/Font-Awesome/icon/pencil/
```
+
+Once you now this trick you still need to do some steps to display a vector based icon:
+
+* add the font to the resources folder
+* define the font in CSS by using `@font-face`
+* set the font to the specific control (in CSS)
+* define the specific icon in java code
+
+Especially the last point isn't what I want. Icons are part of the style of an application and therefore it would be perfect if we could define them in CSS. There fore I created a new Skin for the JavaFX Button called `IconifiedButtonSkin`. By using the skin the handling of vector based icons in your JavaFX application is much easier. To use the skin you only need one line of Java code:
+
+```javaIconifiedButtonSkin.addStyle(myButton);
```
+
+Once this is done the new skin for the button is set. This automatically contains the following steps:
+
+* add the font to the resources folder
+* define the font in CSS by using `@font-face`
+* set the font to the specific control in CSS by adding the `iconified-button` style class
+
+The last think that need to be done is setting the text of the button to define the wanted icon. Thankfully the new skin provides an additional CSS attribute that can be used. By using the -fx-icon-text attribute you can define the wanted icon directly in CSS:
+
+```css#myButton {
+ -fx-icon-text: "\uf0a9";
+}
```
+
+The `IconifiedButtonSkin` class is part of the `ui-basics` module that will be found at Maven Central the next days:
+
+```xml
+ com.guigarage
+ ui-basics
+ X.Y
+
```
+
+## further development
+
+I plan to add a special CSS Converter in Java to provide a better definition of the icons in CSS. Wouldn't it be cool if you could do the following:
+
+```css#myButton {
+ -fx-icon: "fa fa-pencil";
+}
```
+
+Once this is done it would be cool to support more fonts like [ionicons](http://ionicons.com) by default.
diff --git a/content/posts/2014-10-22-datafx-8-released.md b/content/posts/2014-10-22-datafx-8-released.md
index 1c840590..1094a373 100644
--- a/content/posts/2014-10-22-datafx-8-released.md
+++ b/content/posts/2014-10-22-datafx-8-released.md
@@ -1,80 +1,76 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX 8 has been released & DataFX core overview'
-date: "2014-10-22"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'I''m proud to announce that we have released DataFX 8.0 last week. This post will give you an overview of all the cool new features.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-I'm proud to announce that we have released DataFX 8.0 last week. With DataFX 2.0 we created an API to get real world data in your JavaFX 2 application by using data readers for REST, WebSocket, SSE and many more endpoints. With DataFX 8.0 we introduce a lot of more content for your JavaFX 8 applications. Next to the data reader APIs we included flow and injection API to DataFX to create MVC based views and complex workflows. By doing so we lifted DataFX from a data reader API to a (small) application framework. DataFX 8.0 contains 5 modules:
-
-* core
-* datasources
-* websocket
-* flow
-* injection
-
-I think one of the big benefits of DataFX is that it has hardly any external dependency. The following graph shows the internal and external dependencies of DataFX 8:
-
-
-
-As you can see in the picture next to the javassist dependencies all other dependencies are Java specs.
-
-Ok let's talk about the content of the modules. As a first step of the DataFX 8 development we extracted all APIs that provide general support for multithreading and added them to the core module. Next to this some cool new APIs are part of the core module that will help you to define background tasks and solve concurrent problems the easy ways. Today I want to introduce two of these features. If you are interested in all features of DataFX 8 you should read the [tutorials]({{< ref "/posts/2014-05-19-datafx-8-0-tutorials" >}}) and have a look in our [JavaOne slides](http://de.slideshare.net/HendrikEbbers/datafx-8-javaone-2014).
-
-## The Observable Executor
-
-When working with background tasks you will need a thread pool to manage all the concurrent operations. JavaSE provides several different of them with the Executors class. In DataFX 8 we introduce the [ObservableExecutor]({{< ref "/posts/2013-02-09-datafx-observableexecutor-preview" >}}) that is an implementation of the [Executor](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html) interface and provides some JavaFX specific additional functionality. By using the ObservableExecutor you can bind the capacity of the executor to any JavaFX property. In addition all the task interfaces and classes of JavaSE, JavaFX and DataFX are supported by the ObservableExecutor. By doing so it is very easy to define titles, messages or progress updates for all your background tasks and show them on screen. A demo of the ObservableExecutor can be found [here]({{< ref "/posts/2013-02-09-datafx-observableexecutor-preview" >}}). As a next step we will combine the ObservableExecutor with the cool Task Progress View by Dirk Lemmermann. It looks like this one is made for the ObservableExecutor ;)
-
-{{< youtube As-ahnLR_Dw >}}
-
-## The ProcessChain
-
-When developing an enterprise application with JavaFX you will need to define background tasks to call some server endpoints or start batch processes. Normally you will react to the answer of the tasks and update the UI. For example if you call a REST endpoint to receive some data you want to display the data on screen once the call is done. Doing this in the JavaFX Application thread isn't the best idea. You don't know how long the task will need to execute and therefore the application can't be repainted while the call is executing. This will end in a frozen application and frustrated users.
-
-
-
-It's import to execute the server call (as any long running action) to a background thread. Doing this with the basic JavaSE concurrency tools will blow up your code and create methods that aren't readable. Here is a simple example of a function that will call a background task and show it's result on screen:
-
-{{< highlight java >}}
-Runnable backgroundRunnable = () -> {
- try {
- data = loadFromServer();
- Platform.runLater(() -> {
- updateUI(data);
- });
- } catch(Exception e) {
- Platform.runLater(() -> {
- handleException(e);
- });
- } finally {
- Platform.runLater(() -> {
- unblockUI();
- });
- }
-}
-{{< / highlight >}}
-
-I hope you are with me when saying that this code isn't as readable as it should be. In Swing Java contains a good helper class called the [SwingWorker](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html). By using this class it was easier to create background tasks that provide data for the fronted.
-
-
-
-It's still a lot of code that is needed to create a working SwingWorker because anonymous classes are needed. But today we have Lambdas, functional interfaces and all this cool language features and therefore you wouldn't code a background tasks this way. In DataFX 8 we introduce the ProcessChain class that is like a SwingWorker on steroids. Here is a small example that shows how the top code can be refactored by using the ProcessChain:
-
-{{< highlight java >}}
-ProcessChain.create().
-addRunnableInPlatformThread(() -> blockUI()).
-addSupplierInExecutor(() -> loadFromServer()).
-addConsumerInPlatformThread(d -> updateUI(d)).
-onException(e -> handleException(e)).
-withFinal(() -> unblockUI()).
-run();
-{{< / highlight >}}
-
-Cool, isn't it. Now we can read the code and understand what's going on here. The ProcessChain uses all the new functional interfaces like Supplier or Consumer to define a chain of tasks that can be called on a background thread or on the JavaFX Application Thread. In addition the exception handling is directly included in the ProcessChain API. If you want to learn more about the ProcessChain you should check out our [slides](http://de.slideshare.net/HendrikEbbers/datafx-8-javaone-2014) or my [JavaFX Enterprise talk](http://de.slideshare.net/HendrikEbbers/javafx-enterprise-javaone-2014?related=1).
-
-I hope you like these features. In the next posts I will introduce the other DataFX 8 modules.
-
-{% include posts/slideshare.html id="39687394" %}
+---
+outdated: true
+showInBlog: false
+title: 'DataFX 8 has been released & DataFX core overview'
+date: "2014-10-22"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'I''m proud to announce that we have released DataFX 8.0 last week. This post will give you an overview of all the cool new features.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+I'm proud to announce that we have released DataFX 8.0 last week. With DataFX 2.0 we created an API to get real world data in your JavaFX 2 application by using data readers for REST, WebSocket, SSE and many more endpoints. With DataFX 8.0 we introduce a lot of more content for your JavaFX 8 applications. Next to the data reader APIs we included flow and injection API to DataFX to create MVC based views and complex workflows. By doing so we lifted DataFX from a data reader API to a (small) application framework. DataFX 8.0 contains 5 modules:
+
+* core
+* datasources
+* websocket
+* flow
+* injection
+
+I think one of the big benefits of DataFX is that it has hardly any external dependency. The following graph shows the internal and external dependencies of DataFX 8:
+
+
+
+As you can see in the picture next to the javassist dependencies all other dependencies are Java specs.
+
+Ok let's talk about the content of the modules. As a first step of the DataFX 8 development we extracted all APIs that provide general support for multithreading and added them to the core module. Next to this some cool new APIs are part of the core module that will help you to define background tasks and solve concurrent problems the easy ways. Today I want to introduce two of these features. If you are interested in all features of DataFX 8 you should read the [tutorials](/posts/2014-05-19-datafx-8-0-tutorials) and have a look in our [JavaOne slides](http://de.slideshare.net/HendrikEbbers/datafx-8-javaone-2014).
+
+## The Observable Executor
+
+When working with background tasks you will need a thread pool to manage all the concurrent operations. JavaSE provides several different of them with the Executors class. In DataFX 8 we introduce the [ObservableExecutor](/posts/2013-02-09-datafx-observableexecutor-preview) that is an implementation of the [Executor](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html) interface and provides some JavaFX specific additional functionality. By using the ObservableExecutor you can bind the capacity of the executor to any JavaFX property. In addition all the task interfaces and classes of JavaSE, JavaFX and DataFX are supported by the ObservableExecutor. By doing so it is very easy to define titles, messages or progress updates for all your background tasks and show them on screen. A demo of the ObservableExecutor can be found [here](/posts/2013-02-09-datafx-observableexecutor-preview). As a next step we will combine the ObservableExecutor with the cool Task Progress View by Dirk Lemmermann. It looks like this one is made for the ObservableExecutor ;)
+
+
+
+## The ProcessChain
+
+When developing an enterprise application with JavaFX you will need to define background tasks to call some server endpoints or start batch processes. Normally you will react to the answer of the tasks and update the UI. For example if you call a REST endpoint to receive some data you want to display the data on screen once the call is done. Doing this in the JavaFX Application thread isn't the best idea. You don't know how long the task will need to execute and therefore the application can't be repainted while the call is executing. This will end in a frozen application and frustrated users.
+
+
+
+It's import to execute the server call (as any long running action) to a background thread. Doing this with the basic JavaSE concurrency tools will blow up your code and create methods that aren't readable. Here is a simple example of a function that will call a background task and show it's result on screen:
+
+```javaRunnable backgroundRunnable = () -> {
+ try {
+ data = loadFromServer();
+ Platform.runLater(() -> {
+ updateUI(data);
+ });
+ } catch(Exception e) {
+ Platform.runLater(() -> {
+ handleException(e);
+ });
+ } finally {
+ Platform.runLater(() -> {
+ unblockUI();
+ });
+ }
+}
```
+
+I hope you are with me when saying that this code isn't as readable as it should be. In Swing Java contains a good helper class called the [SwingWorker](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html). By using this class it was easier to create background tasks that provide data for the fronted.
+
+
+
+It's still a lot of code that is needed to create a working SwingWorker because anonymous classes are needed. But today we have Lambdas, functional interfaces and all this cool language features and therefore you wouldn't code a background tasks this way. In DataFX 8 we introduce the ProcessChain class that is like a SwingWorker on steroids. Here is a small example that shows how the top code can be refactored by using the ProcessChain:
+
+```javaProcessChain.create().
+addRunnableInPlatformThread(() -> blockUI()).
+addSupplierInExecutor(() -> loadFromServer()).
+addConsumerInPlatformThread(d -> updateUI(d)).
+onException(e -> handleException(e)).
+withFinal(() -> unblockUI()).
+run();
```
+
+Cool, isn't it. Now we can read the code and understand what's going on here. The ProcessChain uses all the new functional interfaces like Supplier or Consumer to define a chain of tasks that can be called on a background thread or on the JavaFX Application Thread. In addition the exception handling is directly included in the ProcessChain API. If you want to learn more about the ProcessChain you should check out our [slides](http://de.slideshare.net/HendrikEbbers/datafx-8-javaone-2014) or my [JavaFX Enterprise talk](http://de.slideshare.net/HendrikEbbers/javafx-enterprise-javaone-2014?related=1).
+
+I hope you like these features. In the next posts I will introduce the other DataFX 8 modules.
+
+{% include posts/slideshare.html id="39687394" %}
diff --git a/content/posts/2014-11-01-new-desktop-application-framework-datafx.md b/content/posts/2014-11-01-new-desktop-application-framework-datafx.md
index de79578c..e013d76e 100644
--- a/content/posts/2014-11-01-new-desktop-application-framework-datafx.md
+++ b/content/posts/2014-11-01-new-desktop-application-framework-datafx.md
@@ -1,181 +1,167 @@
----
-outdated: true
-showInBlog: false
-title: 'New Desktop Application Framework & DataFX'
-date: "2014-11-01"
-author: hendrik
-categories: [DataFX, Desktop Application Framework (JSR 377), JavaFX]
-excerpt: 'If DataFX should become an implementation of the JSR specification it must implement general interfaces and support a toolkit independent architecture.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Maybe you have mentioned that [Andres Almiray](https://twitter.com/aalmiray) is planing [a new desktop application framework JSR](http://www.jroller.com/aalmiray/entry/new_desktop_application_framework_jsr). I had a chat with him some days ago at the canoo hq and we discussed some points of this project. In addition Andres gave me an introduction to [Griffon](http://griffon.codehaus.org) and I showed him [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}).
-
-One of the core features of the framework should be UI toolkit independency. By doing so the framework will only contain general definitions and JavaFX or Swing specific implementations will be loaded by SPI, for example.
-
-Griffon already contains this abstraction but DataFX is hardly coded against JavaFX. I think this is absolutely ok and at the moment there eis no plan to support other UI toolkits that JavaFX with DataFX. As said the application framework will define general classes and interfaces and maybe DataFX will be one of the JavaFX implementation. We will see what happens in the future.
-
-## Generalizing the DataFX concepts
-
-If DataFX should become an implementation of the JSR specification it must implement general interfaces and support a toolkit independent architecture. Therefore I did some tests and create a small platform independent framework based on DataFX architecture and APIs. I chose the concurrent API and the controller API of DataFX and created more general versions. As a benefit I created some cool code and features that will be integrated in DataFX 8.1. Let's have a look at the framework that is called "JWrap". You can find [the sources at GitHub](https://github.com/guigarage/jwrap). Because this was only a test there isn't any javadoc at the moment but the project contains a [Swing](https://github.com/guigarage/jwrap/tree/master/src/main/java/com/guigarage/uif/examples/swing) and a [JavaFX](https://github.com/guigarage/jwrap/tree/master/src/main/java/com/guigarage/uif/examples/javafx) example. JWrap has zero dependencies and defines a MVC and a concurrency API. Both API are platform independent and you don't need dependencies to Swing or JavaFX to use them.
-
-## JWrap concurrency utils
-
-JWrap contains a [UIToolkit class](https://github.com/guigarage/jwrap/blob/master/src/main/java/com/guigarage/uif/concurrent/UIToolkit.java) that can be used to work with the event and rendering thread of the underlying UI toolkit. Here are the methods that are defined in the class:
-
-{{< highlight java >}}
-void runAndWait(Runnable runnable)
-
-void runLater(Runnable runnable)
-
-boolean isToolkitThread()
-
- T runCallableAndWait(Callable callable)
-{{< / highlight >}}
-
-By using these methods you can interact with the event and rendering thread of the used UI toolkit. To do so you must configure JWrap. This can be done by only one line of code. Here is an example how you configure JWrap to use the Swing EDT:
-
-{{< highlight java >}}
-UIToolkit.setPlatform(SwingPlatform.getInstance());
-{{< / highlight >}}
-
-There are several other concurrency classes in JWrap that all depend on the UIToolkit class. By doing so you can now use all the concurrency helpers in JWrap and automatically the EDT will be used as application thread. I ported the [ProcessChain]({{< ref "/posts/2014-10-22-datafx-8-released" >}}) of DataFX to JWarp and now you can code the following in your Swing application:
-
-{{< highlight java >}}
-ProcessChain.create().
- addSupplierInPlatformThread(() -> myTextField.getText()).
- addFunctionInExecutor((t) -> WeatherService.getWeather(t)).
- addConsumerInPlatformThread((t) -> myLabel.setText(t)).onException((e) -> {
- myLabel.setText("Error");
- e.printStackTrace();
- }).run();
-{{< / highlight >}}
-
-I think this code is much better than using the SwingWorker. You can easily use the `ProcessChain` in any Swing application that supports Java 8.
-
-## JWrap MVC API
-
-DataFX contains the [controller and flow API]({{< ref "/posts/2014-05-19-datafx-8-0-tutorials" >}}) that can be used to define MVC based views in JavaFX. I ported some parts of this API to JWarp and created a UI toolkit independent way to define MVC based controllers. JWrap contains some annotations that can be used to create a link between the view and the controller of a dialog.
-
-Let's start with the swim example. As a first step we define the view and define names for all the UI components:
-
-{{< highlight java >}}
-public class SwingDemoView extends JPanel {
-
- public SwingDemoView() {
- setLayout(new BorderLayout());
-
- JButton myButton = new JButton("Get weather by city");
- myButton.setName("myButton");
-
- JTextField myTextField = new JTextField();
- myTextField.setName("myTextField");
-
- JLabel myLabel = new JLabel("Result...");
- myLabel.setName("myLabel");
-
- add(myTextField, BorderLayout.NORTH);
- add(myButton, BorderLayout.CENTER);
- add(myLabel, BorderLayout.SOUTH);
- }
-}
-{{< / highlight >}}
-
-The second class of the dialog will be the controller class. In this class JWrap annotations can be sued to inject view components in the controller and define interaction:
-
-{{< highlight java >}}
-public class SwingDemoController {
-
- @ViewNode
- @ActionTrigger("copy-action")
- private JButton myButton;
-
- @ViewNode
- private JTextField myTextField;
-
- @ViewNode
- private JLabel myLabel;
-
- @ActionMethod("copy-action")
- private void copy() {
- ProcessChain.create().
- addSupplierInPlatformThread(() -> myTextField.getText()).
- addFunctionInExecutor((t) -> WeatherService.getWeather(t)).
- addConsumerInPlatformThread((t) -> myLabel.setText(t)).onException((e) -> {
- myLabel.setText("Error");
- e.printStackTrace();
- }).run();
- }
-
- @PostConstruct
- private void init() {
- System.out.println("TADA");
- }
-}
-{{< / highlight >}}
-
-The `@ViewNode` annotation can be compared to the `@FXML` annotation that is used in JavaFX and DataFX to inject view nodes that are defined in FXML in a controller. The `@ViewNode` annotation has some benefits because it can be used for FXML based view and for coded view (this is one of the features that I will integrate in DataFX 8.1).
-
-The JavaFX version looks mainly the same. Here is the code for the view class:
-
-{{< highlight java >}}
-public class JavaFXDemoView extends VBox {
-
- public JavaFXDemoView() {
- setSpacing(12);
- setPadding(new Insets(12));
-
- Button myButton = new Button("Get weather by city");
- myButton.setId("myButton");
-
- TextField myTextField = new TextField();
- myTextField.setId("myTextField");
-
- Label myLabel = new Label("Result...");
- myLabel.setId("myLabel");
-
- getChildren().addAll(myTextField, myButton, myLabel);
-
- }
-}
-{{< / highlight >}}
-
-And here we have the controller class:
-
-{{< highlight java >}}
-public class JavaFXDemoController {
-
- @ViewNode
- @ActionTrigger("copy-action")
- private Button myButton;
-
- @ViewNode
- private TextField myTextField;
-
- @ViewNode
- private Label myLabel;
-
- @ActionMethod("copy-action")
- private void copy() {
- ProcessChain.create().
- addSupplierInPlatformThread(() -> myTextField.getText()).
- addFunctionInExecutor((t) -> WeatherService.getWeather(t)).
- addConsumerInPlatformThread((t) -> myLabel.setText(t)).onException((e) -> {
- myLabel.setText("Error");
- e.printStackTrace();
- }).run();
- }
-
- @PostConstruct
- private void init() {
- System.out.println("TADA");
- }
-}
-{{< / highlight >}}
-
-As you can see the Swing controller class and the JavaFX controller looks mainly the same. Annotations like `@ViewNode` can be used in Swing and JavaFX.
-
-## The future of JWrap
-
-I created this project to test of a UI independent API can look like. I don't plan to continue working on the library. Maybe I will use it when checking some other ideas for the application framework JSR.
-
-I think that the library can be a benefit for Swing developers. By using JWrap they will get some lambda based concurrency APIs and a MVC framework that can be used to structure the code or prepare a migration to JavaFX.
+---
+outdated: true
+showInBlog: false
+title: 'New Desktop Application Framework & DataFX'
+date: "2014-11-01"
+author: hendrik
+categories: [DataFX, Desktop Application Framework (JSR 377), JavaFX]
+excerpt: 'If DataFX should become an implementation of the JSR specification it must implement general interfaces and support a toolkit independent architecture.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Maybe you have mentioned that [Andres Almiray](https://twitter.com/aalmiray) is planing [a new desktop application framework JSR](http://www.jroller.com/aalmiray/entry/new_desktop_application_framework_jsr). I had a chat with him some days ago at the canoo hq and we discussed some points of this project. In addition Andres gave me an introduction to [Griffon](http://griffon.codehaus.org) and I showed him [DataFX]({{ site.baseurl }}{% link pages/projects/datafx.md %}).
+
+One of the core features of the framework should be UI toolkit independency. By doing so the framework will only contain general definitions and JavaFX or Swing specific implementations will be loaded by SPI, for example.
+
+Griffon already contains this abstraction but DataFX is hardly coded against JavaFX. I think this is absolutely ok and at the moment there eis no plan to support other UI toolkits that JavaFX with DataFX. As said the application framework will define general classes and interfaces and maybe DataFX will be one of the JavaFX implementation. We will see what happens in the future.
+
+## Generalizing the DataFX concepts
+
+If DataFX should become an implementation of the JSR specification it must implement general interfaces and support a toolkit independent architecture. Therefore I did some tests and create a small platform independent framework based on DataFX architecture and APIs. I chose the concurrent API and the controller API of DataFX and created more general versions. As a benefit I created some cool code and features that will be integrated in DataFX 8.1. Let's have a look at the framework that is called "JWrap". You can find [the sources at GitHub](https://github.com/guigarage/jwrap). Because this was only a test there isn't any javadoc at the moment but the project contains a [Swing](https://github.com/guigarage/jwrap/tree/master/src/main/java/com/guigarage/uif/examples/swing) and a [JavaFX](https://github.com/guigarage/jwrap/tree/master/src/main/java/com/guigarage/uif/examples/javafx) example. JWrap has zero dependencies and defines a MVC and a concurrency API. Both API are platform independent and you don't need dependencies to Swing or JavaFX to use them.
+
+## JWrap concurrency utils
+
+JWrap contains a [UIToolkit class](https://github.com/guigarage/jwrap/blob/master/src/main/java/com/guigarage/uif/concurrent/UIToolkit.java) that can be used to work with the event and rendering thread of the underlying UI toolkit. Here are the methods that are defined in the class:
+
+```javavoid runAndWait(Runnable runnable)
+
+void runLater(Runnable runnable)
+
+boolean isToolkitThread()
+
+ T runCallableAndWait(Callable callable)
```
+
+By using these methods you can interact with the event and rendering thread of the used UI toolkit. To do so you must configure JWrap. This can be done by only one line of code. Here is an example how you configure JWrap to use the Swing EDT:
+
+```javaUIToolkit.setPlatform(SwingPlatform.getInstance());
```
+
+There are several other concurrency classes in JWrap that all depend on the UIToolkit class. By doing so you can now use all the concurrency helpers in JWrap and automatically the EDT will be used as application thread. I ported the [ProcessChain](/posts/2014-10-22-datafx-8-released) of DataFX to JWarp and now you can code the following in your Swing application:
+
+```javaProcessChain.create().
+ addSupplierInPlatformThread(() -> myTextField.getText()).
+ addFunctionInExecutor((t) -> WeatherService.getWeather(t)).
+ addConsumerInPlatformThread((t) -> myLabel.setText(t)).onException((e) -> {
+ myLabel.setText("Error");
+ e.printStackTrace();
+ }).run();
```
+
+I think this code is much better than using the SwingWorker. You can easily use the `ProcessChain` in any Swing application that supports Java 8.
+
+## JWrap MVC API
+
+DataFX contains the [controller and flow API](/posts/2014-05-19-datafx-8-0-tutorials) that can be used to define MVC based views in JavaFX. I ported some parts of this API to JWarp and created a UI toolkit independent way to define MVC based controllers. JWrap contains some annotations that can be used to create a link between the view and the controller of a dialog.
+
+Let's start with the swim example. As a first step we define the view and define names for all the UI components:
+
+```javapublic class SwingDemoView extends JPanel {
+
+ public SwingDemoView() {
+ setLayout(new BorderLayout());
+
+ JButton myButton = new JButton("Get weather by city");
+ myButton.setName("myButton");
+
+ JTextField myTextField = new JTextField();
+ myTextField.setName("myTextField");
+
+ JLabel myLabel = new JLabel("Result...");
+ myLabel.setName("myLabel");
+
+ add(myTextField, BorderLayout.NORTH);
+ add(myButton, BorderLayout.CENTER);
+ add(myLabel, BorderLayout.SOUTH);
+ }
+}
```
+
+The second class of the dialog will be the controller class. In this class JWrap annotations can be sued to inject view components in the controller and define interaction:
+
+```javapublic class SwingDemoController {
+
+ @ViewNode
+ @ActionTrigger("copy-action")
+ private JButton myButton;
+
+ @ViewNode
+ private JTextField myTextField;
+
+ @ViewNode
+ private JLabel myLabel;
+
+ @ActionMethod("copy-action")
+ private void copy() {
+ ProcessChain.create().
+ addSupplierInPlatformThread(() -> myTextField.getText()).
+ addFunctionInExecutor((t) -> WeatherService.getWeather(t)).
+ addConsumerInPlatformThread((t) -> myLabel.setText(t)).onException((e) -> {
+ myLabel.setText("Error");
+ e.printStackTrace();
+ }).run();
+ }
+
+ @PostConstruct
+ private void init() {
+ System.out.println("TADA");
+ }
+}
```
+
+The `@ViewNode` annotation can be compared to the `@FXML` annotation that is used in JavaFX and DataFX to inject view nodes that are defined in FXML in a controller. The `@ViewNode` annotation has some benefits because it can be used for FXML based view and for coded view (this is one of the features that I will integrate in DataFX 8.1).
+
+The JavaFX version looks mainly the same. Here is the code for the view class:
+
+```javapublic class JavaFXDemoView extends VBox {
+
+ public JavaFXDemoView() {
+ setSpacing(12);
+ setPadding(new Insets(12));
+
+ Button myButton = new Button("Get weather by city");
+ myButton.setId("myButton");
+
+ TextField myTextField = new TextField();
+ myTextField.setId("myTextField");
+
+ Label myLabel = new Label("Result...");
+ myLabel.setId("myLabel");
+
+ getChildren().addAll(myTextField, myButton, myLabel);
+
+ }
+}
```
+
+And here we have the controller class:
+
+```javapublic class JavaFXDemoController {
+
+ @ViewNode
+ @ActionTrigger("copy-action")
+ private Button myButton;
+
+ @ViewNode
+ private TextField myTextField;
+
+ @ViewNode
+ private Label myLabel;
+
+ @ActionMethod("copy-action")
+ private void copy() {
+ ProcessChain.create().
+ addSupplierInPlatformThread(() -> myTextField.getText()).
+ addFunctionInExecutor((t) -> WeatherService.getWeather(t)).
+ addConsumerInPlatformThread((t) -> myLabel.setText(t)).onException((e) -> {
+ myLabel.setText("Error");
+ e.printStackTrace();
+ }).run();
+ }
+
+ @PostConstruct
+ private void init() {
+ System.out.println("TADA");
+ }
+}
```
+
+As you can see the Swing controller class and the JavaFX controller looks mainly the same. Annotations like `@ViewNode` can be used in Swing and JavaFX.
+
+## The future of JWrap
+
+I created this project to test of a UI independent API can look like. I don't plan to continue working on the library. Maybe I will use it when checking some other ideas for the application framework JSR.
+
+I think that the library can be a benefit for Swing developers. By using JWrap they will get some lambda based concurrency APIs and a MVC framework that can be used to structure the code or prepare a migration to JavaFX.
diff --git a/content/posts/2014-11-04-responsive-design-javafx.md b/content/posts/2014-11-04-responsive-design-javafx.md
index 62591c37..71cf2a7d 100644
--- a/content/posts/2014-11-04-responsive-design-javafx.md
+++ b/content/posts/2014-11-04-responsive-design-javafx.md
@@ -1,149 +1,135 @@
----
-outdated: true
-showInBlog: false
-title: 'Responsive Design for JavaFX'
-date: "2014-11-04"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'At JavaOne I introduced ResponsiveFX as a lib that adds responsive design to JavaFX. This post describes the core concepts of responsive design and the API.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Once of the new APIs that I have shown at JavaOne was __ResponsiveFX__ that can be used to add responsive design to your JavaFX application. ResponsiveFX is an open source project maintained by Canoo and will be published to Maven Central the next days.
-
-## Responsive Design
-
-Today software must fit a wide range of devices. When developing an application customers often want to use it on a desktop pc and on a tablet. In addition a subset of the features should be useable with a mobile phone. Oh, and maybe next year the first customers want to check information on a smart watch. Even if web apps and JavaFX applications can be distributed and used on most of this devices you can't simply use the same UI on them.
-
-
-
-All these devices provide different screen sizes and resolutions. In addition the user interaction is in some parts completely different. While using a mouse and keyboard on a desktop pc you want to use touch and gestures on your mobile to navigate through the app.
-
-One approach to handle these issues is responsive design that can be used to provide an optimal viewing experience—easy reading and navigation with a minimum of resizing, panning, and scrolling—across a wide range of devices. Responsive design was first introduced by web applications and influenced the development trends in this area. By defining different layout for specific screen sizes the fronted of a web application will look good on mostly all devices.
-
-
-
-## ResponsiveFX
-
-The core concept of ReponsiveFX is copied from [Twitter Boostrap](http://getbootstrap.com) that provides responsive design for HTML. Boostrap provides several CSS style classes that can be used to hide or show components on different screen sizes. Here is a short overview of all the style classes:
-
-
-
-By adding one of these style classes to a component the visibility of the component depends on the current frame size. Here is a small example how this can be used in HTML:
-
-{{< highlight xml >}}
-
big text
-
small text
-{{< / highlight >}}
-
-## Responsive Design & JavaFX
-
-By default JavaFX doesn't provide an API for responsive design. Thankfully JavaFX supports CSS and therefore we can add this feature. This is exactly what ReponsiveFX does. By using the API you can simply use the same style classes as in HTML in your JavaFX application. To add the responsive support to an application you only need one line of Java code:
-
-{{< highlight java >}}
-ResponsiveHandler.addResponsiveToWindow(primaryStage);
-{{< / highlight >}}
-
-This adds the support for responsive design to the given stage. All nodes that are in this stage can now use the described style classes. Therefore you can simply do the following in Java code:
-
-{{< highlight java >}}
-TableView table = new TableView(items);
-table.getStyleClass().addAll("visible-lg", "visible-md");
-
-ListView list = new ListView(items);
-list.getStyleClass().addAll("visible-xs", "visible-sm");
-
-pane.getChildren().addAll(table, list);
-{{< / highlight >}}
-
-In the example a table and a list are defined that will visualize the same set of data (`items`). Depending on the size of the application the list or the table will be shown on screen. Here is a short video that shows the behavior:
-
-{{< youtube A35scZFXgic >}}
-
-By adding this API to your JavaFX application you will have the same possibilities as in HTML to provide responsive design.
-
-## Responsive Design & pseudo classes
-
-By using the given classes you can hide and show components depending to the frame size in your application but often you want to show different sizes of controls depending on the screen size. Let's think about a toolbar that should have a different size in all supported screen sizes. In HTML you would do the following:
-
-{{< highlight xml >}}
-
...
-
...
-
...
-
...
-{{< / highlight >}}
-
-In JavaFX this would correspond the following code snippet:
-
-{{< highlight java >}}
-Toolbar extraSmallToolbar = new Toolbar(...);
-extraSmallToolbar.getStyleClass().add("visible-xs");
-
-Toolbar smallToolbar = new Toolbar(...);
-smallToolbar.getStyleClass().add("visible-sm");
-
-Toolbar mediumToolbar = new Toolbar(...);
-mediumToolbar.getStyleClass().add("visible-md");
-
-Toolbar largeToolbar = new Toolbar(...);
-largeToolbar.getStyleClass().add("visible-lg");
-
-pane.getChildren().add(extraSmallToolbar, smallToolbar, mediumToolbar, largeToolbar);
-{{< / highlight >}}
-
-This is very bad practive because Java must handle all 4 instances in this case. Even if only one toolbar will be displayed on screen all are part of the scene graph. If you will do this with controls that contains images you will blow up your memory for example. Therefore you shouldn't do this. I thinks it's clear that we need a better solution and ResponsiveFX contains one :)
-
-Next to the style classes ReponsiveFX provides pseudo classes for all supported screen sizes. Here is a list of the supported pseudo classes:
-
-* extreme-small-device
-* small-device
-* medium-device
-* large-device
-
-By using this pseudo classes you can define the visualization of a node depending on the current application size. The pseudo classes will automatically be added and removed for each node inside the scene graph of a windows that is handled by the ResponsiveHandler. Thanks to this you can define the following CSS rules for a control:
-
-{{< highlight css >}}
-#toolbar {
- -fx-background-color: deepskyblue;
-}
-
-#toolbar:extreme-small-device {
- -fx-padding: 1 1 0 1;
-}
-
-#toolbar:small-device {
- -fx-padding: 2 2 1 2;
-}
-
-#toolbar:medium-device {
- -fx-padding: 6 6 1 6;
-}
-
-#toolbar:large-device {
- -fx-padding: 6 6 1 6;
- -fx-background-image: url(blue-background.png);
-}
-{{< / highlight >}}
-
-In your Java code you can now define one control and set its ID to match the CSS rules:
-
-{{< highlight java >}}
-Toolbar myToolbar = new Toolbar(...);
-myToolbar.setId(toolbar);
-pane.getChildren().add(myToolbar);
-{{< / highlight >}}
-
-Whenever the size of the application will change the matching pseudo class will be set to the control and the visualization of the control will change depending on the CSS attributes. By doing so you can create applications that will look different on the specified frame sizes. This will be helpful when developing applications that should work for desktop and mobile or on embedded devices. Here is a short video that shows how a responsive application might look:
-
-{{< youtube nQiFiXJTZzc >}}
-
-## Responsive Design in Java code
-
-In addition to the shown features ReponsiveFX supports a Java API to react on responsive changes. A listener can be registered to the ResponsiveHandler and will be fired whenever the responsive types changes. By doing so you can react on changes direct in Java code. This will be helpful if you need to change anything that can't be done by CSS. AT the moment this feature is a fast hack for JavaOne but I plan to refactor this in near future.
-
-## Where can I get it?
-
-As said ResponsiveFX will be released in near future. I'm currently create clean modules / libraries of all the demos and examples that I showed at JavaOne. ResponsiveFX is already extracted as a stand alone library. The next days I will set up the GitHub repo and add some documentation. Once this is done I will upload the first version to Maven Central.
-
-## Additional Information
-
-Because of a missing feature in JavaFX ReponsiveFX contains some hacks that can result in unwanted behavior. If you like the API and need responsive design in JavaFX you should [vote for this issue at the JavaFX bug database](https://javafx-jira.kenai.com/browse/RT-38508).
+---
+outdated: true
+showInBlog: false
+title: 'Responsive Design for JavaFX'
+date: "2014-11-04"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'At JavaOne I introduced ResponsiveFX as a lib that adds responsive design to JavaFX. This post describes the core concepts of responsive design and the API.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Once of the new APIs that I have shown at JavaOne was __ResponsiveFX__ that can be used to add responsive design to your JavaFX application. ResponsiveFX is an open source project maintained by Canoo and will be published to Maven Central the next days.
+
+## Responsive Design
+
+Today software must fit a wide range of devices. When developing an application customers often want to use it on a desktop pc and on a tablet. In addition a subset of the features should be useable with a mobile phone. Oh, and maybe next year the first customers want to check information on a smart watch. Even if web apps and JavaFX applications can be distributed and used on most of this devices you can't simply use the same UI on them.
+
+
+
+All these devices provide different screen sizes and resolutions. In addition the user interaction is in some parts completely different. While using a mouse and keyboard on a desktop pc you want to use touch and gestures on your mobile to navigate through the app.
+
+One approach to handle these issues is responsive design that can be used to provide an optimal viewing experience—easy reading and navigation with a minimum of resizing, panning, and scrolling—across a wide range of devices. Responsive design was first introduced by web applications and influenced the development trends in this area. By defining different layout for specific screen sizes the fronted of a web application will look good on mostly all devices.
+
+
+
+## ResponsiveFX
+
+The core concept of ReponsiveFX is copied from [Twitter Boostrap](http://getbootstrap.com) that provides responsive design for HTML. Boostrap provides several CSS style classes that can be used to hide or show components on different screen sizes. Here is a short overview of all the style classes:
+
+
+
+By adding one of these style classes to a component the visibility of the component depends on the current frame size. Here is a small example how this can be used in HTML:
+
+```xml
big text
+
small text
```
+
+## Responsive Design & JavaFX
+
+By default JavaFX doesn't provide an API for responsive design. Thankfully JavaFX supports CSS and therefore we can add this feature. This is exactly what ReponsiveFX does. By using the API you can simply use the same style classes as in HTML in your JavaFX application. To add the responsive support to an application you only need one line of Java code:
+
+```javaResponsiveHandler.addResponsiveToWindow(primaryStage);
```
+
+This adds the support for responsive design to the given stage. All nodes that are in this stage can now use the described style classes. Therefore you can simply do the following in Java code:
+
+```javaTableView table = new TableView(items);
+table.getStyleClass().addAll("visible-lg", "visible-md");
+
+ListView list = new ListView(items);
+list.getStyleClass().addAll("visible-xs", "visible-sm");
+
+pane.getChildren().addAll(table, list);
```
+
+In the example a table and a list are defined that will visualize the same set of data (`items`). Depending on the size of the application the list or the table will be shown on screen. Here is a short video that shows the behavior:
+
+
+
+By adding this API to your JavaFX application you will have the same possibilities as in HTML to provide responsive design.
+
+## Responsive Design & pseudo classes
+
+By using the given classes you can hide and show components depending to the frame size in your application but often you want to show different sizes of controls depending on the screen size. Let's think about a toolbar that should have a different size in all supported screen sizes. In HTML you would do the following:
+
+```xml
...
+
...
+
...
+
...
```
+
+In JavaFX this would correspond the following code snippet:
+
+```javaToolbar extraSmallToolbar = new Toolbar(...);
+extraSmallToolbar.getStyleClass().add("visible-xs");
+
+Toolbar smallToolbar = new Toolbar(...);
+smallToolbar.getStyleClass().add("visible-sm");
+
+Toolbar mediumToolbar = new Toolbar(...);
+mediumToolbar.getStyleClass().add("visible-md");
+
+Toolbar largeToolbar = new Toolbar(...);
+largeToolbar.getStyleClass().add("visible-lg");
+
+pane.getChildren().add(extraSmallToolbar, smallToolbar, mediumToolbar, largeToolbar);
```
+
+This is very bad practive because Java must handle all 4 instances in this case. Even if only one toolbar will be displayed on screen all are part of the scene graph. If you will do this with controls that contains images you will blow up your memory for example. Therefore you shouldn't do this. I thinks it's clear that we need a better solution and ResponsiveFX contains one :)
+
+Next to the style classes ReponsiveFX provides pseudo classes for all supported screen sizes. Here is a list of the supported pseudo classes:
+
+* extreme-small-device
+* small-device
+* medium-device
+* large-device
+
+By using this pseudo classes you can define the visualization of a node depending on the current application size. The pseudo classes will automatically be added and removed for each node inside the scene graph of a windows that is handled by the ResponsiveHandler. Thanks to this you can define the following CSS rules for a control:
+
+```css#toolbar {
+ -fx-background-color: deepskyblue;
+}
+
+#toolbar:extreme-small-device {
+ -fx-padding: 1 1 0 1;
+}
+
+#toolbar:small-device {
+ -fx-padding: 2 2 1 2;
+}
+
+#toolbar:medium-device {
+ -fx-padding: 6 6 1 6;
+}
+
+#toolbar:large-device {
+ -fx-padding: 6 6 1 6;
+ -fx-background-image: url(blue-background.png);
+}
```
+
+In your Java code you can now define one control and set its ID to match the CSS rules:
+
+```javaToolbar myToolbar = new Toolbar(...);
+myToolbar.setId(toolbar);
+pane.getChildren().add(myToolbar);
```
+
+Whenever the size of the application will change the matching pseudo class will be set to the control and the visualization of the control will change depending on the CSS attributes. By doing so you can create applications that will look different on the specified frame sizes. This will be helpful when developing applications that should work for desktop and mobile or on embedded devices. Here is a short video that shows how a responsive application might look:
+
+
+
+## Responsive Design in Java code
+
+In addition to the shown features ReponsiveFX supports a Java API to react on responsive changes. A listener can be registered to the ResponsiveHandler and will be fired whenever the responsive types changes. By doing so you can react on changes direct in Java code. This will be helpful if you need to change anything that can't be done by CSS. AT the moment this feature is a fast hack for JavaOne but I plan to refactor this in near future.
+
+## Where can I get it?
+
+As said ResponsiveFX will be released in near future. I'm currently create clean modules / libraries of all the demos and examples that I showed at JavaOne. ResponsiveFX is already extracted as a stand alone library. The next days I will set up the GitHub repo and add some documentation. Once this is done I will upload the first version to Maven Central.
+
+## Additional Information
+
+Because of a missing feature in JavaFX ReponsiveFX contains some hacks that can result in unwanted behavior. If you like the API and need responsive design in JavaFX you should [vote for this issue at the JavaFX bug database](https://javafx-jira.kenai.com/browse/RT-38508).
diff --git a/content/posts/2014-11-12-first-steps-webcomponents.md b/content/posts/2014-11-12-first-steps-webcomponents.md
index 2d7294f3..9f44ef1e 100644
--- a/content/posts/2014-11-12-first-steps-webcomponents.md
+++ b/content/posts/2014-11-12-first-steps-webcomponents.md
@@ -1,156 +1,144 @@
----
-outdated: true
-showInBlog: false
-title: 'First steps with WebComponents'
-date: "2014-11-12"
-author: hendrik
-categories: [Polymer, Web Frontends, WebComponents]
-excerpt: 'WebComponents are custom components for the web. I tried the new spec and created my first simple WebComponent with HTML, JavaScript and CSS'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-I think one of the big new HTML features in the next years will be WebComponents. By using WebComponents developers can create fully-featured DOM elements as defined in the [web component spec](http://w3c.github.io/webcomponents/spec/custom/). In short this means that you can create your own HTML tags. If you want to add an avatar view to your web app you and use web components you can define a avatar component and then use the `` tag in your HTML file. To use web components today you can use one of the following libraries:
-
-* [bosonic](http://bosonic.github.io)
-* [polymer](https://www.polymer-project.org)
-* [x-tag](http://x-tags.org)
-
-I chose polymer to create my first web component and in this post I want to show you what I did to create a reusable custom HTML tag. Most likely this isn't a best practice tutorial because I currently starting to learn about this topic :)
-
-## Project setup
-
-As a first step I downloaded the polymer lib. To do so I used [bower](http://bower.io) that is a package manager for web development. With bower you can define all the library dependencies of a web application like you can do with Maven for Java apps.
-
-After you have installed bower on your system you need to execute the following commands in the folder of your web project:
-
-{{< highlight shell >}}
-bower init
-bower install --save Polymer/polymer
-{{< / highlight >}}
-
-This will create a `bower.json` file in your project and adds polymer as dependency. My file looks like this:
-
-{{< highlight json >}}
-{
- "name": "polymer-test",
- "version": "0.0.0",
- "description": "A polymer playground",
- "license": "MIT",
- "keywords": [
- "polymer",
- "web-components"
- ],
- "ignore": [
- "**/.*",
- "node_modules",
- "bower_components"
- ],
- "dependencies": {
- "polymer": "Polymer/polymer#^0.4.1"
- }
-}
-{{< / highlight >}}
-
-To download all dependencies you need to call
-
-{{< highlight shell >}}
-bower install
-{{< / highlight >}}
-
-This command will download all defined dependencies and install the in the `bower_components` folder in your project. When committing your project to git you can simply ignore this folder.
-
-If you don't want to use bower you can download and integrate the polymer lib by hand.
-
-As a next step you can create a `index.html` to test your custom components and a folder that will contain the components. Once this is done your application folder might look like this:
-
-
-
-## General structure of a WebComponent
-
-As said a web component is a custom control for web pages. Top define a component we only need one HTML file. As in other [languages or UT toolkits]({{< ref "/posts/2012-11-17-custom-ui-controls-with-javafx-part-1" >}}) a web component is composed of a layout definition, a style and controller logic. In the web world this means HTML (layout), CSS (style) and JavaScript (controller). By using polymer all 3 parts can combined in one file. Here is a skeleton for the file:
-
-{{< highlight html >}}
-
-
-
-
-
- // contains the layout of the component in HTML
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-As you can see the code starts with an import. Each custom component must import the `polymer.html` file. Thanks to bower this is already in the `bower_components` folder and can simply be imported. The `polymer-element` tag describes the web component. In the tag there are 3 more tags that describes the layout (template), the style (style) and the controller of the component (script). The `polymer-element` tag has some attributes that describes the name of our component and its attributes.
-
-To create a small web component you don't need to define all 3 inner tags but some basics are needed to display the component in a browser.
-
-## Defining the first component
-
-As a start we want to create a minimal web component that will only print an "A" on screen. To do so we create the "Simple-A.html" file in the components folder and add the following content:
-
-{{< highlight html >}}
-
-
-
-
-
-
A
-
-
-
-
-
-{{< / highlight >}}
-
-As far as I know is this the minimum definition that you need to define a component. In the template a paragraph that contains an "A" is defined. This is default HTML and if we don't want to create a reusable component we could write this directly in an HTML file. In the script section the Polymer({}); call registers the component so it's recognized by the browser. Once this is done the component can be used in any HTML file to render the "A" paragraph on screen:
-
-
-
-## Use the component
-
-To include the custom web component in a HTML page you need to import it. In addition the polymer platform lib must included to the page. Here is the code of a HTML page that includes everything and adds the "A" paragraph component several times to the body of the page:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-As you can see in the code the html files that defines the custom component is imported in the web page. Once this is done the custom tag `` can be used in the web page. When having a look at the web developer tools of safari you can see that the A tags are now part of the page:
-
-
-
-## Browser support
-
-I tested my HTML file on Safari, Chrome and Firefox. Safari and Firefox work fine but on Chrome I don't see anything. The web console shows a "Cross-Origin Resource Sharing" so maybe it will work when running the page on a web server instead of just opening the file from the filesystem. I'm not a web expert so maybe Chrome has the correct behavior here. I will check this later and blog about it in my next web component post. After all by doing the most simply try and opening the HTML file with the browsers that re installed on my system this is the result of the browser check:
-
-
-
-## Conclusion
-
-It was very easy to create the first web component. As a next step I will try attributes for the components and some JavaScript logic. I will block about it as fast as possible.
+---
+outdated: true
+showInBlog: false
+title: 'First steps with WebComponents'
+date: "2014-11-12"
+author: hendrik
+categories: [Polymer, Web Frontends, WebComponents]
+excerpt: 'WebComponents are custom components for the web. I tried the new spec and created my first simple WebComponent with HTML, JavaScript and CSS'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+I think one of the big new HTML features in the next years will be WebComponents. By using WebComponents developers can create fully-featured DOM elements as defined in the [web component spec](http://w3c.github.io/webcomponents/spec/custom/). In short this means that you can create your own HTML tags. If you want to add an avatar view to your web app you and use web components you can define a avatar component and then use the `` tag in your HTML file. To use web components today you can use one of the following libraries:
+
+* [bosonic](http://bosonic.github.io)
+* [polymer](https://www.polymer-project.org)
+* [x-tag](http://x-tags.org)
+
+I chose polymer to create my first web component and in this post I want to show you what I did to create a reusable custom HTML tag. Most likely this isn't a best practice tutorial because I currently starting to learn about this topic :)
+
+## Project setup
+
+As a first step I downloaded the polymer lib. To do so I used [bower](http://bower.io) that is a package manager for web development. With bower you can define all the library dependencies of a web application like you can do with Maven for Java apps.
+
+After you have installed bower on your system you need to execute the following commands in the folder of your web project:
+
+```shellbower init
+bower install --save Polymer/polymer
```
+
+This will create a `bower.json` file in your project and adds polymer as dependency. My file looks like this:
+
+```json{
+ "name": "polymer-test",
+ "version": "0.0.0",
+ "description": "A polymer playground",
+ "license": "MIT",
+ "keywords": [
+ "polymer",
+ "web-components"
+ ],
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components"
+ ],
+ "dependencies": {
+ "polymer": "Polymer/polymer#^0.4.1"
+ }
+}
```
+
+To download all dependencies you need to call
+
+```shellbower install
```
+
+This command will download all defined dependencies and install the in the `bower_components` folder in your project. When committing your project to git you can simply ignore this folder.
+
+If you don't want to use bower you can download and integrate the polymer lib by hand.
+
+As a next step you can create a `index.html` to test your custom components and a folder that will contain the components. Once this is done your application folder might look like this:
+
+
+
+## General structure of a WebComponent
+
+As said a web component is a custom control for web pages. Top define a component we only need one HTML file. As in other [languages or UT toolkits](/posts/2012-11-17-custom-ui-controls-with-javafx-part-1) a web component is composed of a layout definition, a style and controller logic. In the web world this means HTML (layout), CSS (style) and JavaScript (controller). By using polymer all 3 parts can combined in one file. Here is a skeleton for the file:
+
+```html
+
+
+
+
+ // contains the layout of the component in HTML
+
+
+
+
+
+
+
+
```
+
+As you can see the code starts with an import. Each custom component must import the `polymer.html` file. Thanks to bower this is already in the `bower_components` folder and can simply be imported. The `polymer-element` tag describes the web component. In the tag there are 3 more tags that describes the layout (template), the style (style) and the controller of the component (script). The `polymer-element` tag has some attributes that describes the name of our component and its attributes.
+
+To create a small web component you don't need to define all 3 inner tags but some basics are needed to display the component in a browser.
+
+## Defining the first component
+
+As a start we want to create a minimal web component that will only print an "A" on screen. To do so we create the "Simple-A.html" file in the components folder and add the following content:
+
+```html
+
+
+
+
+
A
+
+
+
+
+
```
+
+As far as I know is this the minimum definition that you need to define a component. In the template a paragraph that contains an "A" is defined. This is default HTML and if we don't want to create a reusable component we could write this directly in an HTML file. In the script section the Polymer({}); call registers the component so it's recognized by the browser. Once this is done the component can be used in any HTML file to render the "A" paragraph on screen:
+
+
+
+## Use the component
+
+To include the custom web component in a HTML page you need to import it. In addition the polymer platform lib must included to the page. Here is the code of a HTML page that includes everything and adds the "A" paragraph component several times to the body of the page:
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+As you can see in the code the html files that defines the custom component is imported in the web page. Once this is done the custom tag `` can be used in the web page. When having a look at the web developer tools of safari you can see that the A tags are now part of the page:
+
+
+
+## Browser support
+
+I tested my HTML file on Safari, Chrome and Firefox. Safari and Firefox work fine but on Chrome I don't see anything. The web console shows a "Cross-Origin Resource Sharing" so maybe it will work when running the page on a web server instead of just opening the file from the filesystem. I'm not a web expert so maybe Chrome has the correct behavior here. I will check this later and blog about it in my next web component post. After all by doing the most simply try and opening the HTML file with the browsers that re installed on my system this is the result of the browser check:
+
+
+
+## Conclusion
+
+It was very easy to create the first web component. As a next step I will try attributes for the components and some JavaScript logic. I will block about it as fast as possible.
diff --git a/content/posts/2014-11-13-hand-drawing-effect-javafx.md b/content/posts/2014-11-13-hand-drawing-effect-javafx.md
index 55071b64..d60659a8 100644
--- a/content/posts/2014-11-13-hand-drawing-effect-javafx.md
+++ b/content/posts/2014-11-13-hand-drawing-effect-javafx.md
@@ -1,117 +1,115 @@
----
-outdated: true
-showInBlog: false
-title: 'Hand drawing effect with JavaFX'
-date: "2014-11-13"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'In this post I show how you can create JavaFX shapes that look like they are hand drawn'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Some days ago Thierry Wasylczenko blogged about [12 of his favorite JS libs](http://zeroturnaround.com/rebellabs/javascript-confessions-12-js-technologies-im-not-ashamed-of-loving/). On of the libs is [js-sequence-diagrams](http://bramp.github.io/js-sequence-diagrams/) that I did know. By using the library you can draw sequence diagrams in a browser. I really like the hand drawn theme of the tool that draw all the diagrams like they are sketched with a pen. Here is an example of the theme:
-
-
-
-After having a look at the [source code](https://github.com/bramp/js-sequence-diagrams/blob/master/src/sequence-diagram.js) of js-sequence-diagrams I found the methods that render all the hand drawn lines. Cubic curves are used here and the control points of the curves are calculated by using random values. These two control points define the bend of the curve as you can see in the following picture:
-
-
-
-Once I've seen this I wanted to try if I can do the same with JavaFX :)
-
-Thankfully JavaFX contains support for cubic curves. The [Path](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/Path.html) shape can contain curves that can be defined by the [CubicCurveTo](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/CubicCurveTo.html) class. By using this class you can create lines and shapes that look like hand drawn onces by using the same algorithm as in js-sequence-diagrams. I created a simple test class that draws some arrows, lines and rectangles by using this algorithm. Here are some results:
-
-
-
-
-
-
-
-
-
-As you can see in the picture the shapes look different in each of them. This is caused by the random values that are part of the algorithm. If you want to try this here is my one class gist that contains all the code:
-
-{{< highlight java >}}
-package com.guigarage.incubator.wobble;
-
-import javafx.application.Application;
-import javafx.geometry.Point2D;
-import javafx.scene.Group;
-import javafx.scene.Scene;
-import javafx.scene.paint.Color;
-import javafx.scene.shape.*;
-import javafx.stage.Stage;
-
-public class WobbleTest extends Application {
-
- public static void main(String... args) {
- launch(args);
- }
-
- @Override
- public void start(Stage primaryStage) throws Exception {
-
- Group group = new Group();
- group.getChildren().add(createHandDrawnRect(10, 10, 100, 100, 2, Color.BLACK));
- group.getChildren().add(createHandDrawnRect(100, 150, 450, 40, 2, Color.BLACK));
- group.getChildren().add(createHandDrawnRect(150, 10, 100, 100, 2, Color.BLACK));
-
- group.getChildren().add(createHandDrawnArrow(100, 100, 160, 160, 2, Color.BLACK));
-
-
- primaryStage.setScene(new Scene(group));
- primaryStage.show();
- }
-
- public Shape createHandDrawnRect(double x1, double y1, double w, double h, double strokeWidth, Color color) {
- Shape top = createHandDrawnLine(x1, y1, x1 + w, y1, strokeWidth, color);
- Shape bottom = createHandDrawnLine(x1, y1 + h, x1 + w, y1 + h, strokeWidth, color);
- Shape left = createHandDrawnLine(x1, y1, x1, y1 + h, strokeWidth, color);
- Shape right = createHandDrawnLine(x1 + w, y1, x1 + w, y1 + h, strokeWidth, color);
- return Shape.union(top, Shape.union(bottom, Shape.union(left, right)));
- }
-
- public Shape createHandDrawnArrow(double x1, double y1, double x2, double y2, double strokeWidth, Color color) {
- Shape line = createHandDrawnLine(x1, y1, x2, y2, strokeWidth, color);
-
- double arrowlenght = strokeWidth * 5;
- double distance = Math.sqrt(Math.pow(x2 -x1, 2) + Math.pow(y2 -y1, 2));
- double unrotatedX = x2 + ((x1 - x2) / distance) * arrowlenght;
- double unrotatedY = y2 + ((y1 - y2) / distance) * arrowlenght;
-
- Point2D rotated1 = new Point2D(x2 + (unrotatedX - x2)*Math.cos(0.5) - (unrotatedY - y2)*Math.sin(0.5), y2 + (unrotatedX - x2)*Math.sin(0.5) + (unrotatedY - y2)*Math.cos(0.5));
- Shape arrowLeft = createHandDrawnLine(x2, y2, rotated1.getX(), rotated1.getY(), strokeWidth, color);
-
- Point2D rotated2 = new Point2D(x2 + (unrotatedX - x2)*Math.cos(-0.5) - (unrotatedY - y2)*Math.sin(-0.5), y2 + (unrotatedX - x2)*Math.sin(-0.5) + (unrotatedY - y2)*Math.cos(-0.5));
- Shape arrowRight = createHandDrawnLine(x2, y2, rotated2.getX(), rotated2.getY(), strokeWidth, color);
- return Shape.union(line, Shape.union(arrowLeft, arrowRight));
- }
-
- public Shape createHandDrawnLine(double x1, double y1, double x2, double y2, double strokeWidth, Color color) {
- Point2D startPoint = new Point2D(x1, y1);
- Point2D endPoint = new Point2D(x2, y2);
-
- double wobble = Math.sqrt((endPoint.getX() - startPoint.getX()) * (endPoint.getX() - startPoint.getX()) + (endPoint.getY() - startPoint.getY()) * (endPoint.getY() - startPoint.getY())) / 25;
-
- double r1 = Math.random();
- double r2 = Math.random();
-
- double xfactor = Math.random() > 0.5 ? wobble : -wobble;
- double yfactor = Math.random() > 0.5 ? wobble : -wobble;
-
- Point2D control1 = new Point2D((endPoint.getX() - startPoint.getX()) * r1 + startPoint.getX() + xfactor, (endPoint.getY() - startPoint.getY()) * r1 + startPoint.getY() + yfactor);
- Point2D control2 = new Point2D((endPoint.getX() - startPoint.getX()) * r2 + startPoint.getX() - xfactor, (endPoint.getY() - startPoint.getY()) * r2 + startPoint.getY() - yfactor);
-
- MoveTo startMove = new MoveTo(startPoint.getX(), startPoint.getY());
- CubicCurveTo curve = new CubicCurveTo(control1.getX(), control1.getY(),
- control2.getX(), control2.getY(),
- endPoint.getX(), endPoint.getY());
-
- Path path = new Path(startMove, curve);
- path.setStrokeLineCap(StrokeLineCap.ROUND);
- path.setStroke(color);
- path.setStrokeWidth(strokeWidth + (strokeWidth * (Math.random() - 0.5) / 8.0));
- path.setStrokeType(StrokeType.CENTERED);
- return path;
- }
-}
-{{< / highlight >}}
+---
+outdated: true
+showInBlog: false
+title: 'Hand drawing effect with JavaFX'
+date: "2014-11-13"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'In this post I show how you can create JavaFX shapes that look like they are hand drawn'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Some days ago Thierry Wasylczenko blogged about [12 of his favorite JS libs](http://zeroturnaround.com/rebellabs/javascript-confessions-12-js-technologies-im-not-ashamed-of-loving/). On of the libs is [js-sequence-diagrams](http://bramp.github.io/js-sequence-diagrams/) that I did know. By using the library you can draw sequence diagrams in a browser. I really like the hand drawn theme of the tool that draw all the diagrams like they are sketched with a pen. Here is an example of the theme:
+
+
+
+After having a look at the [source code](https://github.com/bramp/js-sequence-diagrams/blob/master/src/sequence-diagram.js) of js-sequence-diagrams I found the methods that render all the hand drawn lines. Cubic curves are used here and the control points of the curves are calculated by using random values. These two control points define the bend of the curve as you can see in the following picture:
+
+
+
+Once I've seen this I wanted to try if I can do the same with JavaFX :)
+
+Thankfully JavaFX contains support for cubic curves. The [Path](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/Path.html) shape can contain curves that can be defined by the [CubicCurveTo](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/CubicCurveTo.html) class. By using this class you can create lines and shapes that look like hand drawn onces by using the same algorithm as in js-sequence-diagrams. I created a simple test class that draws some arrows, lines and rectangles by using this algorithm. Here are some results:
+
+
+
+
+
+
+
+
+
+As you can see in the picture the shapes look different in each of them. This is caused by the random values that are part of the algorithm. If you want to try this here is my one class gist that contains all the code:
+
+```javapackage com.guigarage.incubator.wobble;
+
+import javafx.application.Application;
+import javafx.geometry.Point2D;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.*;
+import javafx.stage.Stage;
+
+public class WobbleTest extends Application {
+
+ public static void main(String... args) {
+ launch(args);
+ }
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+
+ Group group = new Group();
+ group.getChildren().add(createHandDrawnRect(10, 10, 100, 100, 2, Color.BLACK));
+ group.getChildren().add(createHandDrawnRect(100, 150, 450, 40, 2, Color.BLACK));
+ group.getChildren().add(createHandDrawnRect(150, 10, 100, 100, 2, Color.BLACK));
+
+ group.getChildren().add(createHandDrawnArrow(100, 100, 160, 160, 2, Color.BLACK));
+
+
+ primaryStage.setScene(new Scene(group));
+ primaryStage.show();
+ }
+
+ public Shape createHandDrawnRect(double x1, double y1, double w, double h, double strokeWidth, Color color) {
+ Shape top = createHandDrawnLine(x1, y1, x1 + w, y1, strokeWidth, color);
+ Shape bottom = createHandDrawnLine(x1, y1 + h, x1 + w, y1 + h, strokeWidth, color);
+ Shape left = createHandDrawnLine(x1, y1, x1, y1 + h, strokeWidth, color);
+ Shape right = createHandDrawnLine(x1 + w, y1, x1 + w, y1 + h, strokeWidth, color);
+ return Shape.union(top, Shape.union(bottom, Shape.union(left, right)));
+ }
+
+ public Shape createHandDrawnArrow(double x1, double y1, double x2, double y2, double strokeWidth, Color color) {
+ Shape line = createHandDrawnLine(x1, y1, x2, y2, strokeWidth, color);
+
+ double arrowlenght = strokeWidth * 5;
+ double distance = Math.sqrt(Math.pow(x2 -x1, 2) + Math.pow(y2 -y1, 2));
+ double unrotatedX = x2 + ((x1 - x2) / distance) * arrowlenght;
+ double unrotatedY = y2 + ((y1 - y2) / distance) * arrowlenght;
+
+ Point2D rotated1 = new Point2D(x2 + (unrotatedX - x2)*Math.cos(0.5) - (unrotatedY - y2)*Math.sin(0.5), y2 + (unrotatedX - x2)*Math.sin(0.5) + (unrotatedY - y2)*Math.cos(0.5));
+ Shape arrowLeft = createHandDrawnLine(x2, y2, rotated1.getX(), rotated1.getY(), strokeWidth, color);
+
+ Point2D rotated2 = new Point2D(x2 + (unrotatedX - x2)*Math.cos(-0.5) - (unrotatedY - y2)*Math.sin(-0.5), y2 + (unrotatedX - x2)*Math.sin(-0.5) + (unrotatedY - y2)*Math.cos(-0.5));
+ Shape arrowRight = createHandDrawnLine(x2, y2, rotated2.getX(), rotated2.getY(), strokeWidth, color);
+ return Shape.union(line, Shape.union(arrowLeft, arrowRight));
+ }
+
+ public Shape createHandDrawnLine(double x1, double y1, double x2, double y2, double strokeWidth, Color color) {
+ Point2D startPoint = new Point2D(x1, y1);
+ Point2D endPoint = new Point2D(x2, y2);
+
+ double wobble = Math.sqrt((endPoint.getX() - startPoint.getX()) * (endPoint.getX() - startPoint.getX()) + (endPoint.getY() - startPoint.getY()) * (endPoint.getY() - startPoint.getY())) / 25;
+
+ double r1 = Math.random();
+ double r2 = Math.random();
+
+ double xfactor = Math.random() > 0.5 ? wobble : -wobble;
+ double yfactor = Math.random() > 0.5 ? wobble : -wobble;
+
+ Point2D control1 = new Point2D((endPoint.getX() - startPoint.getX()) * r1 + startPoint.getX() + xfactor, (endPoint.getY() - startPoint.getY()) * r1 + startPoint.getY() + yfactor);
+ Point2D control2 = new Point2D((endPoint.getX() - startPoint.getX()) * r2 + startPoint.getX() - xfactor, (endPoint.getY() - startPoint.getY()) * r2 + startPoint.getY() - yfactor);
+
+ MoveTo startMove = new MoveTo(startPoint.getX(), startPoint.getY());
+ CubicCurveTo curve = new CubicCurveTo(control1.getX(), control1.getY(),
+ control2.getX(), control2.getY(),
+ endPoint.getX(), endPoint.getY());
+
+ Path path = new Path(startMove, curve);
+ path.setStrokeLineCap(StrokeLineCap.ROUND);
+ path.setStroke(color);
+ path.setStrokeWidth(strokeWidth + (strokeWidth * (Math.random() - 0.5) / 8.0));
+ path.setStrokeType(StrokeType.CENTERED);
+ return path;
+ }
+}
```
diff --git a/content/posts/2015-01-19-concurrency-ui-toolkits-part-1.md b/content/posts/2015-01-19-concurrency-ui-toolkits-part-1.md
index e36b9fdf..92fcf9ab 100644
--- a/content/posts/2015-01-19-concurrency-ui-toolkits-part-1.md
+++ b/content/posts/2015-01-19-concurrency-ui-toolkits-part-1.md
@@ -1,125 +1,106 @@
----
-outdated: true
-showInBlog: false
-title: 'Concurrency in UI Toolkits (Part 1)'
-date: "2015-01-19"
-author: hendrik
-categories: [Desktop Application Framework (JSR 377), JavaFX]
-excerpt: 'This post describes how the Concurrency in UI Toolkits can be defined in a unified way.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Today every UI toolkit that is not running in a browser needs an UI Thread the handle the repainting and the event handling of the UI. Examples for this kinds of UI Toolkits are iOS, Android, SWT, JavaFX or Swing. Each of this toolkits defines a thread that will handle all the ui specific calls. Let's call this thread "UI Thread".
-
-
-
-By definition all calls that will affect the UI or get data of the UI must be called on this thread. Accessing the UI from another thread than the UI Thread will result in a lot of different problems.
-
-Normally all user events that are handled by the toolkit will be called on the UI thread. Therefore an event handler will be called on the thread, too. If a developer wants to interact with UI components as a result of an user event he can do this directly in the handler. The following code shows some pseudo code how this might look. Normally each UI Toolkits provide it's own mechanism for event handling.
-
-{{< highlight java >}}
-button.setOnAction(event -> button.setEnabled(false));
-{{< / highlight >}}
-
-If you want to interact with the UI from outside of an event you need to invoke your code on the "UI Thread".
-
-
-
-Each UI Toolkit provides a helper method to handle this invocation. In a UI Toolkit independent and unified way this method might look like this:
-
-{{< highlight java >}}
-void runOnUiToolkitThread(Runnable runnable);
-{{< / highlight >}}
-
-By doing so any runnable can be called on the UI Thread. This is ok for some general use cases but it's definitely not enough to create an big application. One of the big problems is that you don't know when the code will be called and when the call is finished. The definition of this method only says that the code will be called in some future on the UI Thread. Therefore we need a second method that blocks until the call is finished.
-
-
-
-In most cases this method will have the same signature as the previous one. Let's define the method in a unified way:
-
-{{< highlight java >}}
-void runOnUiToolkitThreadAndWait(Runnable runnable);
-{{< / highlight >}}
-
-Thanks to Java 8 we can define this method as a default method based on the other one:
-
-{{< highlight java >}}
-default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
- FutureTask future = new FutureTask<>(runnable, null);
- runOnUiToolkitThread(future);
- future.get();
-}
-{{< / highlight >}}
-
-This looks good so far but there is still a problem. As said the UI must only be accessed by using the UI Thread. Let's think about a background thread that want's to call a web service based on some user input. To do so the thread needs to know the input of a textfield, for example. Because we can't access the text from the background thread we need to invoke the call to the UI Thread:
-
-
-
-The following code shows how such a call might look like:
-
-{{< highlight java >}}
-public void runningOnBackgroundThread() {
- String userInput = runOnUiToolkitThreadAndWait(() -> textfield.getText());
- callWebservice(userInput);
-}
-{{< / highlight >}}
-
-To do so we need another helper method:
-
-{{< highlight java >}}
- T runOnUiToolkitThreadAndWait(Callable callable);
-{{< / highlight >}}
-
-In addition we can provide a method that won't block until the call is finished:
-
-{{< highlight java >}}
- Provider runOnUiToolkitThread(Callable callable);
-{{< / highlight >}}
-
-Now we have a set of methods that can be used to interact with the UI Thread:
-
-{{< highlight java >}}
-
-public interface UIThread {
-
- void runOnUiToolkitThread(Runnable runnable);
-
- Provider runOnUiToolkitThread(Callable callable);
-
- void runOnUiToolkitThreadAndWait(Runnable runnable);
-
- T runOnUiToolkitThreadAndWait(Callable callable);
-
-}
-{{< / highlight >}}
-
-Let's have a deeper look how we can implement this methods by using default methods:
-
-{{< highlight java >}}
-public interface UIThread {
-
- void runOnUiToolkitThread(Runnable runnable);
-
- default Future runOnUiToolkitThread(Callable callable) {
- FutureTask future = new FutureTask<>(callable);
- runOnUiToolkitThread(future);
- return future;
- }
-
- default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
- runOnUiToolkitThread((Callable)() -> {
- runnable.run();
- return null;
- }).get();
- }
-
- default T runOnUiToolkitThreadAndWait(Callable callable) throws InterruptedException, ExecutionException {
- return runOnUiToolkitThread(callable).get();
- }
-}
-{{< / highlight >}}
-
-As you can see there are 2 differences to the basic interface definition. First we need to throw some exceptions because calling the get() method of a Future instance will throw exceptions. These exceptions are needed. Let's think your runnable call that accesses the UI will contain an error and throws an exception. In this case you want to know about the error when checking the result of the call. As a next change the Provider result type of one method is changed to Future. Internally a Future is used that can't be casted to the Provider interface. In addition a Provider won't define the needed Exceptions as described earlier.
-
-## Conclusion
-
-The defined interface contains only one method that needs to be implemented in a UI Toolkit specific way to create some helper methods. This is a good start but some of you might know, that there are still some problems in this methods. Maybe you call a *AndWait(..) method from the UI Thread. This will maybe end in a deadlock. In addition the Future interface defines the method "boolean cancel(boolean mayInterruptIfRunning)". What happens if we call this on a task that is executed by the UI Thread? This issues will be discussed in the next post.
+---
+outdated: true
+showInBlog: false
+title: 'Concurrency in UI Toolkits (Part 1)'
+date: "2015-01-19"
+author: hendrik
+categories: [Desktop Application Framework (JSR 377), JavaFX]
+excerpt: 'This post describes how the Concurrency in UI Toolkits can be defined in a unified way.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Today every UI toolkit that is not running in a browser needs an UI Thread the handle the repainting and the event handling of the UI. Examples for this kinds of UI Toolkits are iOS, Android, SWT, JavaFX or Swing. Each of this toolkits defines a thread that will handle all the ui specific calls. Let's call this thread "UI Thread".
+
+
+
+By definition all calls that will affect the UI or get data of the UI must be called on this thread. Accessing the UI from another thread than the UI Thread will result in a lot of different problems.
+
+Normally all user events that are handled by the toolkit will be called on the UI thread. Therefore an event handler will be called on the thread, too. If a developer wants to interact with UI components as a result of an user event he can do this directly in the handler. The following code shows some pseudo code how this might look. Normally each UI Toolkits provide it's own mechanism for event handling.
+
+```javabutton.setOnAction(event -> button.setEnabled(false));
```
+
+If you want to interact with the UI from outside of an event you need to invoke your code on the "UI Thread".
+
+
+
+Each UI Toolkit provides a helper method to handle this invocation. In a UI Toolkit independent and unified way this method might look like this:
+
+```javavoid runOnUiToolkitThread(Runnable runnable);
```
+
+By doing so any runnable can be called on the UI Thread. This is ok for some general use cases but it's definitely not enough to create an big application. One of the big problems is that you don't know when the code will be called and when the call is finished. The definition of this method only says that the code will be called in some future on the UI Thread. Therefore we need a second method that blocks until the call is finished.
+
+
+
+In most cases this method will have the same signature as the previous one. Let's define the method in a unified way:
+
+```javavoid runOnUiToolkitThreadAndWait(Runnable runnable);
```
+
+Thanks to Java 8 we can define this method as a default method based on the other one:
+
+```javadefault void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
+ FutureTask future = new FutureTask<>(runnable, null);
+ runOnUiToolkitThread(future);
+ future.get();
+}
```
+
+This looks good so far but there is still a problem. As said the UI must only be accessed by using the UI Thread. Let's think about a background thread that want's to call a web service based on some user input. To do so the thread needs to know the input of a textfield, for example. Because we can't access the text from the background thread we need to invoke the call to the UI Thread:
+
+
+
+The following code shows how such a call might look like:
+
+```javapublic void runningOnBackgroundThread() {
+ String userInput = runOnUiToolkitThreadAndWait(() -> textfield.getText());
+ callWebservice(userInput);
+}
```
+
+To do so we need another helper method:
+
+```java T runOnUiToolkitThreadAndWait(Callable callable);
```
+
+In addition we can provide a method that won't block until the call is finished:
+
+```java Provider runOnUiToolkitThread(Callable callable);
```
+
+Now we have a set of methods that can be used to interact with the UI Thread:
+
+```javapublic interface UIThread {
+
+ void runOnUiToolkitThread(Runnable runnable);
+
+ Provider runOnUiToolkitThread(Callable callable);
+
+ void runOnUiToolkitThreadAndWait(Runnable runnable);
+
+ T runOnUiToolkitThreadAndWait(Callable callable);
+
+}
```
+
+Let's have a deeper look how we can implement this methods by using default methods:
+
+```javapublic interface UIThread {
+
+ void runOnUiToolkitThread(Runnable runnable);
+
+ default Future runOnUiToolkitThread(Callable callable) {
+ FutureTask future = new FutureTask<>(callable);
+ runOnUiToolkitThread(future);
+ return future;
+ }
+
+ default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
+ runOnUiToolkitThread((Callable)() -> {
+ runnable.run();
+ return null;
+ }).get();
+ }
+
+ default T runOnUiToolkitThreadAndWait(Callable callable) throws InterruptedException, ExecutionException {
+ return runOnUiToolkitThread(callable).get();
+ }
+}
```
+
+As you can see there are 2 differences to the basic interface definition. First we need to throw some exceptions because calling the get() method of a Future instance will throw exceptions. These exceptions are needed. Let's think your runnable call that accesses the UI will contain an error and throws an exception. In this case you want to know about the error when checking the result of the call. As a next change the Provider result type of one method is changed to Future. Internally a Future is used that can't be casted to the Provider interface. In addition a Provider won't define the needed Exceptions as described earlier.
+
+## Conclusion
+
+The defined interface contains only one method that needs to be implemented in a UI Toolkit specific way to create some helper methods. This is a good start but some of you might know, that there are still some problems in this methods. Maybe you call a *AndWait(..) method from the UI Thread. This will maybe end in a deadlock. In addition the Future interface defines the method "boolean cancel(boolean mayInterruptIfRunning)". What happens if we call this on a task that is executed by the UI Thread? This issues will be discussed in the next post.
diff --git a/content/posts/2015-01-21-support-emojis.md b/content/posts/2015-01-21-support-emojis.md
index 35da1841..2800c2d5 100644
--- a/content/posts/2015-01-21-support-emojis.md
+++ b/content/posts/2015-01-21-support-emojis.md
@@ -1,96 +1,90 @@
----
-outdated: true
-showInBlog: false
-title: 'How to support Emojis (Part1)'
-date: "2015-01-21"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'The post shows how emojis can be supported in (JavaFX) applications'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Mostly all mobile application support __emojis__ since some years. Later browsers and applications like twitter added global support for emojis. I think it's time to have a deeper look at this funny icons and how a software can make use of them.
-
-
-
-## Emojis and unicode
-
-Let's start with a fact that is a big benefit when working with emojis: Since 2010 all the emoji icons that you know from your favorite chat application are __standardized in the unicode standard__. The unicode standard defines more than 700 emojis. This means that each emoji is defined as a unicode character and has its unique unicode code:
-
-
-
-In the picture above the icons that you might know from apple devices are used to visualize the emojis. But unicode doesn't define the look of the icons. The unicode standard only defines the expression of the emoji as you can see in the official unicode documentation ([example](http://www.unicode.org/charts/PDF/U1F600.pdf)):
-
-
-
-Because the emojis are defined as unicode chars the can be part of any String or character array that supports unicode. For example in Java the String object supports unicode and therefore a String can contain emoji chars. Now the big question is: How can we add a emoji character to a String? On a normal desktop PC we don't have emojis on the keyboard :(
-
-There are different ways how you can type any unicode character with a keyboard ([windows tutorial](http://www.fileformat.info/tip/microsoft/enter_unicode.htm)). If you are a mac user there is a very fast and easy way:
-
-The "Messages" app supports emojis like you know it from an iPhone. Here you can simple add emojis and copy&paste them in any other application. Here is a short video that shows the handling:
-
-{{< youtube ihVJn4C3SzI >}}
-
-## Emojis in JavaFX
-
-This successful test shows that the operation system supports emojis. Let's try Java as a next step. To do so I created a small and easy JavaFX application that contains only a simple TextField:
-
-{{< highlight java >}}
-public class EmojiTest extends Application {
-
- @Override
- public void start(Stage primaryStage) throws Exception {
- TextField textField = new TextField();
- primaryStage.setScene(new Scene(new StackPane(textField)));
- primaryStage.show();
- }
-
- public static void main(String... args) {
- launch(args);
- }
-}
-{{< / highlight >}}
-
-Once the application is running we can do the same as before: Create a text with emoji chars, copy the text and past it into the JavaFX textfield:
-
-
-
-As you can see in the image something went terrible wrong. We don't see any smileys in the textfield. Instead of the emojis some strange characters appeared. Does this mean that JavaFX doesn't support emojis?
-
-
-
-## Emojis and fonts
-
-You shouldn't be scared ;) JavaFX isn't the problem. The strange issue is based on the font of the textfield. Let's think about the functionality of a font: it interprets a character and draws a (vector based) icon for the char on the screen. In the example no specify font is defined for the textfield. Therefore the default font will be used that is "Lucida Grande" on a Mac ([see this post for more details](http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-August/009912.html)). Lucida Grande doesn't contain a visual representation for the emoji unicode characters and therefore the strange icons will be shown. Th show emojis on the screen we need a font that supports them. One open source font that supports emojis is OpenSansEmoji. The font can be found at [github](https://github.com/MorbZ/OpenSansEmoji). Once you downloaded the font you can define it for your textfield [as described in an earlier post]({{< ref "/posts/2014-10-01-integrate-custom-fonts-javafx-application-using-css" >}}):
-
-{{< highlight java >}}
-@font-face {
- font-family: 'OpenSansEmoji';
- src: url('OpenSansEmoji.ttf');
-}
-
-.text-field {
- -fx-font-family: OpenSansEmoji;
- -fx-font-size: 32;
-}
-{{< / highlight >}}
-
-Once this is done we can use emojis in JavaFX applications - but only on windows without problems. On Mac OS there is a bug in the os depended clipboard code. Therefore you can't paste any text with emojis in a JavaFX textfield. I will describe this problem in detail later. Let's add a emoji character directly in code to the textfield. This will work on any OS.
-
-## Emojis and UTF-8
-
-As you can see [on this page](http://apps.timwhitlock.info/emoji/tables/unicode) a emoji is defined by 4 bytes in UTF-8. In Java all Strings are defined in UTF-8 by default and therefore we need to define a emoji this way:
-
-{{< highlight java >}}
-byte[] emojiBytes = new byte[]{(byte)0xF0, (byte)0x9F, (byte)0x98, (byte)0x81};
-String emojiAsString = new String(emojiBytes, Charset.forName("UTF-8"));
-{{< / highlight >}}
-
-This code will create a string that contains the grinning emoji as you can see in the overview:
-
-
-
-Once this is done the emoji will be shown in the textfield and can simply be copied to any other application that supports emojis:
-
-
-
-The last posts ([like this one]({{< ref "/posts/2015-01-19-concurrency-ui-toolkits-part-1" >}})) I'm working on are very long and therefore I decided to split them in several smaller ones. In the next post I will discuss the problem on Mac. In addition I will show how emojis can be simply added to a text.
+---
+outdated: true
+showInBlog: false
+title: 'How to support Emojis (Part1)'
+date: "2015-01-21"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'The post shows how emojis can be supported in (JavaFX) applications'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Mostly all mobile application support __emojis__ since some years. Later browsers and applications like twitter added global support for emojis. I think it's time to have a deeper look at this funny icons and how a software can make use of them.
+
+
+
+## Emojis and unicode
+
+Let's start with a fact that is a big benefit when working with emojis: Since 2010 all the emoji icons that you know from your favorite chat application are __standardized in the unicode standard__. The unicode standard defines more than 700 emojis. This means that each emoji is defined as a unicode character and has its unique unicode code:
+
+
+
+In the picture above the icons that you might know from apple devices are used to visualize the emojis. But unicode doesn't define the look of the icons. The unicode standard only defines the expression of the emoji as you can see in the official unicode documentation ([example](http://www.unicode.org/charts/PDF/U1F600.pdf)):
+
+
+
+Because the emojis are defined as unicode chars the can be part of any String or character array that supports unicode. For example in Java the String object supports unicode and therefore a String can contain emoji chars. Now the big question is: How can we add a emoji character to a String? On a normal desktop PC we don't have emojis on the keyboard :(
+
+There are different ways how you can type any unicode character with a keyboard ([windows tutorial](http://www.fileformat.info/tip/microsoft/enter_unicode.htm)). If you are a mac user there is a very fast and easy way:
+
+The "Messages" app supports emojis like you know it from an iPhone. Here you can simple add emojis and copy&paste them in any other application. Here is a short video that shows the handling:
+
+
+
+## Emojis in JavaFX
+
+This successful test shows that the operation system supports emojis. Let's try Java as a next step. To do so I created a small and easy JavaFX application that contains only a simple TextField:
+
+```javapublic class EmojiTest extends Application {
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ TextField textField = new TextField();
+ primaryStage.setScene(new Scene(new StackPane(textField)));
+ primaryStage.show();
+ }
+
+ public static void main(String... args) {
+ launch(args);
+ }
+}
```
+
+Once the application is running we can do the same as before: Create a text with emoji chars, copy the text and past it into the JavaFX textfield:
+
+
+
+As you can see in the image something went terrible wrong. We don't see any smileys in the textfield. Instead of the emojis some strange characters appeared. Does this mean that JavaFX doesn't support emojis?
+
+
+
+## Emojis and fonts
+
+You shouldn't be scared ;) JavaFX isn't the problem. The strange issue is based on the font of the textfield. Let's think about the functionality of a font: it interprets a character and draws a (vector based) icon for the char on the screen. In the example no specify font is defined for the textfield. Therefore the default font will be used that is "Lucida Grande" on a Mac ([see this post for more details](http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-August/009912.html)). Lucida Grande doesn't contain a visual representation for the emoji unicode characters and therefore the strange icons will be shown. Th show emojis on the screen we need a font that supports them. One open source font that supports emojis is OpenSansEmoji. The font can be found at [github](https://github.com/MorbZ/OpenSansEmoji). Once you downloaded the font you can define it for your textfield [as described in an earlier post](/posts/2014-10-01-integrate-custom-fonts-javafx-application-using-css):
+
+```java@font-face {
+ font-family: 'OpenSansEmoji';
+ src: url('OpenSansEmoji.ttf');
+}
+
+.text-field {
+ -fx-font-family: OpenSansEmoji;
+ -fx-font-size: 32;
+}
```
+
+Once this is done we can use emojis in JavaFX applications - but only on windows without problems. On Mac OS there is a bug in the os depended clipboard code. Therefore you can't paste any text with emojis in a JavaFX textfield. I will describe this problem in detail later. Let's add a emoji character directly in code to the textfield. This will work on any OS.
+
+## Emojis and UTF-8
+
+As you can see [on this page](http://apps.timwhitlock.info/emoji/tables/unicode) a emoji is defined by 4 bytes in UTF-8. In Java all Strings are defined in UTF-8 by default and therefore we need to define a emoji this way:
+
+```javabyte[] emojiBytes = new byte[]{(byte)0xF0, (byte)0x9F, (byte)0x98, (byte)0x81};
+String emojiAsString = new String(emojiBytes, Charset.forName("UTF-8"));
```
+
+This code will create a string that contains the grinning emoji as you can see in the overview:
+
+
+
+Once this is done the emoji will be shown in the textfield and can simply be copied to any other application that supports emojis:
+
+
+
+The last posts ([like this one](/posts/2015-01-19-concurrency-ui-toolkits-part-1)) I'm working on are very long and therefore I decided to split them in several smaller ones. In the next post I will discuss the problem on Mac. In addition I will show how emojis can be simply added to a text.
diff --git a/content/posts/2015-01-22-datafx-tutorial-6.md b/content/posts/2015-01-22-datafx-tutorial-6.md
index 2741ee1a..ddb15680 100644
--- a/content/posts/2015-01-22-datafx-tutorial-6.md
+++ b/content/posts/2015-01-22-datafx-tutorial-6.md
@@ -1,136 +1,126 @@
----
-outdated: true
-showInBlog: false
-title: 'DataFX Tutorial 6'
-date: "2015-01-22"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'In this tutorial I want to show how dynamic actions can be handled in DataFX.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this tutorial I want to show how dynamic actions can be handled in DataFX. In all the last tutorials the actions are defined in the flow configuration or by using annotations. By doing so you can't dynamically choose which action should be called when clicking a button for example. To do so DataFX provides the FlowActionHandler class. This class provides methods to call DataFX actions directly in code. Here are some examples:
-
-{{< highlight java >}}
-flowActionHandler.handle("actionId");
-flowActionHandler.navigate(NextController.class);
-flowActionHandler.navigateBack();
-{{< / highlight >}}
-
-As you can see the FlowActionHandler class provides methods for all the action types that are supported in DataFX by using annotations or the flow configuration.
-
-Normally you want to use the FlowActionHandler inside of a view to call dynamic actions based on a user interaction. To do so DataFX provides the @ActionHandler annotation that can be used to inject the FlowActionHandler in a view controller. Here is a small example how this will look:
-
-{{< highlight java >}}
-@ViewController("view.fxml")
-public class MyController {
-
- @ActionHandler
- protected FlowActionHandler actionHandler;
-
- public void doSomething() {
- actionHandler.handle("actionId");
- //or
- actionHandler.navigate(NextController.class);
- }
-}
-{{< / highlight >}}
-
-As you can see it is really easy to call DataFX actions in code. As a next step we want to create a small application that uses this features.
-
-Let's say we have a main view and 3 sub views. In the main view you can choose by using radio buttons to which view you want to navigate.
-
-
-
-To do so we create a controller with the "navigate" buttons and the radio buttons. As a next step we need to define a ToggleGroup for all the radio buttons. This group manages the RadioButton instances. By doing so you can only select one RadioButton. This is a JavaFX basic feature. If you want to now more about RadioButtons and ToggleGroups you should [buy this book]({{ site.baseurl }}{% link pages/mastering-javafx-controls.md %}) or visit this training. After this is done the controller should look like this:
-
-{{< highlight java >}}
-@ViewController("main.fxml")
-public class MainController {
-
- @ViewNode
- private RadioButton radioButton1;
-
- @ViewNode
- private RadioButton radioButton2;
-
- @ViewNode
- private RadioButton radioButton3;
-
- @ViewNode
- @ActionTrigger("navigate")
- private Button navigateToButton;
-
- private ToggleGroup group;
-
- @PostConstruct
- public void init() throws FlowException {
- radioButton1.setUserData(View1Controller.class);
- radioButton2.setUserData(View2Controller.class);
- radioButton3.setUserData(View3Controller.class);
-
- group = new ToggleGroup();
- group.getToggles().addAll(radioButton1, radioButton2, radioButton3);
-
- radioButton1.setSelected(true);
- }
-}
-{{< / highlight >}}
-
-As you can see in the code I don't use the @FXML annotation. With DataFX 8 we introduced the @ViewNode annotation to inject components of the view in the controller. Basically this annotation can be used as the @FXML annotation but it provides more features. You can define the fx:id of the node as the value of the annotation, for example. By doing so your field must not have the same name as the node in the FXML file. Here is a short example how this can be used:
-
-{{< highlight java >}}
-@ViewNode("fx-id")
-private Button anyName;
-{{< / highlight >}}
-
-In addition the [JSR-377]({{< ref "/posts/2014-12-30-desktopembedded-application-api-jsr" >}}) is currently planned and this will introduce a UI Toolkit independent annotation to inject view components. DataFX will implement the JSR once it is released and therefor we started to define our own basic annotations. SO maybe the name of the annotation will change once the JSR is released.
-
-Once the controller is finished we need to add the action handler and navigate to the selected view. The RadioButtons instances in the controller define the controller classes for all the subviews as user data. By doing so we can simply navigate to the selected user data. Here is the final code for the controller:
-
-{{< highlight java >}}
-@ViewController("main.fxml")
-public class MainController {
-
- @ViewNode
- private RadioButton radioButton1;
-
- @ViewNode
- private RadioButton radioButton2;
-
- @ViewNode
- private RadioButton radioButton3;
-
- @ViewNode
- @ActionTrigger("navigate")
- private Button navigateToButton;
-
- @ActionHandler
- private FlowActionHandler actionHandler;
-
- private ToggleGroup group;
-
- @PostConstruct
- public void init() throws FlowException {
- radioButton1.setUserData(View1Controller.class);
- radioButton2.setUserData(View2Controller.class);
- radioButton3.setUserData(View3Controller.class);
-
- group = new ToggleGroup();
- group.getToggles().addAll(radioButton1, radioButton2, radioButton3);
-
- radioButton1.setSelected(true);
- }
-
-
- @ActionMethod("navigate")
- public void navigate() throws VetoException, FlowException {
- actionHandler.navigate((Class>) group.getSelectedToggle().getUserData());
- }
-}
-{{< / highlight >}}
-
-Once this is done you can select the wanted view in the UI and by clicking the "navigate" button the view will change to the selected one.
-
-
-
-All the view controllers for the subviews are defined as shown in earlier tutorials. You can find the complete code of the example [here](https://bitbucket.org/datafx/datafx/src/0352a3543b378d8bd37a5f7f25d3137525e3a761/modules/tutorials/?at=default).
+---
+outdated: true
+showInBlog: false
+title: 'DataFX Tutorial 6'
+date: "2015-01-22"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'In this tutorial I want to show how dynamic actions can be handled in DataFX.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this tutorial I want to show how dynamic actions can be handled in DataFX. In all the last tutorials the actions are defined in the flow configuration or by using annotations. By doing so you can't dynamically choose which action should be called when clicking a button for example. To do so DataFX provides the FlowActionHandler class. This class provides methods to call DataFX actions directly in code. Here are some examples:
+
+```javaflowActionHandler.handle("actionId");
+flowActionHandler.navigate(NextController.class);
+flowActionHandler.navigateBack();
```
+
+As you can see the FlowActionHandler class provides methods for all the action types that are supported in DataFX by using annotations or the flow configuration.
+
+Normally you want to use the FlowActionHandler inside of a view to call dynamic actions based on a user interaction. To do so DataFX provides the @ActionHandler annotation that can be used to inject the FlowActionHandler in a view controller. Here is a small example how this will look:
+
+```java@ViewController("view.fxml")
+public class MyController {
+
+ @ActionHandler
+ protected FlowActionHandler actionHandler;
+
+ public void doSomething() {
+ actionHandler.handle("actionId");
+ //or
+ actionHandler.navigate(NextController.class);
+ }
+}
```
+
+As you can see it is really easy to call DataFX actions in code. As a next step we want to create a small application that uses this features.
+
+Let's say we have a main view and 3 sub views. In the main view you can choose by using radio buttons to which view you want to navigate.
+
+
+
+To do so we create a controller with the "navigate" buttons and the radio buttons. As a next step we need to define a ToggleGroup for all the radio buttons. This group manages the RadioButton instances. By doing so you can only select one RadioButton. This is a JavaFX basic feature. If you want to now more about RadioButtons and ToggleGroups you should [buy this book]({{ site.baseurl }}{% link pages/mastering-javafx-controls.md %}) or visit this training. After this is done the controller should look like this:
+
+```java@ViewController("main.fxml")
+public class MainController {
+
+ @ViewNode
+ private RadioButton radioButton1;
+
+ @ViewNode
+ private RadioButton radioButton2;
+
+ @ViewNode
+ private RadioButton radioButton3;
+
+ @ViewNode
+ @ActionTrigger("navigate")
+ private Button navigateToButton;
+
+ private ToggleGroup group;
+
+ @PostConstruct
+ public void init() throws FlowException {
+ radioButton1.setUserData(View1Controller.class);
+ radioButton2.setUserData(View2Controller.class);
+ radioButton3.setUserData(View3Controller.class);
+
+ group = new ToggleGroup();
+ group.getToggles().addAll(radioButton1, radioButton2, radioButton3);
+
+ radioButton1.setSelected(true);
+ }
+}
```
+
+As you can see in the code I don't use the @FXML annotation. With DataFX 8 we introduced the @ViewNode annotation to inject components of the view in the controller. Basically this annotation can be used as the @FXML annotation but it provides more features. You can define the fx:id of the node as the value of the annotation, for example. By doing so your field must not have the same name as the node in the FXML file. Here is a short example how this can be used:
+
+```java@ViewNode("fx-id")
+private Button anyName;
```
+
+In addition the [JSR-377](/posts/2014-12-30-desktopembedded-application-api-jsr) is currently planned and this will introduce a UI Toolkit independent annotation to inject view components. DataFX will implement the JSR once it is released and therefor we started to define our own basic annotations. SO maybe the name of the annotation will change once the JSR is released.
+
+Once the controller is finished we need to add the action handler and navigate to the selected view. The RadioButtons instances in the controller define the controller classes for all the subviews as user data. By doing so we can simply navigate to the selected user data. Here is the final code for the controller:
+
+```java@ViewController("main.fxml")
+public class MainController {
+
+ @ViewNode
+ private RadioButton radioButton1;
+
+ @ViewNode
+ private RadioButton radioButton2;
+
+ @ViewNode
+ private RadioButton radioButton3;
+
+ @ViewNode
+ @ActionTrigger("navigate")
+ private Button navigateToButton;
+
+ @ActionHandler
+ private FlowActionHandler actionHandler;
+
+ private ToggleGroup group;
+
+ @PostConstruct
+ public void init() throws FlowException {
+ radioButton1.setUserData(View1Controller.class);
+ radioButton2.setUserData(View2Controller.class);
+ radioButton3.setUserData(View3Controller.class);
+
+ group = new ToggleGroup();
+ group.getToggles().addAll(radioButton1, radioButton2, radioButton3);
+
+ radioButton1.setSelected(true);
+ }
+
+
+ @ActionMethod("navigate")
+ public void navigate() throws VetoException, FlowException {
+ actionHandler.navigate((Class>) group.getSelectedToggle().getUserData());
+ }
+}
```
+
+Once this is done you can select the wanted view in the UI and by clicking the "navigate" button the view will change to the selected one.
+
+
+
+All the view controllers for the subviews are defined as shown in earlier tutorials. You can find the complete code of the example [here](https://bitbucket.org/datafx/datafx/src/0352a3543b378d8bd37a5f7f25d3137525e3a761/modules/tutorials/?at=default).
diff --git a/content/posts/2015-01-28-set-datafx-application.md b/content/posts/2015-01-28-set-datafx-application.md
index b7cd99de..2b7ceca2 100644
--- a/content/posts/2015-01-28-set-datafx-application.md
+++ b/content/posts/2015-01-28-set-datafx-application.md
@@ -1,41 +1,39 @@
----
-outdated: true
-showInBlog: false
-title: 'How to set up a DataFX application'
-date: "2015-01-28"
-author: hendrik
-categories: [DataFX, JavaFX]
-excerpt: 'This tutorial describes how you can add DataFX to your JavaFX application or start a new application that is based on DataFX.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-A lot of people start using DataFX in small projects without a build file and by doing so they sometimes use old builds. Because of that I will give you some hints how to setup a project that is using DataFX.
-
-## DataFX builds
-
-Every stable DataFX build can be found at Maven Central. If you are new to Maven or Maven Central just open this [link](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.datafx%22). On the page you will find all artifacts of DataFX. If you for example want to use DataFX core you can download the jar, sources and javadoc [here](http://search.maven.org/#artifactdetails%7Cio.datafx%7Ccore%7C8.0%7Cjar).
-
-
-
-Each DataFX artifact is defined by the group-id, artifact-id and version. The group-id is always "io.datafx" and the artifact-id depends on the DataFX-Module. If you for example want to create an application that is suing the DataFX Flow you need the datafx-flow module and all it's dependencies. At the moment the last stable version is 8.0.
-
-If you want to download the DataFX jars by hand and add them to your application you need to download all dependencies of the module, too. Thankfully DataFX doesn't have much dependencies. Here is an overview:
-
-
-
-Once you have downloaded the last version of DataFX and added the jars to the class path of your application you can start coding.
-
-## Using builds tools
-
-Normally you won't download the dependencies of your application manually. Build tools like [Maven](http://maven.apache.org) or [Gradle](https://gradle.org) can do this job for you. By using one of the tools you only need to define the dependencies in your build file and the build tool will automatically download all needed jars. In addition the tools support transitive dependencies. This allows you to avoid needing to discover and specify the libraries that your own dependencies require, and including them automatically. If you Maven as build tool and you only want to add the DataFX Flow API to your application you only need to add one dependency:
-
-{{< highlight xml >}}
-
- io.datafx
- flow
- 8.0
-
-{{< / highlight >}}
-
-## Use DataFX in your application
-
-Once you added DataFX as dependency to your application you can using it as described in the [tutorials]({{< ref "/posts/2014-05-19-datafx-8-0-tutorials" >}}).
+---
+outdated: true
+showInBlog: false
+title: 'How to set up a DataFX application'
+date: "2015-01-28"
+author: hendrik
+categories: [DataFX, JavaFX]
+excerpt: 'This tutorial describes how you can add DataFX to your JavaFX application or start a new application that is based on DataFX.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+A lot of people start using DataFX in small projects without a build file and by doing so they sometimes use old builds. Because of that I will give you some hints how to setup a project that is using DataFX.
+
+## DataFX builds
+
+Every stable DataFX build can be found at Maven Central. If you are new to Maven or Maven Central just open this [link](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.datafx%22). On the page you will find all artifacts of DataFX. If you for example want to use DataFX core you can download the jar, sources and javadoc [here](http://search.maven.org/#artifactdetails%7Cio.datafx%7Ccore%7C8.0%7Cjar).
+
+
+
+Each DataFX artifact is defined by the group-id, artifact-id and version. The group-id is always "io.datafx" and the artifact-id depends on the DataFX-Module. If you for example want to create an application that is suing the DataFX Flow you need the datafx-flow module and all it's dependencies. At the moment the last stable version is 8.0.
+
+If you want to download the DataFX jars by hand and add them to your application you need to download all dependencies of the module, too. Thankfully DataFX doesn't have much dependencies. Here is an overview:
+
+
+
+Once you have downloaded the last version of DataFX and added the jars to the class path of your application you can start coding.
+
+## Using builds tools
+
+Normally you won't download the dependencies of your application manually. Build tools like [Maven](http://maven.apache.org) or [Gradle](https://gradle.org) can do this job for you. By using one of the tools you only need to define the dependencies in your build file and the build tool will automatically download all needed jars. In addition the tools support transitive dependencies. This allows you to avoid needing to discover and specify the libraries that your own dependencies require, and including them automatically. If you Maven as build tool and you only want to add the DataFX Flow API to your application you only need to add one dependency:
+
+```xml
+ io.datafx
+ flow
+ 8.0
+
```
+
+## Use DataFX in your application
+
+Once you added DataFX as dependency to your application you can using it as described in the [tutorials](/posts/2014-05-19-datafx-8-0-tutorials).
diff --git a/content/posts/2015-01-29-introduction-open-dolphin.md b/content/posts/2015-01-29-introduction-open-dolphin.md
index 114ac9af..7960e0ad 100644
--- a/content/posts/2015-01-29-introduction-open-dolphin.md
+++ b/content/posts/2015-01-29-introduction-open-dolphin.md
@@ -1,126 +1,112 @@
----
-outdated: true
-showInBlog: false
-title: 'An introduction to Open Dolphin'
-date: "2015-01-29"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'The post gives a short introduction about the architecture and features of Open Dolphin'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Last year I started to work at Canoo and some of you might know that Canoo provides the open source remoting middleware [Open Dolphin](http://open-dolphin.org/dolphin_website/Home.html). At the end of the last year I had the pleasure to work with Open Dolphin in a customer project. Based on the experience of this project I started to contribute to Open Dolphin because I think that it provides an interesting way to handle the remoting aspects of an application. In addition I will blog about Open Dolphin and how you can use it in (JavaFX) applications.
-
-
-
-If I need to describe Open Dolphin in just a few words I would say that it is a library that syncs presentation models between a server and one or many clients. If you haven't seen such an approach before it's maybe hard to understand. Therefore I will start with a basic introduction of the core concepts with this post.
-
-
-
-As you can see in the image the client and the server can access the same presentation model. Let's think about the presentation model as any data model. There are some best practices what kind of data should be defined in a presentation model but first of all let us define this as a model with any data in it. Both the client and the server can read data from the model or edit data in the model. Open Dolphin will automatically sync the model between the server and the client. In addition Open Dolphin supports multiple clients and therefore a more correct diagram would look something like this:
-
-
-
-As you can see in the picture all the different clients don't know each other and the sync between the presentation models in centralized by the server. If client A edits a value in the presentation model it will be synchronized with the server. Once the server has updated it's own presentation model with the new value the server synchronizes this change with all other clients. By doing you can create applications that share exactly the same presentation model. The following video shows a short example:
-
-{{< youtube fdTdo7G_hZY >}}
-
-While the sharing of the presentation model between several clients is a very cool feature and big benefit most of the time you need to synchronize a model only between the server and one client. Therefore the examples that will be shown in the following post will all use this approach. Once this workflow is completely described I will start to introduce the sync of several clients in future posts.
-
-## Benefits of using Open Dolphin and presentation models
-
-One big benefit of Open Dolphin is its independence to UI Toolkits. By default Open Dolphin doesn't depend on any toolkit like JavaFX, Swing or GWT. By using Open Dolphin you can use the same presentation model for JavaFX and Java Script clients, for example. When using some of the best practices that I will show in future posts a migration from one UI technology to another one will be more easy by using Open Dolphin. In addition the creation of an application that supports different client implementations (for example mobile, desktop and web) can be based on Open Dolphin. By doing so only the view of the clients will be different because Open Dolphin capsulate the controller logic and the data model.
-
-Next to the support of different client technologies Open Dolphin is based on the presentation model pattern. By doing so it combines many best practices to create MVC, MVP or MVVM applications. The following graphic shows how the MVC can be implemented by using Open Dolphin:
-
-
-
-## The presentation model
-
-Let's have a deeper look at the presentation models and how such a model is structured and managed in Open Dolphin. Each presentation model is defined by an unique id. In addition a presentation model can be specified by a type. Both values are defined as a string. Open Dolphin provides methods to find a specific presentation model by its id or all presentation models of a given type.
-
-{{< highlight java >}}
-PresentationModel model = dolphin.findPresentationModelById("myPresentationModel");
-List allErrorModels = dolphin.findAllPresentationModelsByType("errorModel");
-{{< / highlight >}}
-
-A presentation model contains a set of attributes and each attribute defines a value in the presentation model. Let's have a look at the following example to describe how attributes can be defined:
-
-
-
-In this example we have two different input fields and therefore we will define 2 different attributes:
-
-* An attributes that defines the name value
-* An attributes that defines the description value
-
-To create Attributes the Dolphin interface contains some factory methods. The following code snippet shows how the Attributes can be created:
-
-{{< highlight java >}}
-ClientAttribute nameAttribute = clientDolphin.createAttribute("nameValue", "initial value");
-ClientAttribute descriptionAttribute = clientDolphin.createAttribute("descriptionValue", "initial value");
-{{< / highlight >}}
-
-In the code a both attributes are created by defining the name of the attribute and an initial value. Once the attributes are created we can create a presentation model that will automatically synced between client and server:
-
-{{< highlight java >}}
-ClientPresentationModel presentationModel = dolphin.presentationModel("myPresentationModel", nameAttribute, descriptionAttribute);
-{{< / highlight >}}
-
-Once this is done the presentation model is created an can will automatically be synced between client and server whenever anything in it will be changed. This will happen if the value of an attribute will be changed, for example:
-
-{{< highlight java >}}
-nameAttribute.setValue("Hendrik Ebbers");
-{{< / highlight >}}
-
-Next to the name an Open Dolphin attribute is defined by a tag and a qualifier. As shown with the type of presentation models attributes can be found by using its tag, for example. Since these powerful features aren't needed for a first simple application I will show them in a later post.
-
-## Server commands
-
-Another important feature of Open Dolphin is the support of server commands. On server side command handlers can be registered for a specific command. Each command is defined by a unique name and can be called from client side.
-
-
-
-By doing so you can trigger server commands from client side. In a server command the presentation models can be accessed and modified. By doing so you can define a save command for example. Once the command is triggered you can convert the current content of the presentation model into business entities and persist them in a database.
-
-On server side the command handler can be registered by using a method of the ServerDolphin interface:
-
-{{< highlight java >}}
-dolphin.action("action", (command, response) -> {
- System.out.println("action command was triggered");
-}
-{{< / highlight >}}
-
-Once the command handler is registered it can be called from client side:
-
-{{< highlight java >}}
-clientDolphin.send("action");
-{{< / highlight >}}
-
-By doing so the command will be called on server side.
-
-## Basic interfaces
-
-The 3 most important interfaces of Open Dolphin are Dolphin, PresentationModel and Attribute. All three interfaces are defined in the dolphin-core module. In addition to the core model Open Dolphin provides a module for the client and the server side. Each of this modules contains a specialization of the interfaces. The dolphin-client module contains the ClientDolphin, ClientPresentationModel and CLientAttribute interfaces that extend the base ones for example.
-
-
-
-By doing so you need only one dependency for the client and one dependency for the server to use open dolphin:
-
-{{< highlight xml >}}
-
-
- org.open-dolphin
- dolphin-server
- 0.11
-
-
-
-
- org.open-dolphin
- dolphin-client
- 0.11
-
-{{< / highlight >}}
-
-## Conclusion
-
-This post shows some of the core concepts of Open Dolphin. For developers that used REST or EJB as the removing layer of applications this is a complete new approach. Therefore it's important to understand how Open Dolphin works before creating a first simple application based on this concepts. In my next Open Dolphin post I will show how a first "Hello World" application can be created.
+---
+outdated: true
+showInBlog: false
+title: 'An introduction to Open Dolphin'
+date: "2015-01-29"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'The post gives a short introduction about the architecture and features of Open Dolphin'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Last year I started to work at Canoo and some of you might know that Canoo provides the open source remoting middleware [Open Dolphin](http://open-dolphin.org/dolphin_website/Home.html). At the end of the last year I had the pleasure to work with Open Dolphin in a customer project. Based on the experience of this project I started to contribute to Open Dolphin because I think that it provides an interesting way to handle the remoting aspects of an application. In addition I will blog about Open Dolphin and how you can use it in (JavaFX) applications.
+
+
+
+If I need to describe Open Dolphin in just a few words I would say that it is a library that syncs presentation models between a server and one or many clients. If you haven't seen such an approach before it's maybe hard to understand. Therefore I will start with a basic introduction of the core concepts with this post.
+
+
+
+As you can see in the image the client and the server can access the same presentation model. Let's think about the presentation model as any data model. There are some best practices what kind of data should be defined in a presentation model but first of all let us define this as a model with any data in it. Both the client and the server can read data from the model or edit data in the model. Open Dolphin will automatically sync the model between the server and the client. In addition Open Dolphin supports multiple clients and therefore a more correct diagram would look something like this:
+
+
+
+As you can see in the picture all the different clients don't know each other and the sync between the presentation models in centralized by the server. If client A edits a value in the presentation model it will be synchronized with the server. Once the server has updated it's own presentation model with the new value the server synchronizes this change with all other clients. By doing you can create applications that share exactly the same presentation model. The following video shows a short example:
+
+
+
+While the sharing of the presentation model between several clients is a very cool feature and big benefit most of the time you need to synchronize a model only between the server and one client. Therefore the examples that will be shown in the following post will all use this approach. Once this workflow is completely described I will start to introduce the sync of several clients in future posts.
+
+## Benefits of using Open Dolphin and presentation models
+
+One big benefit of Open Dolphin is its independence to UI Toolkits. By default Open Dolphin doesn't depend on any toolkit like JavaFX, Swing or GWT. By using Open Dolphin you can use the same presentation model for JavaFX and Java Script clients, for example. When using some of the best practices that I will show in future posts a migration from one UI technology to another one will be more easy by using Open Dolphin. In addition the creation of an application that supports different client implementations (for example mobile, desktop and web) can be based on Open Dolphin. By doing so only the view of the clients will be different because Open Dolphin capsulate the controller logic and the data model.
+
+Next to the support of different client technologies Open Dolphin is based on the presentation model pattern. By doing so it combines many best practices to create MVC, MVP or MVVM applications. The following graphic shows how the MVC can be implemented by using Open Dolphin:
+
+
+
+## The presentation model
+
+Let's have a deeper look at the presentation models and how such a model is structured and managed in Open Dolphin. Each presentation model is defined by an unique id. In addition a presentation model can be specified by a type. Both values are defined as a string. Open Dolphin provides methods to find a specific presentation model by its id or all presentation models of a given type.
+
+```javaPresentationModel model = dolphin.findPresentationModelById("myPresentationModel");
+List allErrorModels = dolphin.findAllPresentationModelsByType("errorModel");
```
+
+A presentation model contains a set of attributes and each attribute defines a value in the presentation model. Let's have a look at the following example to describe how attributes can be defined:
+
+
+
+In this example we have two different input fields and therefore we will define 2 different attributes:
+
+* An attributes that defines the name value
+* An attributes that defines the description value
+
+To create Attributes the Dolphin interface contains some factory methods. The following code snippet shows how the Attributes can be created:
+
+```javaClientAttribute nameAttribute = clientDolphin.createAttribute("nameValue", "initial value");
+ClientAttribute descriptionAttribute = clientDolphin.createAttribute("descriptionValue", "initial value");
```
+
+In the code a both attributes are created by defining the name of the attribute and an initial value. Once the attributes are created we can create a presentation model that will automatically synced between client and server:
+
+```javaClientPresentationModel presentationModel = dolphin.presentationModel("myPresentationModel", nameAttribute, descriptionAttribute);
```
+
+Once this is done the presentation model is created an can will automatically be synced between client and server whenever anything in it will be changed. This will happen if the value of an attribute will be changed, for example:
+
+```javanameAttribute.setValue("Hendrik Ebbers");
```
+
+Next to the name an Open Dolphin attribute is defined by a tag and a qualifier. As shown with the type of presentation models attributes can be found by using its tag, for example. Since these powerful features aren't needed for a first simple application I will show them in a later post.
+
+## Server commands
+
+Another important feature of Open Dolphin is the support of server commands. On server side command handlers can be registered for a specific command. Each command is defined by a unique name and can be called from client side.
+
+
+
+By doing so you can trigger server commands from client side. In a server command the presentation models can be accessed and modified. By doing so you can define a save command for example. Once the command is triggered you can convert the current content of the presentation model into business entities and persist them in a database.
+
+On server side the command handler can be registered by using a method of the ServerDolphin interface:
+
+```javadolphin.action("action", (command, response) -> {
+ System.out.println("action command was triggered");
+}
```
+
+Once the command handler is registered it can be called from client side:
+
+```javaclientDolphin.send("action");
```
+
+By doing so the command will be called on server side.
+
+## Basic interfaces
+
+The 3 most important interfaces of Open Dolphin are Dolphin, PresentationModel and Attribute. All three interfaces are defined in the dolphin-core module. In addition to the core model Open Dolphin provides a module for the client and the server side. Each of this modules contains a specialization of the interfaces. The dolphin-client module contains the ClientDolphin, ClientPresentationModel and CLientAttribute interfaces that extend the base ones for example.
+
+
+
+By doing so you need only one dependency for the client and one dependency for the server to use open dolphin:
+
+```xml
+
+ org.open-dolphin
+ dolphin-server
+ 0.11
+
+
+
+
+ org.open-dolphin
+ dolphin-client
+ 0.11
+
```
+
+## Conclusion
+
+This post shows some of the core concepts of Open Dolphin. For developers that used REST or EJB as the removing layer of applications this is a complete new approach. Therefore it's important to understand how Open Dolphin works before creating a first simple application based on this concepts. In my next Open Dolphin post I will show how a first "Hello World" application can be created.
diff --git a/content/posts/2015-02-01-concurrency-ui-toolkits-part-2.md b/content/posts/2015-02-01-concurrency-ui-toolkits-part-2.md
index 89f2bf12..060d6dd6 100644
--- a/content/posts/2015-02-01-concurrency-ui-toolkits-part-2.md
+++ b/content/posts/2015-02-01-concurrency-ui-toolkits-part-2.md
@@ -1,156 +1,146 @@
----
-outdated: true
-showInBlog: false
-title: 'Concurrency in UI Toolkits (Part 2)'
-date: "2015-02-01"
-author: hendrik
-categories: [Desktop Application Framework (JSR 377), JavaFX]
-excerpt: 'This post describes how the Concurrency in UI Toolkits can be defined in a unified way.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In the [first post]({{< ref "/posts/2015-01-19-concurrency-ui-toolkits-part-1" >}}) of this series I showed how Concurrency is handled in UI Toolkits and how a generic approach to work with the toolkit specific thread may look like. This ends in the following interface:
-
-{{< highlight java >}}
-public interface UIThread {
-
- void runOnUiToolkitThread(Runnable runnable);
-
- default Future runOnUiToolkitThread(Callable callable) {
- FutureTask future = new FutureTask<>(callable);
- runOnUiToolkitThread(future);
- return future;
- }
-
- default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
- runOnUiToolkitThread((Callable)() -> {
- runnable.run();
- return null;
- }).get();
- }
-
- default T runOnUiToolkitThreadAndWait(Callable callable) throws InterruptedException, ExecutionException {
- return runOnUiToolkitThread(callable).get();
- }
-}
-{{< / highlight >}}
-
-But there are still some problems with this interface:
-
-* What happens if the `runOnUiToolkitThreadAndWait(..)` method is called on the UI-Thread?
-* One method returns a `Future<>` that defines the `boolean cancel(boolean mayInterruptIfRunning)` method. By definition thy method will interrupt the thread in that the task is running. But we never want to interrupt the UI Toolkit thread.
-
-Let's start with the first problem. Before we can solve this another question must be answered: I it's a problem to call this methods on the toolkit thread we need a way to check if the current thread is the toolkit thread. To do so most toolkits provide a helper method that checks if the current thread is the toolkit Thread. Examples are shown in the following code snippet.
-
-{{< highlight java >}}
-//JavaFX Helper Method
-Platform.isFxApplicationThread();
-
-//Swing Helper Method
-SwingUtilities.isEventDispatchThread()
-{{< / highlight >}}
-
-Because most Toolkits support this method we can simply add it to our interface:
-
-{{< highlight java >}}
-public interface UIThread {
-
- void runOnUiToolkitThread(Runnable runnable);
-
- boolean isUIToolkitThread();
-
- default Future runOnUiToolkitThread(Callable callable) {
- FutureTask future = new FutureTask<>(callable);
- runOnUiToolkitThread(future);
- return future;
- }
-
- default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
- runOnUiToolkitThread((Callable)() -> {
- runnable.run();
- return null;
- }).get();
- }
-
- default T runOnUiToolkitThreadAndWait(Callable callable) throws InterruptedException, ExecutionException {
- return runOnUiToolkitThread(callable).get();
- }
-}
-{{< / highlight >}}
-
-Once this is done we can have a deeper look at the methods that will block until a task was executed on the ui toolkit. In the defined interface the two methods that are named `runOnUiToolkitThreadAndWait` defines this behavior. Once the method is called a new task is created and added to the ui thread. Because the thread has a lot of work to do normally a queue will handle this tasks and execute them by using a first in first out approach. The following image shows an example.
-
-
-
-By doing so our task will be added to the queue and executed once all task that has been added earlier to the queue were executed. If we call this method from the ui thread the created task can't be executed before the task that is currently running is finished. But because the `runOnUiToolkitThreadAndWait` methods will wait for the execution of the new task we will end in an deadlock that is definitely the worst think that can happen. By doing so nothing can be handled on the UI thread: No user interaction or rendering can be done and the application is frozen. Because no Exception will be thrown the application just hangs we will receive no information what has triggered the error.
-
-With the help of the new `isUIToolkitThread()` method we can avoid this behavior and refactor the methods to an more fail-safe version. With a simple if-statement we can add a special behavior if the `runOnUiToolkitThreadAndWait` method is called from the ui thread:
-
-{{< highlight java >}}
-default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
- if(isUIToolkitThread()) {
- //what should we do now?? 😰
- } else {
- runOnUiToolkitThread((Callable)() -> {
- runnable.run();
- return null;
- }).get();
- }
-}
-{{< / highlight >}}
-
-Once this is done we need to decide what we want to do if the method was called join the ui thread. In general there are two different ways how this is handled by ui toolkits:
-
-* throw an `Exception` (checked or unchecked)
-* directly execute the runnable by calling the `run()` method
-
-Here are the implementations for this approaches:
-
-{{< highlight java >}}
-//unchecked exception
-default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
- if(isUIToolkitThread()) {
- throw new RuntimeException("This method should not be called on the UI Thread")
- } else {
- runOnUiToolkitThread((Callable)() -> {
- runnable.run();
- return null;
- }).get();
- }
-}
-
-//unchecked exception
-default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException, ToolkitException {
- if(isUIToolkitThread()) {
- throw new ToolkitException("This method should not be called on the UI Thread")
- } else {
- runOnUiToolkitThread((Callable)() -> {
- runnable.run();
- return null;
- }).get();
- }
-}
-
-//Call the runnable directly
-default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
- if(isUIToolkitThread()) {
- try {
- runnable.run();
- } catch(Exception e) {
- throw new ExecutionException(e);
- }
- } else {
- runOnUiToolkitThread((Callable)() -> {
- runnable.run();
- return null;
- }).get();
- }
-}
-{{< / highlight >}}
-
-The first 2 methods looks mostly the same. Only the exception type is different. The first method uses an unchecked exception that will end in a more readable code when using the method because you don't need to catch the new exception type all the time. But developers need to know that an unchecked exception will be thrown whenever the method is called on the ui thread to avoid errors at runtime.
-
-The third method can be called on any thread. A developer doesn't need to think about it. If you know what you do, this is the most flexibel way how such a method can be defined. But on the other hand this can cause problems. I have seen a lot of projects where developers used this type of method way to often. Because they ad no idea how to handle the ui thread `invokeAndWait(..)` methods were called all over the code. By doing so your stack trace ends in something like this:
-
-
-
-This will end in code that is unperformant, unstable and can't be maintained anymore. Therefore I would choose one of the first 2 implementations. But that's only how I see this things and maybe you have a complete different opinion. Therefore it would be great if you can leave a comment here about your favorite way how to handle this problems. [JSR-377]({{< ref "/posts/2014-12-30-desktopembedded-application-api-jsr" >}}) will contain such a interface and we want to resolve all the shown problems in an ui toolkit independent way. If you are interested in the JSR or want to share your opinion about this topic you should have a look at the [JSR Mailing List](http://jsr377-api.40747.n7.nabble.com). In the next post I will have a deeper look at the `Future<>` interface in combination with ui threads.
+---
+outdated: true
+showInBlog: false
+title: 'Concurrency in UI Toolkits (Part 2)'
+date: "2015-02-01"
+author: hendrik
+categories: [Desktop Application Framework (JSR 377), JavaFX]
+excerpt: 'This post describes how the Concurrency in UI Toolkits can be defined in a unified way.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In the [first post](/posts/2015-01-19-concurrency-ui-toolkits-part-1) of this series I showed how Concurrency is handled in UI Toolkits and how a generic approach to work with the toolkit specific thread may look like. This ends in the following interface:
+
+```javapublic interface UIThread {
+
+ void runOnUiToolkitThread(Runnable runnable);
+
+ default Future runOnUiToolkitThread(Callable callable) {
+ FutureTask future = new FutureTask<>(callable);
+ runOnUiToolkitThread(future);
+ return future;
+ }
+
+ default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
+ runOnUiToolkitThread((Callable)() -> {
+ runnable.run();
+ return null;
+ }).get();
+ }
+
+ default T runOnUiToolkitThreadAndWait(Callable callable) throws InterruptedException, ExecutionException {
+ return runOnUiToolkitThread(callable).get();
+ }
+}
```
+
+But there are still some problems with this interface:
+
+* What happens if the `runOnUiToolkitThreadAndWait(..)` method is called on the UI-Thread?
+* One method returns a `Future<>` that defines the `boolean cancel(boolean mayInterruptIfRunning)` method. By definition thy method will interrupt the thread in that the task is running. But we never want to interrupt the UI Toolkit thread.
+
+Let's start with the first problem. Before we can solve this another question must be answered: I it's a problem to call this methods on the toolkit thread we need a way to check if the current thread is the toolkit thread. To do so most toolkits provide a helper method that checks if the current thread is the toolkit Thread. Examples are shown in the following code snippet.
+
+```java//JavaFX Helper Method
+Platform.isFxApplicationThread();
+
+//Swing Helper Method
+SwingUtilities.isEventDispatchThread()
```
+
+Because most Toolkits support this method we can simply add it to our interface:
+
+```javapublic interface UIThread {
+
+ void runOnUiToolkitThread(Runnable runnable);
+
+ boolean isUIToolkitThread();
+
+ default Future runOnUiToolkitThread(Callable callable) {
+ FutureTask future = new FutureTask<>(callable);
+ runOnUiToolkitThread(future);
+ return future;
+ }
+
+ default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
+ runOnUiToolkitThread((Callable)() -> {
+ runnable.run();
+ return null;
+ }).get();
+ }
+
+ default T runOnUiToolkitThreadAndWait(Callable callable) throws InterruptedException, ExecutionException {
+ return runOnUiToolkitThread(callable).get();
+ }
+}
```
+
+Once this is done we can have a deeper look at the methods that will block until a task was executed on the ui toolkit. In the defined interface the two methods that are named `runOnUiToolkitThreadAndWait` defines this behavior. Once the method is called a new task is created and added to the ui thread. Because the thread has a lot of work to do normally a queue will handle this tasks and execute them by using a first in first out approach. The following image shows an example.
+
+
+
+By doing so our task will be added to the queue and executed once all task that has been added earlier to the queue were executed. If we call this method from the ui thread the created task can't be executed before the task that is currently running is finished. But because the `runOnUiToolkitThreadAndWait` methods will wait for the execution of the new task we will end in an deadlock that is definitely the worst think that can happen. By doing so nothing can be handled on the UI thread: No user interaction or rendering can be done and the application is frozen. Because no Exception will be thrown the application just hangs we will receive no information what has triggered the error.
+
+With the help of the new `isUIToolkitThread()` method we can avoid this behavior and refactor the methods to an more fail-safe version. With a simple if-statement we can add a special behavior if the `runOnUiToolkitThreadAndWait` method is called from the ui thread:
+
+```javadefault void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
+ if(isUIToolkitThread()) {
+ //what should we do now?? 😰
+ } else {
+ runOnUiToolkitThread((Callable)() -> {
+ runnable.run();
+ return null;
+ }).get();
+ }
+}
```
+
+Once this is done we need to decide what we want to do if the method was called join the ui thread. In general there are two different ways how this is handled by ui toolkits:
+
+* throw an `Exception` (checked or unchecked)
+* directly execute the runnable by calling the `run()` method
+
+Here are the implementations for this approaches:
+
+```java//unchecked exception
+default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
+ if(isUIToolkitThread()) {
+ throw new RuntimeException("This method should not be called on the UI Thread")
+ } else {
+ runOnUiToolkitThread((Callable)() -> {
+ runnable.run();
+ return null;
+ }).get();
+ }
+}
+
+//unchecked exception
+default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException, ToolkitException {
+ if(isUIToolkitThread()) {
+ throw new ToolkitException("This method should not be called on the UI Thread")
+ } else {
+ runOnUiToolkitThread((Callable)() -> {
+ runnable.run();
+ return null;
+ }).get();
+ }
+}
+
+//Call the runnable directly
+default void runOnUiToolkitThreadAndWait(Runnable runnable) throws InterruptedException, ExecutionException {
+ if(isUIToolkitThread()) {
+ try {
+ runnable.run();
+ } catch(Exception e) {
+ throw new ExecutionException(e);
+ }
+ } else {
+ runOnUiToolkitThread((Callable)() -> {
+ runnable.run();
+ return null;
+ }).get();
+ }
+}
```
+
+The first 2 methods looks mostly the same. Only the exception type is different. The first method uses an unchecked exception that will end in a more readable code when using the method because you don't need to catch the new exception type all the time. But developers need to know that an unchecked exception will be thrown whenever the method is called on the ui thread to avoid errors at runtime.
+
+The third method can be called on any thread. A developer doesn't need to think about it. If you know what you do, this is the most flexibel way how such a method can be defined. But on the other hand this can cause problems. I have seen a lot of projects where developers used this type of method way to often. Because they ad no idea how to handle the ui thread `invokeAndWait(..)` methods were called all over the code. By doing so your stack trace ends in something like this:
+
+
+
+This will end in code that is unperformant, unstable and can't be maintained anymore. Therefore I would choose one of the first 2 implementations. But that's only how I see this things and maybe you have a complete different opinion. Therefore it would be great if you can leave a comment here about your favorite way how to handle this problems. [JSR-377](/posts/2014-12-30-desktopembedded-application-api-jsr) will contain such a interface and we want to resolve all the shown problems in an ui toolkit independent way. If you are interested in the JSR or want to share your opinion about this topic you should have a look at the [JSR Mailing List](http://jsr377-api.40747.n7.nabble.com). In the next post I will have a deeper look at the `Future<>` interface in combination with ui threads.
diff --git a/content/posts/2015-02-06-test-driven-development-youtube.md b/content/posts/2015-02-06-test-driven-development-youtube.md
index f21e7a03..8803a435 100644
--- a/content/posts/2015-02-06-test-driven-development-youtube.md
+++ b/content/posts/2015-02-06-test-driven-development-youtube.md
@@ -8,6 +8,6 @@ categories: [DataFX, JavaFX]
excerpt: 'Sven Ruppert and I gave a talk about Testing for JavaFX. In this talk we show how you can test your JavaFX application with TestFX.'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-[Sven Ruppert](https://twitter.com/SvenRuppert) and I gave a talk about Testing for JavaFX at [Coding Serbia](http://codingserbia.com). In this talk we show how you can test your JavaFX application by using [TestFX](https://github.com/TestFX/TestFX) and describe some patterns that are very useful when testing big applications. A detailed blog post about the topic of the talk can be found [here]({{< ref "/posts/2014-10-01-dialog-objects-pattern-automated-tests-testfx" >}}). The talk was recorded and published at YouTube:
+[Sven Ruppert](https://twitter.com/SvenRuppert) and I gave a talk about Testing for JavaFX at [Coding Serbia](http://codingserbia.com). In this talk we show how you can test your JavaFX application by using [TestFX](https://github.com/TestFX/TestFX) and describe some patterns that are very useful when testing big applications. A detailed blog post about the topic of the talk can be found [here](/posts/2014-10-01-dialog-objects-pattern-automated-tests-testfx). The talk was recorded and published at YouTube:
-{{< youtube Zt08nDyW-3M >}}
+
diff --git a/content/posts/2015-02-11-jsr377-got-green-light-continue.md b/content/posts/2015-02-11-jsr377-got-green-light-continue.md
index 4558f58c..de56f4d2 100644
--- a/content/posts/2015-02-11-jsr377-got-green-light-continue.md
+++ b/content/posts/2015-02-11-jsr377-got-green-light-continue.md
@@ -14,4 +14,4 @@ Today [the Review Ballot Results for JSR377 (Desktop|Embedded Application API)](
Spec lead Andres Almiray published [the official web page](http://jsr377.github.io/site/) for the JSR today.
-If you want to know more about JSR377 you should read [this introduction]({{< ref "/posts/2014-12-30-desktopembedded-application-api-jsr" >}}) or have a look at the [mailing list](http://jsr377-api.40747.n7.nabble.com).
+If you want to know more about JSR377 you should read [this introduction](/posts/2014-12-30-desktopembedded-application-api-jsr) or have a look at the [mailing list](http://jsr377-api.40747.n7.nabble.com).
diff --git a/content/posts/2015-02-12-short-introduction-bower.md b/content/posts/2015-02-12-short-introduction-bower.md
index 4329d87b..72bd330f 100644
--- a/content/posts/2015-02-12-short-introduction-bower.md
+++ b/content/posts/2015-02-12-short-introduction-bower.md
@@ -1,53 +1,51 @@
----
-outdated: true
-showInBlog: false
-title: 'A short introduction to Bower'
-date: "2015-02-12"
-author: hendrik
-categories: [Web Frontends]
-excerpt: 'This post gives a short introduction to Bower from a Java developers point of view.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Some weeks ago [I blogged about web components]({{< ref "/posts/2014-11-12-first-steps-webcomponents" >}}). Since that post I did a lot of research about this topic and had a [talk about web components at JFokus](http://www.jfokus.se/jfokus/talks.jsp#WebComponents). I really like this new technology and therefore I plan to blog about it more often in future. All the JavaFX lovers and readers of my blog shouldn't be afraid. I will continue work with JavaFX ;)
-
-Before going deep in the web components topic I want to introduce a tool that I think is needed when working with this new technology: [bower](http://bower.io).
-
-
-
-Bower is an open source tool that is created by Twitter and helps you to manage the dependencies of a web application. By using bower you can define all the dependencies of your application and automatically download them.
-
-## Getting started with bower
-
-Bower can be [installed by using NPM](http://bower.io/#install-bower) and once it's on your system you can create a bower configuration for your project by simply calling `bower init`. By doing so you need to define some metadata for your project and bower will create a json file (`bower.json`) in your project folder. This file contains the definition of your project and might look like this:
-
-{{< highlight json >}}
-{
- "name": "bootstrap-layout",
- "version": "0.0.0",
- "authors": [
- "Hendrik Ebbers "
- ],
- "license": "MIT",
- "ignore": [
- "**/.*",
- "node_modules",
- "bower_components",
- "test",
- "tests"
- ]
-}
-{{< / highlight >}}
-
-Developers who are familiar with [Maven](http://maven.apache.org) might notice some parallels. Once the file is created you can add dependencies to your project by calling a bower command like `bower install --save webcomponentsjs` that installs the web components polyfill (I plan to blog later about that module). When looking at the bower file you will find a dependencies section that contains the added module. In addition a `bower_components` folder was created in your project that contains the defined dependency. Once this is done you can simply use any content of the `bower_components` folder in your application. But don't forget to add the `bower_components` folder to `.gitignore` ;) When checking out the project from git you only need to call `bower install` and the cool little tool will download all the defined dependencies for you and add them to the `bower_components` folder automatically. So from a Java developer point of view this is mostly what Maven does for my Java project.
-
-Here is a quick overview about the commands that is part of my JFokus talk:
-
-
-
-## How to define dependencies
-
-Some of you might ask yourself how you should know the definition or name of a dependency. Bower is more flexible that Maven in this case. When calling the `install` command there are different ways how a dependency can be specified. Here is a short overview that is taken from the [bower web page](http://bower.io/#getting-started):
-
-
-
-In addition bower provides a [search frontend](http://bower.io/search/) (like the Maven central frontend) that can be used to search for modules and dependencies.
+---
+outdated: true
+showInBlog: false
+title: 'A short introduction to Bower'
+date: "2015-02-12"
+author: hendrik
+categories: [Web Frontends]
+excerpt: 'This post gives a short introduction to Bower from a Java developers point of view.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Some weeks ago [I blogged about web components](/posts/2014-11-12-first-steps-webcomponents). Since that post I did a lot of research about this topic and had a [talk about web components at JFokus](http://www.jfokus.se/jfokus/talks.jsp#WebComponents). I really like this new technology and therefore I plan to blog about it more often in future. All the JavaFX lovers and readers of my blog shouldn't be afraid. I will continue work with JavaFX ;)
+
+Before going deep in the web components topic I want to introduce a tool that I think is needed when working with this new technology: [bower](http://bower.io).
+
+
+
+Bower is an open source tool that is created by Twitter and helps you to manage the dependencies of a web application. By using bower you can define all the dependencies of your application and automatically download them.
+
+## Getting started with bower
+
+Bower can be [installed by using NPM](http://bower.io/#install-bower) and once it's on your system you can create a bower configuration for your project by simply calling `bower init`. By doing so you need to define some metadata for your project and bower will create a json file (`bower.json`) in your project folder. This file contains the definition of your project and might look like this:
+
+```json{
+ "name": "bootstrap-layout",
+ "version": "0.0.0",
+ "authors": [
+ "Hendrik Ebbers "
+ ],
+ "license": "MIT",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ]
+}
```
+
+Developers who are familiar with [Maven](http://maven.apache.org) might notice some parallels. Once the file is created you can add dependencies to your project by calling a bower command like `bower install --save webcomponentsjs` that installs the web components polyfill (I plan to blog later about that module). When looking at the bower file you will find a dependencies section that contains the added module. In addition a `bower_components` folder was created in your project that contains the defined dependency. Once this is done you can simply use any content of the `bower_components` folder in your application. But don't forget to add the `bower_components` folder to `.gitignore` ;) When checking out the project from git you only need to call `bower install` and the cool little tool will download all the defined dependencies for you and add them to the `bower_components` folder automatically. So from a Java developer point of view this is mostly what Maven does for my Java project.
+
+Here is a quick overview about the commands that is part of my JFokus talk:
+
+
+
+## How to define dependencies
+
+Some of you might ask yourself how you should know the definition or name of a dependency. Bower is more flexible that Maven in this case. When calling the `install` command there are different ways how a dependency can be specified. Here is a short overview that is taken from the [bower web page](http://bower.io/#getting-started):
+
+
+
+In addition bower provides a [search frontend](http://bower.io/search/) (like the Maven central frontend) that can be used to search for modules and dependencies.
diff --git a/content/posts/2015-02-13-quick-overview-datafx-mvc-flow-api.md b/content/posts/2015-02-13-quick-overview-datafx-mvc-flow-api.md
index ab104156..2d14cde8 100644
--- a/content/posts/2015-02-13-quick-overview-datafx-mvc-flow-api.md
+++ b/content/posts/2015-02-13-quick-overview-datafx-mvc-flow-api.md
@@ -1,162 +1,150 @@
----
-outdated: true
-showInBlog: false
-title: 'A quick overview to the DataFX MVC and Flow API'
-date: "2015-02-13"
-author: hendrik
-categories: [DataFX, Desktop Application Framework (JSR 377), JavaFX]
-excerpt: 'This is a short overview of the controller and flow API of DataFX with some small examples'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-This is a short overview of the controller and flow API of DataFX that I have written for the [JSR377 mailing list](http://jsr377-api.40747.n7.nabble.com/Application-Framework-Architecture-td31.html#a52). If you want to discuss the architecture in general please add a reply to the mailing list.
-
-DataFX provides a MVC approach that adds a lot of API sugar to the FXML API of JavaFX. As a first example you can find a simple controller here:
-
-{{< highlight java >}}
-@ViewController("view.fxml")
-public class MyController {
-
- @ViewNode
- private Label myLabel;
-
- @ViewNode
- @ActionTrigger("action-id")
- private Button myButton;
-
- @PostContruct
- private void init() {
- myLabel.setText("");
- }
-
- @ActionMethod("action-id")
- private void onAction() {
- myLabel.setText("clicked...");
- }
-
-}
-{{< / highlight >}}
-
-DataFX Controllers supports a lot of standard annotations like `@PostConstruct`. In addition the `@ViewNode` and `@ViewController` Annotation can be used to provide a link to the view. `@ViewNode` does mainly the same as `@FXML` but provides additional functionalities. Actions can be defined by an unique id. Therefore you can use Annotations to bind controls to actions. If you want a action to be called in a background thread you only need to add the `@Async` Annotation to the method.
-
-Next to this there are some special annotations to inject DataFX related Objects like an exception handler or the DataFX concurrency toolkit. Here is an example:
-
-{{< highlight java >}}
-@ViewController("view.fxml")
-public class MyController {
-
- @ViewNode
- private Label myLabel;
-
- @ConcurrencyProvider
- private ObservableExecutor executor;
-
- @PostContruct
- private void init() {
- executor.createProcessChain().
- addSupplierInExecutor(() -> getDataFromServer()).
- addConsumerInPlatformThread(data -> myLabel.setText(data)).
- run();
- }
-}
-{{< / highlight >}}
-
-On top of the MVC API is the Flow API. By using this API you can define flows in your application. By doing so you can define links between views or actions that will open a specific view. A Flow can easily defined by using the controller classes:
-
-{{< highlight java >}}
-Flow flow = new Flow(WizardView1Controller.class).
- withLink(WizardView1Controller.class, "next", WizardView2Controller.class).
- withLink(WizardView2Controller.class, "next", WizardView3Controller.class).
- withLink(WizardView3Controller.class, "next", WizardView4Controller.class).
- withLink(WizardView4Controller.class, "next", WizardView5Controller.class);
-{{< / highlight >}}
-
-When using a flow you can define actions as global actions for the flow or actions that are view specific.
-
-Next to this the Flow API adds a lot of new annotations. By adding the `@BackAction` annotation to a node like a button the flow will navigate back to the last view once the button is clicked. Instead of defining the links in the flow definition you can use the `@LinkAction(NextViewController.class)` annotation.
-
-In addition the Flow API provides CDI by using `@Inject`. To do so 4 different scopes are defined:
-
-* application scope (singleton)
-* flow scope (same instance will be injected in every controller / view / model of the flow)
-* view scope (same instance will be injected in the controller / model of the view)
-* dependend (always inject a new instance)
-
-In addition DataFX provides a event system. This can be used to handle events between 2 separated flows, for example. Each event type is defined by a unique id. The following code snippet defines two controllers that can be used in complete different parts of the application and don’t know each other. By using the event system the first controller can send events to the second one by clicking the button:
-
-{{< highlight java >}}
-@ViewController("producer.fxml")
-public class ProducerController {
-
- @ViewNode
- @EventTrigger("test-message")
- private Button sendButton;
-
- @ViewNode
- private TextField textField;
-
- @EventProducer("test-message")
- private String getMessage() {
- return textField.getText();
- }
-
-}
-
-@ViewController("receiver.fxml")
-public class ReceiverController {
-
- @ViewNode
- private Label messageLabel;
-
- @OnEvent("test-message")
- private void onNewChatMessage(Event e) {
- messageLabel.setText(e.getContent());
- }
-}
-{{< / highlight >}}
-
-If you want the async events you only need to add the `@Async` annotation to the producer or / and receiver. By doing so you can create events on a background thread that will be received on the platform thread.
-
-DataFX provides a PlugIn API that can be used to define additional components / plugins that will be managed by DataFX. Therefore you can define two types of Annotations: A injection annotation that can be used to inject specific objects or a handler annotation that can be use to do some stuff with objects. Here are two examples:
-
-## Example A
-
-DataFX provides a plugin for feature driven development. By doing so you can define nodes in your controller like this:
-
-{{< highlight java >}}
-@HideByFeature("PLAY_FEATURE")
-private Button playButton;
-
-@ViewNode
-@DisabledByFeature("FEATURE2")
-private Button button2;
-{{< / highlight >}}
-
-Now you can use the [togglz API](http://www.togglz.org/documentation/overview.html) to define feature toggles and change them at runtime. If you for example disable the `PLAY_FEATURE` the playButton will become hidden. This is en example for a plugin that provides handler annotations.
-
-## Example B
-
-DataFX provides a Plugin for remote EJBs. By using the plugin you can inject a Remote-EJB-Proxy in your controller:
-
-{{< highlight java >}}
-@ViewController("view.fxml")
-public class EjbViewController {
-
- @RemoteEjb()
- RemoteCalculator calculator;
-
- @ViewNode
- @ActionTrigger("calc")
- Button myButton;
-
- @Async
- @ActionMethod("calc")
- private void onAction() {
- System.out.println(calculator.add(3, 3));
- }
-
-}
-{{< / highlight >}}
-
-In this case the EJB Wrapper / Proxy will be injected by using the custom / plugin annotation
-
-If you want to now more you should have a look at [the DataFX tutorials]({{< ref "/posts/2014-05-19-datafx-8-0-tutorials" >}}) or ask me :)
+---
+outdated: true
+showInBlog: false
+title: 'A quick overview to the DataFX MVC and Flow API'
+date: "2015-02-13"
+author: hendrik
+categories: [DataFX, Desktop Application Framework (JSR 377), JavaFX]
+excerpt: 'This is a short overview of the controller and flow API of DataFX with some small examples'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+This is a short overview of the controller and flow API of DataFX that I have written for the [JSR377 mailing list](http://jsr377-api.40747.n7.nabble.com/Application-Framework-Architecture-td31.html#a52). If you want to discuss the architecture in general please add a reply to the mailing list.
+
+DataFX provides a MVC approach that adds a lot of API sugar to the FXML API of JavaFX. As a first example you can find a simple controller here:
+
+```java@ViewController("view.fxml")
+public class MyController {
+
+ @ViewNode
+ private Label myLabel;
+
+ @ViewNode
+ @ActionTrigger("action-id")
+ private Button myButton;
+
+ @PostContruct
+ private void init() {
+ myLabel.setText("");
+ }
+
+ @ActionMethod("action-id")
+ private void onAction() {
+ myLabel.setText("clicked...");
+ }
+
+}
```
+
+DataFX Controllers supports a lot of standard annotations like `@PostConstruct`. In addition the `@ViewNode` and `@ViewController` Annotation can be used to provide a link to the view. `@ViewNode` does mainly the same as `@FXML` but provides additional functionalities. Actions can be defined by an unique id. Therefore you can use Annotations to bind controls to actions. If you want a action to be called in a background thread you only need to add the `@Async` Annotation to the method.
+
+Next to this there are some special annotations to inject DataFX related Objects like an exception handler or the DataFX concurrency toolkit. Here is an example:
+
+```java@ViewController("view.fxml")
+public class MyController {
+
+ @ViewNode
+ private Label myLabel;
+
+ @ConcurrencyProvider
+ private ObservableExecutor executor;
+
+ @PostContruct
+ private void init() {
+ executor.createProcessChain().
+ addSupplierInExecutor(() -> getDataFromServer()).
+ addConsumerInPlatformThread(data -> myLabel.setText(data)).
+ run();
+ }
+}
```
+
+On top of the MVC API is the Flow API. By using this API you can define flows in your application. By doing so you can define links between views or actions that will open a specific view. A Flow can easily defined by using the controller classes:
+
+```javaFlow flow = new Flow(WizardView1Controller.class).
+ withLink(WizardView1Controller.class, "next", WizardView2Controller.class).
+ withLink(WizardView2Controller.class, "next", WizardView3Controller.class).
+ withLink(WizardView3Controller.class, "next", WizardView4Controller.class).
+ withLink(WizardView4Controller.class, "next", WizardView5Controller.class);
```
+
+When using a flow you can define actions as global actions for the flow or actions that are view specific.
+
+Next to this the Flow API adds a lot of new annotations. By adding the `@BackAction` annotation to a node like a button the flow will navigate back to the last view once the button is clicked. Instead of defining the links in the flow definition you can use the `@LinkAction(NextViewController.class)` annotation.
+
+In addition the Flow API provides CDI by using `@Inject`. To do so 4 different scopes are defined:
+
+* application scope (singleton)
+* flow scope (same instance will be injected in every controller / view / model of the flow)
+* view scope (same instance will be injected in the controller / model of the view)
+* dependend (always inject a new instance)
+
+In addition DataFX provides a event system. This can be used to handle events between 2 separated flows, for example. Each event type is defined by a unique id. The following code snippet defines two controllers that can be used in complete different parts of the application and don’t know each other. By using the event system the first controller can send events to the second one by clicking the button:
+
+```java@ViewController("producer.fxml")
+public class ProducerController {
+
+ @ViewNode
+ @EventTrigger("test-message")
+ private Button sendButton;
+
+ @ViewNode
+ private TextField textField;
+
+ @EventProducer("test-message")
+ private String getMessage() {
+ return textField.getText();
+ }
+
+}
+
+@ViewController("receiver.fxml")
+public class ReceiverController {
+
+ @ViewNode
+ private Label messageLabel;
+
+ @OnEvent("test-message")
+ private void onNewChatMessage(Event e) {
+ messageLabel.setText(e.getContent());
+ }
+}
```
+
+If you want the async events you only need to add the `@Async` annotation to the producer or / and receiver. By doing so you can create events on a background thread that will be received on the platform thread.
+
+DataFX provides a PlugIn API that can be used to define additional components / plugins that will be managed by DataFX. Therefore you can define two types of Annotations: A injection annotation that can be used to inject specific objects or a handler annotation that can be use to do some stuff with objects. Here are two examples:
+
+## Example A
+
+DataFX provides a plugin for feature driven development. By doing so you can define nodes in your controller like this:
+
+```java@HideByFeature("PLAY_FEATURE")
+private Button playButton;
+
+@ViewNode
+@DisabledByFeature("FEATURE2")
+private Button button2;
```
+
+Now you can use the [togglz API](http://www.togglz.org/documentation/overview.html) to define feature toggles and change them at runtime. If you for example disable the `PLAY_FEATURE` the playButton will become hidden. This is en example for a plugin that provides handler annotations.
+
+## Example B
+
+DataFX provides a Plugin for remote EJBs. By using the plugin you can inject a Remote-EJB-Proxy in your controller:
+
+```java@ViewController("view.fxml")
+public class EjbViewController {
+
+ @RemoteEjb()
+ RemoteCalculator calculator;
+
+ @ViewNode
+ @ActionTrigger("calc")
+ Button myButton;
+
+ @Async
+ @ActionMethod("calc")
+ private void onAction() {
+ System.out.println(calculator.add(3, 3));
+ }
+
+}
```
+
+In this case the EJB Wrapper / Proxy will be injected by using the custom / plugin annotation
+
+If you want to now more you should have a look at [the DataFX tutorials](/posts/2014-05-19-datafx-8-0-tutorials) or ask me :)
diff --git a/content/posts/2015-02-15-use-webcomponents-today.md b/content/posts/2015-02-15-use-webcomponents-today.md
index 960f4456..6e499a13 100644
--- a/content/posts/2015-02-15-use-webcomponents-today.md
+++ b/content/posts/2015-02-15-use-webcomponents-today.md
@@ -1,167 +1,153 @@
----
-outdated: true
-showInBlog: false
-title: 'An overview of the Web Component specifications'
-date: "2015-02-15"
-author: hendrik
-categories: [General, WebComponents]
-excerpt: 'This gives a short overview to the four W3C specs to define reusable web components: Element Template, Shadow DOM, Custom Elements and HTML Imports'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-WebComponents are a new W3C standard that is defined by some new specification:
-
-* Element Template
-* Shadow DOM
-* Custom Elements
-* HTML Imports
-
-An overview about this specs and how they can be used in HTML can be found in the presentation that I did with [Michael Heinrichs](https://twitter.com/net0pyr) at JFokus in detail. Therefore I only want a short overview here.
-
-## Element Template
-
-By using the template tag you can define a reusable template of a HTML hierarchy that can be reused and added to your DOM. Let's say you define the following template:
-
-
-
-Once you have defined this template you can create a instance in JavaScript and add it to the DOM of the page:
-
-
-
-By doing so you can reuse the defined template several times in your page.
-
-## Shadow DOM
-
-Let's say you have defined a template (or a web component as we will see later) and use it in your application. By doing so the DOM of your component will be added to the page DOM. If you than want to style your page by using CSS or access the page by JavaScript there are some pitfalls. As an example the following DOM is created and a component (green) is added to the regular DOM (blue). A node in the page and in the component uses the same ID or style class:
-
-
-
-Maybe the component was created by a different developer or it is part of a 3rd party module. In this case you maybe don't know about the internal IDs or style classes. When styling or modifying your application you would use the following code:
-
-{{< highlight js >}}
-//JavaScript
-document.querySelector(".content")
-
-//CSS
-.content {
- color: blue;
-}
-{{< / highlight >}}
-
-In both cases your code will affect the node in the regular DOM and in the component. But normally you don't want to change the component. Therefore the Shadow DOM was introduced. By using the shadow DOM the nodes of the component are separated from the regular DOM:
-
-
-
-Once this is done CSS or JavaScript changes won't affect the component that is capsulated by the Shadow DOM. A component in a Shadow DOM can be created by using JavaScript:
-
-{{< highlight js >}}
-var root = host.createShadowRoot();
-var clone = document.importNode(template.content, true);
-root.appendChild(clone);
-{{< / highlight >}}
-
-## Custom Elements
-
-The Custom Elements spec makes use of templates and the shadow DOM. By doing so you can specify a component and add it to a page in a Shadow DOM. In addition the spec defines a lifecylce for components.
-
-By using the Custom Elements spec you can define reusable tags for your components. Let's say you want to define a activity stream like in Facebook or Twitter. To do so we want to create a custom element for the entries in this stream.
-
-
-
-Normally you need to define a div hierarchy for any entry in the stream. This ends in a lot of boilerplate code like shown in the following snippet:
-
-{{< highlight html >}}
-
-{{< / highlight >}}
-
-This don't look readable and what we really want to do is something like this:
-
-{{< highlight html >}}
-
- Michael had fun writing web components.
-
-
- Hendrik blogged on GuiGarage.
-
-{{< / highlight >}}
-
-This can be done by using Custom Elements. To do so we first create a template:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-Once this is done we need to write some JavaScript code to create a custom element that is based on this template:
-
-{{< highlight js >}}
-var importDoc = document.currentScript.ownerDocument;
- var activityPrototype = Object.create(HTMLElement.prototype);
-
- activityPrototype.createdCallback = function() {
- var template = importDoc.querySelector('template');
- var clone = document.importNode(template.content, true);
-
- var host = $(this);
- $(".icon", clone).attr("src", host.attr("iconSrc"));
- $(".time", clone).text(host.attr("time"));
-
- var shadowRoot = this.createShadowRoot();
- shadowRoot.appendChild(clone);
- };
-
- // Register our new element
- document.registerElement('activity-card', {
- prototype: activityPrototype
- });
-{{< / highlight >}}
-
-Once this is done the `activity-card` tag can be used in our application. In the JavaScript code a method called `createdCallback` is defined. This method is part of the Custom Elements lifecycle and will be called once the component is created. Next to this method the following methods are defined in the lifecycle:
-
-* `createdCallback`
-* `attachedCallback`
-* `detachedCallback`
-* `attributeChangedCallback(attrName, oldVal, newVal)`
-
-## HTML Imports
-
-When using the first 3 specs we can define reusable components in our HTML page. But all the code is still part of our HTML (or JavaScript) file. This is ok if we only want to create a single HTML page. But when creating a big application you will have several HTML files and you don't want to define the reusable components on any page. Therefore the `import` can be used. By doing so you can specify a reusable component in a extracted HTML file that can be reused on any page. By doing so it's even easy to create components that can be shared between several projects.
-
-Using the import is easy. You only need to specify an import link that points to the file that contains the component specification:
-
-{{< highlight html >}}
-
-{{< / highlight >}}
-
-Once this is done you can simply use the custom component in the page.
-
-## Concusion
-
-This is only a quick overview to the new specifications without going to much into details. If you want to learn more you should have a look at our slides or additional documentation on the web.
-
-[slideshare id=44255563&doc=jfocus-webcomponents-final-150204052708-conversion-gate01]
-
-A god starting point is the [webcomponents.org](http://webcomponents.org) page that contains a lot of documentation.
-
-When trying to create your first own web component you will maybe see a big problem: Today most of the modern browsers don't support this new specs.
-
-
-
-As a workaround you can use the __webcomponents.js polypill__ that will add the support of the shown specs to mostly all evergreen browsers. I plan to give an introduction to this polypill in a separate post.
+---
+outdated: true
+showInBlog: false
+title: 'An overview of the Web Component specifications'
+date: "2015-02-15"
+author: hendrik
+categories: [General, WebComponents]
+excerpt: 'This gives a short overview to the four W3C specs to define reusable web components: Element Template, Shadow DOM, Custom Elements and HTML Imports'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+WebComponents are a new W3C standard that is defined by some new specification:
+
+* Element Template
+* Shadow DOM
+* Custom Elements
+* HTML Imports
+
+An overview about this specs and how they can be used in HTML can be found in the presentation that I did with [Michael Heinrichs](https://twitter.com/net0pyr) at JFokus in detail. Therefore I only want a short overview here.
+
+## Element Template
+
+By using the template tag you can define a reusable template of a HTML hierarchy that can be reused and added to your DOM. Let's say you define the following template:
+
+
+
+Once you have defined this template you can create a instance in JavaScript and add it to the DOM of the page:
+
+
+
+By doing so you can reuse the defined template several times in your page.
+
+## Shadow DOM
+
+Let's say you have defined a template (or a web component as we will see later) and use it in your application. By doing so the DOM of your component will be added to the page DOM. If you than want to style your page by using CSS or access the page by JavaScript there are some pitfalls. As an example the following DOM is created and a component (green) is added to the regular DOM (blue). A node in the page and in the component uses the same ID or style class:
+
+
+
+Maybe the component was created by a different developer or it is part of a 3rd party module. In this case you maybe don't know about the internal IDs or style classes. When styling or modifying your application you would use the following code:
+
+```js//JavaScript
+document.querySelector(".content")
+
+//CSS
+.content {
+ color: blue;
+}
```
+
+In both cases your code will affect the node in the regular DOM and in the component. But normally you don't want to change the component. Therefore the Shadow DOM was introduced. By using the shadow DOM the nodes of the component are separated from the regular DOM:
+
+
+
+Once this is done CSS or JavaScript changes won't affect the component that is capsulated by the Shadow DOM. A component in a Shadow DOM can be created by using JavaScript:
+
+```jsvar root = host.createShadowRoot();
+var clone = document.importNode(template.content, true);
+root.appendChild(clone);
```
+
+## Custom Elements
+
+The Custom Elements spec makes use of templates and the shadow DOM. By doing so you can specify a component and add it to a page in a Shadow DOM. In addition the spec defines a lifecylce for components.
+
+By using the Custom Elements spec you can define reusable tags for your components. Let's say you want to define a activity stream like in Facebook or Twitter. To do so we want to create a custom element for the entries in this stream.
+
+
+
+Normally you need to define a div hierarchy for any entry in the stream. This ends in a lot of boilerplate code like shown in the following snippet:
+
+```html
```
+
+This don't look readable and what we really want to do is something like this:
+
+```html
+ Michael had fun writing web components.
+
+
+ Hendrik blogged on GuiGarage.
+
```
+
+This can be done by using Custom Elements. To do so we first create a template:
+
+```html
+
+
+
+
+
+
```
+
+Once this is done we need to write some JavaScript code to create a custom element that is based on this template:
+
+```jsvar importDoc = document.currentScript.ownerDocument;
+ var activityPrototype = Object.create(HTMLElement.prototype);
+
+ activityPrototype.createdCallback = function() {
+ var template = importDoc.querySelector('template');
+ var clone = document.importNode(template.content, true);
+
+ var host = $(this);
+ $(".icon", clone).attr("src", host.attr("iconSrc"));
+ $(".time", clone).text(host.attr("time"));
+
+ var shadowRoot = this.createShadowRoot();
+ shadowRoot.appendChild(clone);
+ };
+
+ // Register our new element
+ document.registerElement('activity-card', {
+ prototype: activityPrototype
+ });
```
+
+Once this is done the `activity-card` tag can be used in our application. In the JavaScript code a method called `createdCallback` is defined. This method is part of the Custom Elements lifecycle and will be called once the component is created. Next to this method the following methods are defined in the lifecycle:
+
+* `createdCallback`
+* `attachedCallback`
+* `detachedCallback`
+* `attributeChangedCallback(attrName, oldVal, newVal)`
+
+## HTML Imports
+
+When using the first 3 specs we can define reusable components in our HTML page. But all the code is still part of our HTML (or JavaScript) file. This is ok if we only want to create a single HTML page. But when creating a big application you will have several HTML files and you don't want to define the reusable components on any page. Therefore the `import` can be used. By doing so you can specify a reusable component in a extracted HTML file that can be reused on any page. By doing so it's even easy to create components that can be shared between several projects.
+
+Using the import is easy. You only need to specify an import link that points to the file that contains the component specification:
+
+```html
```
+
+Once this is done you can simply use the custom component in the page.
+
+## Concusion
+
+This is only a quick overview to the new specifications without going to much into details. If you want to learn more you should have a look at our slides or additional documentation on the web.
+
+[slideshare id=44255563&doc=jfocus-webcomponents-final-150204052708-conversion-gate01]
+
+A god starting point is the [webcomponents.org](http://webcomponents.org) page that contains a lot of documentation.
+
+When trying to create your first own web component you will maybe see a big problem: Today most of the modern browsers don't support this new specs.
+
+
+
+As a workaround you can use the __webcomponents.js polypill__ that will add the support of the shown specs to mostly all evergreen browsers. I plan to give an introduction to this polypill in a separate post.
diff --git a/content/posts/2015-07-10-material-design-in-javafx.md b/content/posts/2015-07-10-material-design-in-javafx.md
index 8324d8fe..15e87764 100644
--- a/content/posts/2015-07-10-material-design-in-javafx.md
+++ b/content/posts/2015-07-10-material-design-in-javafx.md
@@ -20,4 +20,4 @@ The source of the project [can be found at GitHub](https://github.com/guigarage/
The entry point of the demo application can be found at [`com.guigarage.sdk.demos.SimpleViewAppDemo1`](https://github.com/guigarage/sdkfx/blob/master/src/main/java/com/guigarage/sdk/demos/SimpleViewAppDemo1.java) and by starting this application you can play with the first demo. An overview of this application can be found in this video:
-{{< youtube 3hnYnEm6sHA >}}
+
diff --git a/content/posts/2015-09-06-cool-javafx-uis-in-less-time-use-projection.md b/content/posts/2015-09-06-cool-javafx-uis-in-less-time-use-projection.md
index b2e4b8a2..022b927f 100644
--- a/content/posts/2015-09-06-cool-javafx-uis-in-less-time-use-projection.md
+++ b/content/posts/2015-09-06-cool-javafx-uis-in-less-time-use-projection.md
@@ -1,67 +1,63 @@
----
-outdated: true
-showInBlog: false
-title: 'Cool JavaFX UIs in less time? Use projection!'
-date: "2015-09-06"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'This post shows how you can create UIs by using metadata and the projection pattern in JavaFX. By doing so all developers can create cool UIs.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Some weeks ago I blogged about [my first Material Design approach in JavaFX]({{< ref "/posts/2015-07-10-material-design-in-javafx" >}}). But the project contains more than just some new styles for JavaFX. In the project I tried some technics to create good looking application without spending much time in styling. Therefore I created some basic Java layout and styles that will automatically be used for specific data types. It's like projecting the raw data in a nice UI. The basic idea of this approach evolved after some discussions with [Dierk König](https://twitter.com/mittie). In addition Twitter Bootstrap already offers some styles and layouts that I reused here.
-
-## Project your data to the view
-
-Let's have a deeper look how this small approach is working. In the Material Design demo I created a basic interface called [Media](https://github.com/guigarage/sdkfx/blob/master/src/main/java/com/guigarage/sdk/util/Media.java). This interface defines a basic data structures that can hold an image, a title and a description:
-
-{{< highlight java >}}
-public interface Media {
-
- StringProperty titleProperty();
-
- StringProperty descriptionProperty();
-
- ObjectProperty imageProperty();
-}
-{{< / highlight >}}
-
-When creating your own custom data model you can simply create complete classes that implement the interface and export some basic metadata based of the class by using the interface. The project includes a basic implementation of the interface called [DefaultMedia](https://github.com/guigarage/sdkfx/blob/master/src/main/java/com/guigarage/sdk/util/DefaultMedia.java).
-
-Let's think about a possible visual presentation of this interface. When having a look at Twitter Bootstrap you can find an example. Bootstrap provides the [media object](http://getbootstrap.com/components/#media) that can simply be used to render media data:
-
-
-
-I already created a JavaFX list cell that specifies a layout that can be used for media objects. You can find a detailed description [here]({{< ref "/posts/2014-09-30-enrich-list-ui-using-medialistcell" >}}). Based on this I created the MediaList that is completely ready to render media and don't need to be configured anymore.
-
-{{< highlight java >}}
-MediaList list = new MediaList<>();
-list.getItems().add(new DefaultMedia("Test01", "This is the description", image1));
-list.getItems().add(new DefaultMedia("Test02", "This is the description", image2));
-list.getItems().add(new DefaultMedia("Test03", "This is the description", image3));
-list.getItems().add(new DefaultMedia("Test04", "This is the description", image4));
-list.getItems().add(new DefaultMedia("Test05", "This is the description", image5));
-{{< / highlight >}}
-
-By using the MediaList class you simply create a list like this one:
-
-
-
-But this isn't the only view in the material design example that is based on the Media definition. Next to the list the user info panel uses a media object internally:
-
-
-
-The next one is the image view that contains a description of the shown image:
-
-
-
-As you can see there are several examples how a simple data definition like the shown Media interface can be rendered on screen. Currently I'm working on a table that support the Media object.
-
-
-
-In the table implementation I experiment how such a control can easily be configured. So stay tuned ;)
-
-## Why should we use such a concept?
-
-I think there are several benefits in the media example. If you want to visualize some data that will match in the given format you don't need to think about the visualization. If you want to show a list, a table or just one element there are several ready to use containers / controls. Each of this controls defines a different projection of the data to the screen. Developers that aren't familiar with custom controls or styling of application can use this concepts to create good looking applications from scratch.
-
-The Media interface is just a beginning here and is still very limited in the way how it can be used and displayed. In addition it must fit to your data model. But as said I think that this is only the start. You can create a form layout based on the same concepts. Let's think you have a FormData interface that defines the data that should be displayed in a form and adds some metadate like the label texts and so on. I'm currently thinking about concepts for complex scenarios and how such interfaces might look like. If you want to have a first look you can check the [form classes](https://github.com/guigarage/sdkfx/tree/master/src/main/java/com/guigarage/sdk/form) in my material design example.
+---
+outdated: true
+showInBlog: false
+title: 'Cool JavaFX UIs in less time? Use projection!'
+date: "2015-09-06"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'This post shows how you can create UIs by using metadata and the projection pattern in JavaFX. By doing so all developers can create cool UIs.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Some weeks ago I blogged about [my first Material Design approach in JavaFX](/posts/2015-07-10-material-design-in-javafx). But the project contains more than just some new styles for JavaFX. In the project I tried some technics to create good looking application without spending much time in styling. Therefore I created some basic Java layout and styles that will automatically be used for specific data types. It's like projecting the raw data in a nice UI. The basic idea of this approach evolved after some discussions with [Dierk König](https://twitter.com/mittie). In addition Twitter Bootstrap already offers some styles and layouts that I reused here.
+
+## Project your data to the view
+
+Let's have a deeper look how this small approach is working. In the Material Design demo I created a basic interface called [Media](https://github.com/guigarage/sdkfx/blob/master/src/main/java/com/guigarage/sdk/util/Media.java). This interface defines a basic data structures that can hold an image, a title and a description:
+
+```javapublic interface Media {
+
+ StringProperty titleProperty();
+
+ StringProperty descriptionProperty();
+
+ ObjectProperty imageProperty();
+}
```
+
+When creating your own custom data model you can simply create complete classes that implement the interface and export some basic metadata based of the class by using the interface. The project includes a basic implementation of the interface called [DefaultMedia](https://github.com/guigarage/sdkfx/blob/master/src/main/java/com/guigarage/sdk/util/DefaultMedia.java).
+
+Let's think about a possible visual presentation of this interface. When having a look at Twitter Bootstrap you can find an example. Bootstrap provides the [media object](http://getbootstrap.com/components/#media) that can simply be used to render media data:
+
+
+
+I already created a JavaFX list cell that specifies a layout that can be used for media objects. You can find a detailed description [here](/posts/2014-09-30-enrich-list-ui-using-medialistcell). Based on this I created the MediaList that is completely ready to render media and don't need to be configured anymore.
+
+```javaMediaList list = new MediaList<>();
+list.getItems().add(new DefaultMedia("Test01", "This is the description", image1));
+list.getItems().add(new DefaultMedia("Test02", "This is the description", image2));
+list.getItems().add(new DefaultMedia("Test03", "This is the description", image3));
+list.getItems().add(new DefaultMedia("Test04", "This is the description", image4));
+list.getItems().add(new DefaultMedia("Test05", "This is the description", image5));
```
+
+By using the MediaList class you simply create a list like this one:
+
+
+
+But this isn't the only view in the material design example that is based on the Media definition. Next to the list the user info panel uses a media object internally:
+
+
+
+The next one is the image view that contains a description of the shown image:
+
+
+
+As you can see there are several examples how a simple data definition like the shown Media interface can be rendered on screen. Currently I'm working on a table that support the Media object.
+
+
+
+In the table implementation I experiment how such a control can easily be configured. So stay tuned ;)
+
+## Why should we use such a concept?
+
+I think there are several benefits in the media example. If you want to visualize some data that will match in the given format you don't need to think about the visualization. If you want to show a list, a table or just one element there are several ready to use containers / controls. Each of this controls defines a different projection of the data to the screen. Developers that aren't familiar with custom controls or styling of application can use this concepts to create good looking applications from scratch.
+
+The Media interface is just a beginning here and is still very limited in the way how it can be used and displayed. In addition it must fit to your data model. But as said I think that this is only the start. You can create a form layout based on the same concepts. Let's think you have a FormData interface that defines the data that should be displayed in a form and adds some metadate like the label texts and so on. I'm currently thinking about concepts for complex scenarios and how such interfaces might look like. If you want to have a first look you can check the [form classes](https://github.com/guigarage/sdkfx/tree/master/src/main/java/com/guigarage/sdk/form) in my material design example.
diff --git a/content/posts/2015-09-09-how-to-create-a-responsive-layout-in-javafx.md b/content/posts/2015-09-09-how-to-create-a-responsive-layout-in-javafx.md
index df520fbb..66dd7bcf 100644
--- a/content/posts/2015-09-09-how-to-create-a-responsive-layout-in-javafx.md
+++ b/content/posts/2015-09-09-how-to-create-a-responsive-layout-in-javafx.md
@@ -1,198 +1,190 @@
----
-outdated: true
-showInBlog: false
-title: 'How to create a responsive layout in JavaFX'
-date: "2015-09-09"
-author: hendrik
-categories: [JavaFX, Layout & UI]
-excerpt: 'Some days ago I was asked at twitter about a responsive layout problem in JavaFX. Here I will show how a first solution to create such a responsive layout.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Some days ago [I was asked at twitter about a responsive layout problem in JavaFX](https://twitter.com/j_e_willis/status/641000236119257088). Based on the work that I did with [ResponsiveFX]({{< ref "/posts/2014-11-04-responsive-design-javafx" >}}) I was asked how I would create a specific responsive behavior.
-
-In this special case, an image and a text should next to each other on a desktop. In a smaller (mobile) version the text should be placed under the image. You can find the [question at stackoverflow](http://stackoverflow.com/questions/32021293/javafx-creating-a-responsive-layout), too.
-
-I want to start with a first look at how the solution should look like. The following picture shows the described layout on a big and on a small screen:
-
-
-
-Let's discuss several approaches that we can use to create this behavior.
-
-## Switch between HBox and VBox
-
-One suggested solution is to switch between an HBox and a VBox at runtime. This means that on a big screen you will see the image and text wrapped in an HBox and when the size becomes smaller the HBox will be replaced by a VBox. By doing so we need to discuss if we want to reuse the text and image component in both layouts or create a separate instance for each layout. Here I think that recycling of the components is a good idea. If you use 2 instances you need to sync them. By using the JavaFX property API this isn't as hard as it sounds in the first moment but it can still create some errors. So let's have a look at a code snippet that creates the basic view:
-
-{{< highlight java >}}
-public class ResponsiveLayoutDemo extends Application {
-
- private Label textLabel;
-
- private ImageView imageView;
-
- private HBox hBox;
-
- private StackPane mainPane;
-
- @Override
- public void start(Stage primaryStage) throws Exception {
- this.textLabel = new Label("Lorem ipsum dolor sit amet...");
- textLabel.setWrapText(true);
-
- this.imageView = new ImageView("http://goo.gl/1tEZxQ");
- imageView.setFitWidth(240);
- imageView.setPreserveRatio(true);
-
- hBox = new HBox();
- hBox.setSpacing(8);
-
- hBox.getChildren().addAll(imageView, textLabel);
-
- mainPane = new StackPane(hBox);
- mainPane.setPadding(new Insets(24));
-
- primaryStage.setScene(new Scene(mainPane));
- primaryStage.show();
- }
-
- public static void main(String... args) {
- launch(args);
- }
-}
-{{< / highlight >}}
-
-When running this example the view will be shown with the text and image next to each other:
-
-
-
-As a next step we want to refactor the code by using a VBox:
-
-{{< highlight java >}}
-public class ResponsiveLayoutDemo extends Application {
-
- private Label textLabel;
-
- private ImageView imageView;
-
- private VBox vBox;
-
- private StackPane mainPane;
-
- @Override
- public void start(Stage primaryStage) throws Exception {
- this.textLabel = new Label("Lorem ipsum dolor sit amet...");
- textLabel.setWrapText(true);
-
- this.imageView = new ImageView("http://goo.gl/1tEZxQ");
- imageView.setFitWidth(240);
- imageView.setPreserveRatio(true);
-
- vBox = new VBox();
- vBox.setSpacing(8);
-
- vBox.getChildren().addAll(imageView, textLabel);
-
- mainPane = new StackPane(vBox);
- mainPane.setPadding(new Insets(24));
-
- primaryStage.setScene(new Scene(mainPane));
- primaryStage.show();
- }
-
- public static void main(String... args) {
- launch(args);
- }
-}
-{{< / highlight >}}
-
-In this example the text will be displayed under the image as it should look on small devices:
-
-
-
-As a last step we want to modify the code and create an application that will change it's layout dynamically:
-
-{{< highlight java >}}
-public class ResponsiveLayoutDemo extends Application {
-
- private Label textLabel;
-
- private ImageView imageView;
-
- private VBox vBox;
-
- private HBox hBox;
-
- private StackPane mainPane;
-
- @Override
- public void start(Stage primaryStage) throws Exception {
- this.textLabel = new Label("Lorem ipsum dolor sit amet...");
- textLabel.setWrapText(true);
-
- this.imageView = new ImageView("http://goo.gl/1tEZxQ");
- imageView.setFitWidth(240);
- imageView.setPreserveRatio(true);
-
- hBox = new HBox();
- hBox.setSpacing(8);
-
- vBox = new VBox();
- vBox.setSpacing(8);
-
- mainPane = new StackPane();
- mainPane.setPadding(new Insets(24));
-
- changeToLargeLayout();
-
- primaryStage.widthProperty().addListener(e -> {
- if(primaryStage.getWidth() < 600) {
- changeToSmallLayout();
- } else {
- changeToLargeLayout();
- }
- });
-
- primaryStage.setScene(new Scene(mainPane));
- primaryStage.show();
- }
-
- public void changeToSmallLayout() {
- hBox.getChildren().clear();
- vBox.getChildren().clear();
- vBox.getChildren().addAll(imageView, textLabel);
- mainPane.getChildren().clear();
- mainPane.getChildren().add(vBox);
- }
-
- public void changeToLargeLayout() {
- hBox.getChildren().clear();
- vBox.getChildren().clear();
- hBox.getChildren().addAll(imageView, textLabel);
- mainPane.getChildren().clear();
- mainPane.getChildren().add(hBox);
- }
-
- public static void main(String... args) {
- launch(args);
- }
-}
-{{< / highlight >}}
-
-In this first try, the mainPane contains the hBox or the vBox depending on the width of the scene. To do so a lister is attached to the width property. In addition, the children of the vBox and hBox will be cleared and the text and image will be attached to the currently visible panel. As you can see in this video the view already behaves as it should:
-
-{{< youtube wEt8WKDR7r8 >}}
-
-
There are still some ugly parts in the code. As you might have noticed the listener will be called for each repaint of our stage. therefore nodes will be replaced and added to the scene graph all the time. Here we can use the JavaFX binding API to create a more performant binding. Here is the code snippet that shows the changed code:
-
-{{< highlight java >}}
-primaryStage.widthProperty().greaterThan(600).addListener((obs, oldValue, newValue) -> {
- if (!newValue) {
- changeToSmallLayout();
- } else {
- changeToLargeLayout();
- }
- });
-{{< / highlight >}}
-
-Now the scene graph will only be changed if the size will become greater or smaller than 600 pixels.
-
-I think this is a valid solution for the given problem and we can create a responsive behavior this way. But I think that it's not the perfect solution and therefore I will show another and easier approach the next days.
+---
+outdated: true
+showInBlog: false
+title: 'How to create a responsive layout in JavaFX'
+date: "2015-09-09"
+author: hendrik
+categories: [JavaFX, Layout & UI]
+excerpt: 'Some days ago I was asked at twitter about a responsive layout problem in JavaFX. Here I will show how a first solution to create such a responsive layout.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Some days ago [I was asked at twitter about a responsive layout problem in JavaFX](https://twitter.com/j_e_willis/status/641000236119257088). Based on the work that I did with [ResponsiveFX](/posts/2014-11-04-responsive-design-javafx) I was asked how I would create a specific responsive behavior.
+
+In this special case, an image and a text should next to each other on a desktop. In a smaller (mobile) version the text should be placed under the image. You can find the [question at stackoverflow](http://stackoverflow.com/questions/32021293/javafx-creating-a-responsive-layout), too.
+
+I want to start with a first look at how the solution should look like. The following picture shows the described layout on a big and on a small screen:
+
+
+
+Let's discuss several approaches that we can use to create this behavior.
+
+## Switch between HBox and VBox
+
+One suggested solution is to switch between an HBox and a VBox at runtime. This means that on a big screen you will see the image and text wrapped in an HBox and when the size becomes smaller the HBox will be replaced by a VBox. By doing so we need to discuss if we want to reuse the text and image component in both layouts or create a separate instance for each layout. Here I think that recycling of the components is a good idea. If you use 2 instances you need to sync them. By using the JavaFX property API this isn't as hard as it sounds in the first moment but it can still create some errors. So let's have a look at a code snippet that creates the basic view:
+
+```javapublic class ResponsiveLayoutDemo extends Application {
+
+ private Label textLabel;
+
+ private ImageView imageView;
+
+ private HBox hBox;
+
+ private StackPane mainPane;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ this.textLabel = new Label("Lorem ipsum dolor sit amet...");
+ textLabel.setWrapText(true);
+
+ this.imageView = new ImageView("http://goo.gl/1tEZxQ");
+ imageView.setFitWidth(240);
+ imageView.setPreserveRatio(true);
+
+ hBox = new HBox();
+ hBox.setSpacing(8);
+
+ hBox.getChildren().addAll(imageView, textLabel);
+
+ mainPane = new StackPane(hBox);
+ mainPane.setPadding(new Insets(24));
+
+ primaryStage.setScene(new Scene(mainPane));
+ primaryStage.show();
+ }
+
+ public static void main(String... args) {
+ launch(args);
+ }
+}
```
+
+When running this example the view will be shown with the text and image next to each other:
+
+
+
+As a next step we want to refactor the code by using a VBox:
+
+```javapublic class ResponsiveLayoutDemo extends Application {
+
+ private Label textLabel;
+
+ private ImageView imageView;
+
+ private VBox vBox;
+
+ private StackPane mainPane;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ this.textLabel = new Label("Lorem ipsum dolor sit amet...");
+ textLabel.setWrapText(true);
+
+ this.imageView = new ImageView("http://goo.gl/1tEZxQ");
+ imageView.setFitWidth(240);
+ imageView.setPreserveRatio(true);
+
+ vBox = new VBox();
+ vBox.setSpacing(8);
+
+ vBox.getChildren().addAll(imageView, textLabel);
+
+ mainPane = new StackPane(vBox);
+ mainPane.setPadding(new Insets(24));
+
+ primaryStage.setScene(new Scene(mainPane));
+ primaryStage.show();
+ }
+
+ public static void main(String... args) {
+ launch(args);
+ }
+}
```
+
+In this example the text will be displayed under the image as it should look on small devices:
+
+
+
+As a last step we want to modify the code and create an application that will change it's layout dynamically:
+
+```javapublic class ResponsiveLayoutDemo extends Application {
+
+ private Label textLabel;
+
+ private ImageView imageView;
+
+ private VBox vBox;
+
+ private HBox hBox;
+
+ private StackPane mainPane;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ this.textLabel = new Label("Lorem ipsum dolor sit amet...");
+ textLabel.setWrapText(true);
+
+ this.imageView = new ImageView("http://goo.gl/1tEZxQ");
+ imageView.setFitWidth(240);
+ imageView.setPreserveRatio(true);
+
+ hBox = new HBox();
+ hBox.setSpacing(8);
+
+ vBox = new VBox();
+ vBox.setSpacing(8);
+
+ mainPane = new StackPane();
+ mainPane.setPadding(new Insets(24));
+
+ changeToLargeLayout();
+
+ primaryStage.widthProperty().addListener(e -> {
+ if(primaryStage.getWidth() < 600) {
+ changeToSmallLayout();
+ } else {
+ changeToLargeLayout();
+ }
+ });
+
+ primaryStage.setScene(new Scene(mainPane));
+ primaryStage.show();
+ }
+
+ public void changeToSmallLayout() {
+ hBox.getChildren().clear();
+ vBox.getChildren().clear();
+ vBox.getChildren().addAll(imageView, textLabel);
+ mainPane.getChildren().clear();
+ mainPane.getChildren().add(vBox);
+ }
+
+ public void changeToLargeLayout() {
+ hBox.getChildren().clear();
+ vBox.getChildren().clear();
+ hBox.getChildren().addAll(imageView, textLabel);
+ mainPane.getChildren().clear();
+ mainPane.getChildren().add(hBox);
+ }
+
+ public static void main(String... args) {
+ launch(args);
+ }
+}
```
+
+In this first try, the mainPane contains the hBox or the vBox depending on the width of the scene. To do so a lister is attached to the width property. In addition, the children of the vBox and hBox will be cleared and the text and image will be attached to the currently visible panel. As you can see in this video the view already behaves as it should:
+
+
+
+
There are still some ugly parts in the code. As you might have noticed the listener will be called for each repaint of our stage. therefore nodes will be replaced and added to the scene graph all the time. Here we can use the JavaFX binding API to create a more performant binding. Here is the code snippet that shows the changed code:
+
+```javaprimaryStage.widthProperty().greaterThan(600).addListener((obs, oldValue, newValue) -> {
+ if (!newValue) {
+ changeToSmallLayout();
+ } else {
+ changeToLargeLayout();
+ }
+ });
```
+
+Now the scene graph will only be changed if the size will become greater or smaller than 600 pixels.
+
+I think this is a valid solution for the given problem and we can create a responsive behavior this way. But I think that it's not the perfect solution and therefore I will show another and easier approach the next days.
diff --git a/content/posts/2015-09-11-creating-an-interactive-application-with-polymer-part-1.md b/content/posts/2015-09-11-creating-an-interactive-application-with-polymer-part-1.md
index 6a832f14..dbae7aac 100644
--- a/content/posts/2015-09-11-creating-an-interactive-application-with-polymer-part-1.md
+++ b/content/posts/2015-09-11-creating-an-interactive-application-with-polymer-part-1.md
@@ -1,368 +1,348 @@
----
-outdated: true
-showInBlog: false
-title: 'Creating an interactive application with Polymer (Part 1)'
-date: "2015-09-11"
-author: hendrik
-categories: [Polymer, Web Frontends, WebComponents]
-excerpt: 'In this post I will create an interactive web application based on Polymer 1.0 to show how data binding can be used and how a basic app might look like.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Some time ago I created [my first post about web components]({{< ref "/posts/2014-11-12-first-steps-webcomponents" >}}) and today I want to continue this series. In the last month I played a lot with this new technology since at Canoo we think that this will be very important for web development in the future. Therefore [Michael Heinrichs](https://twitter.com/net0pyr) and I will give [a university session at Devoxx](http://cfp.devoxx.be/2015/talk/OVY-1576/Building_modern_web_UIs_with_Web_Components) this year and plan to offer web component and Polymer training at Canoo.
-
-In this blog post I will create an interactive web application based on Google Polymer 1.0 to show how data binding can be used and how a basic Polymer application might look like. In this case I don't want to dive deep into the creation of custom components using Polymer but give a first introduction how you can design applications by using the Polymer paper elements.
-
-## What is Polymer?
-
-[Google Polymer](https://www.polymer-project.org/1.0/) is an open source toolkit that is build based on the [web component specification]({{< ref "/posts/2015-02-15-use-webcomponents-today" >}}) and provides some additional features. In addition Polymer provides it's own UI component suite that is based on the [Material Design style by Google](https://www.google.com/design/spec/material-design/introduction.html).
-
-
-
-Based on Polymer and web components it's very easy to create a web application that is based on custom components instead falling in the `
` hell.
-
-Here is a short example that shows how a Google maps web component can be integrated in any web page:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-
-
-Polymer provides an [element catalog](https://elements.polymer-project.org) with documentation and many examples of all components that are part of the lib.
-
-## Project setup
-
-Let's start with a first project that uses Polymer and the Polymer paper components to create an application. This project only needs 2 file:
-
-* a `index.html` that contains our application
-* a `bower.json` that defines all external dependencies
-
-Our final application should be a picture viewer that support some user interaction. I want to change the size of all images by using a slider. Here is a first sketch:
-
-
-
-To use the Polymer paper components we only need 1 dependency to `PolymerElements/paper-elements` in the bower file. If you are not familiar with [Bower](http://bower.io) you can find a short introduction [here]({{< ref "/posts/2015-02-12-short-introduction-bower" >}}).
-
-Once you have added the dependency your bower.json file like look like this:
-
-{{< highlight json >}}
-{
- "name": "polymer-interaction",
- "version": "1.0.0",
- "authors": [
- "Hendrik Ebbers "
- ],
- "license": "MIT",
- "ignore": [
- "**/.*",
- "node_modules",
- "bower_components",
- "test",
- "tests"
- ],
- "dependencies": {
- "paper-elements": "PolymerElements/paper-elements#1.0.5"
- }
-}
-{{< / highlight >}}
-
-After calling `bower install` all dependencies are downloaded to the `bower_components` folder. This includes:
-
-* `webcomponentsjs` - A [polyfill](https://en.wikipedia.org/wiki/Polyfill) that provides the features of the web components spec for browser version that doesn't support native support for the features
-* `polymer` - the basic api of polymer.
-* `paper-*` - all Polymer paper components like controls and layouts
-* `iron-*` - basic web components like an icon view. The Polymer paper components are based on this basic components
-
-Once this is done we can create the initial `index.html` file. Here we will start to provide the functionality of the web components spec by adding the polypill. To do so we include the script in our page:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-Now we can start using the new features. We want to start with the import. In our example we need the Polymer API and some paper components. Therefore we add imports to all these dependencies:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-The paper elements already depends on the Polymer API and therefore we don't need to add it explicitly.
-
-## Starting with Polymer
-
-Since Polymer is a framework for web components we will create a component that wraps our complete application view. To do so we need a html template and some JavaScript for the Polymer boostrap / configuration. A first simple example of such a component looks like this:
-
-{{< highlight html >}}
-
-
- CONTENT
-
-
-
-
-{{< / highlight >}}
-
-This code snippet defines a Polymer based web component that can be added to a html page by using the `` tag (as defined in the polymer id). This web component only contains the static text "Content". Let's add this code snippet and the custom tag to our `index.html`:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CONTENT
-
-
-
-
-
-
-{{< / highlight >}}
-
-Here is a pic of the current state in chrome:
-
-
-
-As a Java developer I simply use IntelliJ to test my app. By opening the page from IntelliJ the IDE starts automatically a web server to provide the web app.
-
-
-
-If you don't use IntelliJ there are [several](https://developers.google.com/web/tools/polymer-starter-kit/) [other](https://www.npmjs.com/package/gulp-webserver) [ways](http://www.linuxjournal.com/content/tech-tip-really-simple-http-server-python) how you can test your app.
-
-Let's add some first Polymer paper elements. Here I want to start with a [`paper-header-panel`](https://elements.polymer-project.org/elements/paper-header-panel) that defines a header and a content area. The header area is always on top and you can use it perfectly to display a toolbar. The content are will fill the rest of the page size and is scrollable by default.
-
-
-
-In this header panel we want to add a toolbar with a title and a slider. For all these components Polymer paper offers ready to use web components. How this components can be used is documented in the [Polymer elements catalog](https://elements.polymer-project.org). Once this is done our code look like this:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Polymer interaction
-
-
-
CONTENT
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-In chrome we can already see the toolbar but the layout doesn't look that perfect:
-
-
-
-Polymer provides a [flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) based layout that can be simply modified by using custom attributes that are [provided by Polymer](https://elements.polymer-project.org/guides/flex-layout). I don't want to dive deep here in flexbox and Polymer layout (since this post is already very long) and simply show the final code:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Polymer interaction
-
-
-
- Content
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-
-
-Ok, as a next step I want to add some static images. Therefore I will use [lorempixel.com](http://lorempixel.com) that is a perfect service to get some random images. After adding some images to the content as shown in the following code snippet our application already look like some kind of image viewer:
-
-{{< highlight html >}}
-
-
-
-
- ...
-
-{{< / highlight >}}
-
-
-
-Thanks to the flex box layout that is used in Polymer the images are aligned in a responsive grid. When resizing the browser windows the column count in each row will fit to the width of the browser. In addition a scrollbar automatically appears if all images can't be shown on screen.
-
-As a next step I want to finalize the styling of our application by adding some CSS. Here is the final html file:
-
-{{< highlight html >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Polymer interaction
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-
-
-Ok, this will be enough for today :)
-
-In the next post I will show how the Polymer properties and data binding can be used to create the needed interaction.
+---
+outdated: true
+showInBlog: false
+title: 'Creating an interactive application with Polymer (Part 1)'
+date: "2015-09-11"
+author: hendrik
+categories: [Polymer, Web Frontends, WebComponents]
+excerpt: 'In this post I will create an interactive web application based on Polymer 1.0 to show how data binding can be used and how a basic app might look like.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Some time ago I created [my first post about web components](/posts/2014-11-12-first-steps-webcomponents) and today I want to continue this series. In the last month I played a lot with this new technology since at Canoo we think that this will be very important for web development in the future. Therefore [Michael Heinrichs](https://twitter.com/net0pyr) and I will give [a university session at Devoxx](http://cfp.devoxx.be/2015/talk/OVY-1576/Building_modern_web_UIs_with_Web_Components) this year and plan to offer web component and Polymer training at Canoo.
+
+In this blog post I will create an interactive web application based on Google Polymer 1.0 to show how data binding can be used and how a basic Polymer application might look like. In this case I don't want to dive deep into the creation of custom components using Polymer but give a first introduction how you can design applications by using the Polymer paper elements.
+
+## What is Polymer?
+
+[Google Polymer](https://www.polymer-project.org/1.0/) is an open source toolkit that is build based on the [web component specification](/posts/2015-02-15-use-webcomponents-today) and provides some additional features. In addition Polymer provides it's own UI component suite that is based on the [Material Design style by Google](https://www.google.com/design/spec/material-design/introduction.html).
+
+
+
+Based on Polymer and web components it's very easy to create a web application that is based on custom components instead falling in the `
` hell.
+
+Here is a short example that shows how a Google maps web component can be integrated in any web page:
+
+```html
+
+
+
+
+
+
+
```
+
+
+
+Polymer provides an [element catalog](https://elements.polymer-project.org) with documentation and many examples of all components that are part of the lib.
+
+## Project setup
+
+Let's start with a first project that uses Polymer and the Polymer paper components to create an application. This project only needs 2 file:
+
+* a `index.html` that contains our application
+* a `bower.json` that defines all external dependencies
+
+Our final application should be a picture viewer that support some user interaction. I want to change the size of all images by using a slider. Here is a first sketch:
+
+
+
+To use the Polymer paper components we only need 1 dependency to `PolymerElements/paper-elements` in the bower file. If you are not familiar with [Bower](http://bower.io) you can find a short introduction [here](/posts/2015-02-12-short-introduction-bower).
+
+Once you have added the dependency your bower.json file like look like this:
+
+```json{
+ "name": "polymer-interaction",
+ "version": "1.0.0",
+ "authors": [
+ "Hendrik Ebbers "
+ ],
+ "license": "MIT",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ],
+ "dependencies": {
+ "paper-elements": "PolymerElements/paper-elements#1.0.5"
+ }
+}
```
+
+After calling `bower install` all dependencies are downloaded to the `bower_components` folder. This includes:
+
+* `webcomponentsjs` - A [polyfill](https://en.wikipedia.org/wiki/Polyfill) that provides the features of the web components spec for browser version that doesn't support native support for the features
+* `polymer` - the basic api of polymer.
+* `paper-*` - all Polymer paper components like controls and layouts
+* `iron-*` - basic web components like an icon view. The Polymer paper components are based on this basic components
+
+Once this is done we can create the initial `index.html` file. Here we will start to provide the functionality of the web components spec by adding the polypill. To do so we include the script in our page:
+
+```html
+
+
+
+
+
+
+
+
+
```
+
+Now we can start using the new features. We want to start with the import. In our example we need the Polymer API and some paper components. Therefore we add imports to all these dependencies:
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+The paper elements already depends on the Polymer API and therefore we don't need to add it explicitly.
+
+## Starting with Polymer
+
+Since Polymer is a framework for web components we will create a component that wraps our complete application view. To do so we need a html template and some JavaScript for the Polymer boostrap / configuration. A first simple example of such a component looks like this:
+
+```html
+
+ CONTENT
+
+
+
+
```
+
+This code snippet defines a Polymer based web component that can be added to a html page by using the `` tag (as defined in the polymer id). This web component only contains the static text "Content". Let's add this code snippet and the custom tag to our `index.html`:
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CONTENT
+
+
+
+
+
+
```
+
+Here is a pic of the current state in chrome:
+
+
+
+As a Java developer I simply use IntelliJ to test my app. By opening the page from IntelliJ the IDE starts automatically a web server to provide the web app.
+
+
+
+If you don't use IntelliJ there are [several](https://developers.google.com/web/tools/polymer-starter-kit/) [other](https://www.npmjs.com/package/gulp-webserver) [ways](http://www.linuxjournal.com/content/tech-tip-really-simple-http-server-python) how you can test your app.
+
+Let's add some first Polymer paper elements. Here I want to start with a [`paper-header-panel`](https://elements.polymer-project.org/elements/paper-header-panel) that defines a header and a content area. The header area is always on top and you can use it perfectly to display a toolbar. The content are will fill the rest of the page size and is scrollable by default.
+
+
+
+In this header panel we want to add a toolbar with a title and a slider. For all these components Polymer paper offers ready to use web components. How this components can be used is documented in the [Polymer elements catalog](https://elements.polymer-project.org). Once this is done our code look like this:
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Polymer interaction
+
+
+
CONTENT
+
+
+
+
+
+
+
```
+
+In chrome we can already see the toolbar but the layout doesn't look that perfect:
+
+
+
+Polymer provides a [flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) based layout that can be simply modified by using custom attributes that are [provided by Polymer](https://elements.polymer-project.org/guides/flex-layout). I don't want to dive deep here in flexbox and Polymer layout (since this post is already very long) and simply show the final code:
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Polymer interaction
+
+
+
+ Content
+
+
+
+
+
+
+
+
```
+
+
+
+Ok, as a next step I want to add some static images. Therefore I will use [lorempixel.com](http://lorempixel.com) that is a perfect service to get some random images. After adding some images to the content as shown in the following code snippet our application already look like some kind of image viewer:
+
+```html
+
+
+
+ ...
+
```
+
+
+
+Thanks to the flex box layout that is used in Polymer the images are aligned in a responsive grid. When resizing the browser windows the column count in each row will fit to the width of the browser. In addition a scrollbar automatically appears if all images can't be shown on screen.
+
+As a next step I want to finalize the styling of our application by adding some CSS. Here is the final html file:
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Polymer interaction
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+
+
+Ok, this will be enough for today :)
+
+In the next post I will show how the Polymer properties and data binding can be used to create the needed interaction.
diff --git a/content/posts/2015-09-16-layered-images-and-icons-with-javafx.md b/content/posts/2015-09-16-layered-images-and-icons-with-javafx.md
index 06c1ae0e..f45c7cd4 100644
--- a/content/posts/2015-09-16-layered-images-and-icons-with-javafx.md
+++ b/content/posts/2015-09-16-layered-images-and-icons-with-javafx.md
@@ -16,4 +16,4 @@ Since I have to wait 1 more month I started to recreate the effect by using Java
Here is a first preview (and yes I only used JavaFX to create this):
-{{< youtube zLR7oCh7U5g >}}
+
diff --git a/content/posts/2015-09-18-more-fun-with-layered-icons-in-javafx.md b/content/posts/2015-09-18-more-fun-with-layered-icons-in-javafx.md
index 4428a83c..57427f01 100644
--- a/content/posts/2015-09-18-more-fun-with-layered-icons-in-javafx.md
+++ b/content/posts/2015-09-18-more-fun-with-layered-icons-in-javafx.md
@@ -8,7 +8,7 @@ categories: [JavaFX, Layout & UI]
excerpt: 'Some cool JavaFX based demos of layered icons that copies the visualization of the new AppleTV icons.'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-2 days ago [I showed the first demo]({{< ref "/posts/2015-09-16-layered-images-and-icons-with-javafx" >}}) of my layered icon component for JavaFX that copies the visualization of the new AppleTV icons. Yesterday evening I created some cool new layered icons based on this technology and recorded a video of the examples (I describe the effects and some first techniques in the movie). Hopefully I find some time to describe the used technology in detail. Since this will be a longer post it sadly needs some time...
+2 days ago [I showed the first demo](/posts/2015-09-16-layered-images-and-icons-with-javafx) of my layered icon component for JavaFX that copies the visualization of the new AppleTV icons. Yesterday evening I created some cool new layered icons based on this technology and recorded a video of the examples (I describe the effects and some first techniques in the movie). Hopefully I find some time to describe the used technology in detail. Since this will be a longer post it sadly needs some time...
-{{< youtube ElRvz9Rghic >}}
+
diff --git a/content/posts/2015-10-04-dolphin-platform-a-sneak-peek.md b/content/posts/2015-10-04-dolphin-platform-a-sneak-peek.md
index c7127e7c..fa207f0f 100644
--- a/content/posts/2015-10-04-dolphin-platform-a-sneak-peek.md
+++ b/content/posts/2015-10-04-dolphin-platform-a-sneak-peek.md
@@ -34,11 +34,11 @@ Ok, I think this was enough description and I hope that you want to see some cod
Here are the links to additional DOlphin Platform sneak peeks:
-* I blogged about the [Dolphin Platform controller API]({{< ref "/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api" >}}).
-* I blogged about the [Dolphin Platform model API]({{< ref "/posts/2015-10-06-dolphin-platform-a-sneak-peek-of-the-model-api" >}}).
-* I blogged about the [Dolphin Platform view API]({{< ref "/posts/2015-10-07-dolphin-platform-a-sneak-peek-of-the-view-api" >}}).
-* I created [a first "getting started" tutorial]({{< ref "/posts/2015-10-18-dolphin-platform-how-to-create-an-application" >}}) for the Dolphin Platform.
-* I blogged about [Dolphin Platform Web Frontends with Polymer]({{< ref "/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer" >}}).
-* I blogged about [the first release of the Dolphin Platform]({{< ref "/posts/2015-11-09-dolphin-platform-has-been-released" >}}).
-* I blogged about how to use [Dolphin Platform with kumuluzEE]({{< ref "/posts/2015-11-11-dolphin-platform-kumuluzee-javaee-microservices-with-dynamic-and-rich-frontends" >}}).
-* I was interviewed for the [Nighthacking YouTube channel]({{< ref "/posts/2015-11-12-dolphin-platform-in-15-minutes-nighthacking" >}}).
+* I blogged about the [Dolphin Platform controller API](/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api).
+* I blogged about the [Dolphin Platform model API](/posts/2015-10-06-dolphin-platform-a-sneak-peek-of-the-model-api).
+* I blogged about the [Dolphin Platform view API](/posts/2015-10-07-dolphin-platform-a-sneak-peek-of-the-view-api).
+* I created [a first "getting started" tutorial](/posts/2015-10-18-dolphin-platform-how-to-create-an-application) for the Dolphin Platform.
+* I blogged about [Dolphin Platform Web Frontends with Polymer](/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer).
+* I blogged about [the first release of the Dolphin Platform](/posts/2015-11-09-dolphin-platform-has-been-released).
+* I blogged about how to use [Dolphin Platform with kumuluzEE](/posts/2015-11-11-dolphin-platform-kumuluzee-javaee-microservices-with-dynamic-and-rich-frontends).
+* I was interviewed for the [Nighthacking YouTube channel](/posts/2015-11-12-dolphin-platform-in-15-minutes-nighthacking).
diff --git a/content/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api.md b/content/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api.md
index eef80824..97605b78 100644
--- a/content/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api.md
+++ b/content/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api.md
@@ -1,97 +1,89 @@
----
-outdated: true
-showInBlog: false
-title: 'Dolphin Platform: A Sneak Peek of the controller API'
-date: "2015-10-05"
-author: hendrik
-categories: [Dolphin Platform, JavaFX]
-excerpt: 'In this sneak peek of the Dolphin Platform, a new open source project by Canoo, I want to show how server side controller can be defined.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Today I want to add the next sneak peek of the Dolphin Platform, a new __open source__ project on that [Michael Heinrich](https://twitter.com/net0pyr) and I are currently working at Canoo. Yesterday I blogged about the [general concept of the platform]({{ site.baseurl }}{% post_url 2015-10-04-dolphin-platform-a-sneak-peek %}
-). Today I want to show server side controllers can be defined by using the Dolphin Platform.
-
-## The Controller API
-
-As already said the controller are defined on the server. If you already used JSF you might know this concept. But don't be afraid, I won't compare Dolphin Platform with JSF ;)
-
-Each controller must be annotated with the `@DolphinController` annotation and therefore the most simple controller might look like this:
-
-{{< highlight java >}}
-@DolphinController
-public class MyController {
-}
-{{< / highlight >}}
-
-Even if this class don't make that much sense we created a complete runnable Dolphin Platform server application here. Once this is deployed the underlying platform (currently JavaEE or Spring) will automatically find your container and manage its lifecycle. This is done by the architecture of Dolphin Platform that provides a public API and specific bootstrap implementations for __JavaEE and Spring__. As a developer you will always code against the public API and only need to add the needed bootrap module as a dependency to your server application.
-
-
-
-This means that the shown controller will __work in any Spring or JavaEE 7 environment__.
-
-Since the controllers managed by the container you automatically get all the benefits that comes with it. This means that you can use `@Inject` or `@PostContruct` annotations, for example:
-
-{{< highlight java >}}
-@DolphinController
-public class MyController {
-
- @Inject
- private PersistenceService myService;
-
- @PostConstruct
- public void init() {
- myService.loadData();
- }
-
-}
-{{< / highlight >}}
-
-Next to this Dolphin Platform provides addition features for the controller API. Any method that is annotated by `@DolphinAction` can be called from the client view to trigger some actions on user interaction, for example.
-
-{{< highlight java >}}
-@DolphinController
-public class MyController {
-
- @Inject
- private PersistenceService myService;
-
- @DolphinAction
- public void load() {
- myService.loadData();
- }
-
- @DolphinAction
- public void save() {
- myService.saveData();
- }
-
-}
-{{< / highlight >}}
-
-By doing so it's very easy to handle the business logic that will be triggered by a user action. Since the methods are defined on the server you benefit of security and transaction support, for example.
-
-Next to the actions a main concept of the Dolphin Platform is the presentation model (or view model). Each view-controller-pair can define it's own model that can simply be injected in the controller by using the `@DolphinModel` annotation. We will see later how such a model can be defined. When injecting a model to the controller its lifecycle is bound to the lifecycle of the controller and will be automatically managed by the underlying platform.
-
-{{< highlight java >}}
-@DolphinController
-public class MyController {
-
- @Inject
- private PersistenceService myService;
-
- @DolphinModel
- private MyModel model;
-
- @DolphinAction
- public void refresh() {
- model.setData(myService.loadData());
- }
-
-}
-{{< / highlight >}}
-
-By doing so the model instance will automatically be created when a new controller instance will be created. If the controller will be destroyed by the container the model will be destroyed, too. In addition the model will automatically be synchronized between the server controller and the view on the client side. How the model can be accessed and handled on the client will part of a future post.
-
-I think the biggest benefit in the shown concept is the perfect integration in a web container like it is provided by __Spring or JavaEE__. All your controller (and model) instances will be managed by the container and it's no problem to inject a __spring service__ in your controller, for example. By doing so you can use an API like [Spring data](http://projects.spring.io/spring-data/) and fill your view model directly with data from your persistence.
-
-In the next preview I will show how a view model can be defined by using Dolphin Platform and how you can simply observe any view model on the server and client.
+---
+outdated: true
+showInBlog: false
+title: 'Dolphin Platform: A Sneak Peek of the controller API'
+date: "2015-10-05"
+author: hendrik
+categories: [Dolphin Platform, JavaFX]
+excerpt: 'In this sneak peek of the Dolphin Platform, a new open source project by Canoo, I want to show how server side controller can be defined.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Today I want to add the next sneak peek of the Dolphin Platform, a new __open source__ project on that [Michael Heinrich](https://twitter.com/net0pyr) and I are currently working at Canoo. Yesterday I blogged about the [general concept of the platform]({{ site.baseurl }}{% post_url 2015-10-04-dolphin-platform-a-sneak-peek %}
+). Today I want to show server side controllers can be defined by using the Dolphin Platform.
+
+## The Controller API
+
+As already said the controller are defined on the server. If you already used JSF you might know this concept. But don't be afraid, I won't compare Dolphin Platform with JSF ;)
+
+Each controller must be annotated with the `@DolphinController` annotation and therefore the most simple controller might look like this:
+
+```java@DolphinController
+public class MyController {
+}
```
+
+Even if this class don't make that much sense we created a complete runnable Dolphin Platform server application here. Once this is deployed the underlying platform (currently JavaEE or Spring) will automatically find your container and manage its lifecycle. This is done by the architecture of Dolphin Platform that provides a public API and specific bootstrap implementations for __JavaEE and Spring__. As a developer you will always code against the public API and only need to add the needed bootrap module as a dependency to your server application.
+
+
+
+This means that the shown controller will __work in any Spring or JavaEE 7 environment__.
+
+Since the controllers managed by the container you automatically get all the benefits that comes with it. This means that you can use `@Inject` or `@PostContruct` annotations, for example:
+
+```java@DolphinController
+public class MyController {
+
+ @Inject
+ private PersistenceService myService;
+
+ @PostConstruct
+ public void init() {
+ myService.loadData();
+ }
+
+}
```
+
+Next to this Dolphin Platform provides addition features for the controller API. Any method that is annotated by `@DolphinAction` can be called from the client view to trigger some actions on user interaction, for example.
+
+```java@DolphinController
+public class MyController {
+
+ @Inject
+ private PersistenceService myService;
+
+ @DolphinAction
+ public void load() {
+ myService.loadData();
+ }
+
+ @DolphinAction
+ public void save() {
+ myService.saveData();
+ }
+
+}
```
+
+By doing so it's very easy to handle the business logic that will be triggered by a user action. Since the methods are defined on the server you benefit of security and transaction support, for example.
+
+Next to the actions a main concept of the Dolphin Platform is the presentation model (or view model). Each view-controller-pair can define it's own model that can simply be injected in the controller by using the `@DolphinModel` annotation. We will see later how such a model can be defined. When injecting a model to the controller its lifecycle is bound to the lifecycle of the controller and will be automatically managed by the underlying platform.
+
+```java@DolphinController
+public class MyController {
+
+ @Inject
+ private PersistenceService myService;
+
+ @DolphinModel
+ private MyModel model;
+
+ @DolphinAction
+ public void refresh() {
+ model.setData(myService.loadData());
+ }
+
+}
```
+
+By doing so the model instance will automatically be created when a new controller instance will be created. If the controller will be destroyed by the container the model will be destroyed, too. In addition the model will automatically be synchronized between the server controller and the view on the client side. How the model can be accessed and handled on the client will part of a future post.
+
+I think the biggest benefit in the shown concept is the perfect integration in a web container like it is provided by __Spring or JavaEE__. All your controller (and model) instances will be managed by the container and it's no problem to inject a __spring service__ in your controller, for example. By doing so you can use an API like [Spring data](http://projects.spring.io/spring-data/) and fill your view model directly with data from your persistence.
+
+In the next preview I will show how a view model can be defined by using Dolphin Platform and how you can simply observe any view model on the server and client.
diff --git a/content/posts/2015-10-06-dolphin-platform-a-sneak-peek-of-the-model-api.md b/content/posts/2015-10-06-dolphin-platform-a-sneak-peek-of-the-model-api.md
index 563edef6..298daf99 100644
--- a/content/posts/2015-10-06-dolphin-platform-a-sneak-peek-of-the-model-api.md
+++ b/content/posts/2015-10-06-dolphin-platform-a-sneak-peek-of-the-model-api.md
@@ -1,74 +1,68 @@
----
-outdated: true
-showInBlog: false
-title: 'Dolphin Platform: A Sneak Peek of the model API'
-date: "2015-10-06"
-author: hendrik
-categories: [Dolphin Platform, JavaFX, Web Frontends]
-excerpt: 'This is a short overview about the model API of the Dolphin Platform. This defines a model that will automatically synchronized between client and server.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Before I will talk the first time about the Dolphin Platform today at ["Java Forum Nord"](http://javaforumnord.de/programm_3) I will use the time to post the next preview. Today I will give a short overview about the model API of the Dolphin Platform. The last days I already gave a [general overview]({{ site.baseurl }}{% post_url 2015-10-04-dolphin-platform-a-sneak-peek %}
-) and described how the [controller API of Dolphin Platform]({{< ref "/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api" >}}) is working.
-
-## The Model API
-
-To describe the API that helps you to define presentation models in Dolphin Platform I will start with an example. Let's say we have the following view that can be part of a photo library app:
-
-
-
-In this view we have several elements that need a data model. If the data of this app is stored on a server the data model must be shared between the client and the server. When having a look at the screen we can see 3 different elements that need data from the data model to visualize itself or provide user interaction:
-
-* The title of the screen needs a String as its content. Here we can display the title of a photo album or an internationalized string
-* The slider that defines a value. Let's imagine that the interaction with the slider changes the size of the pictures in the main area. Maybe the last value of the slider should be stored on the server to automatically save user preferences
-* All pictures in the main area. As you can see each card in this area contains an image and maybe a badge in the top right corner. A badge element in the top right corner visualizes if the photo is flagged.
-
-Based on this definition we would create a presentation model that might look like this one:
-
-
-
-When defining such a model in JavaFX you can use the cool property API and the observable collections that are part of JavaFX. Modern javaScript frameworks like AngularJS or Polymer provide a similar behavior and therefore we decided to offer the same benefits when defining model with the Dolphin Platform. Since [Michael Heinrichs](https://twitter.com/net0pyr) was the project lead of the property and bindings APIs of JavaFX at Oracle we had a lot of knowledge in this area that helped us creating the model API: In Dolphin Platform you work with properties and observable collections, too. Therefore it really easy to define a hierarchical model for your view. A model for the shown view might look like this:
-
-{{< highlight java >}}
-@DolphinBean
-public class PhotoOverviewModel {
-
- private Property title;
-
- private Property sliderValue;
-
- private ObservableList photos;
-
- //getter & setter
-
-}
-
-@DolphinBean
-public class PhotoModel {
-
- private Property imageUrl;
-
- private Property flagged;
-
- //getter & setter
-
-}
-{{< / highlight >}}
-
-All properties and collections in Dolphin Platform are observable and therefore it's quite easy to observe them on the client and the server:
-
-{{< highlight java >}}
-myModel.getTitleProperty().onChange(e -> System.out.println("New title: " + e.getNewValue()));
-{{< / highlight >}}
-
-For all client APIs we support first class support for the Dolphin Platform properties. When working with JavaFX for example it's quite easy and intuitive to bind a synchronized Dolphin Platform property to a JavaFX property:
-
-{{< highlight java >}}
-FXBinder.bind(booleanJavaFXProperty).bidirectionalTo(booleanDolphinProperty);
-{{< / highlight >}}
-
-On JavaScript clients the handling is even more elegant as you can bind the Dolphin Platform model directly in HTML.
-
-The main benefit of this concept is that you can use the same model classes on the server and the client. Because the model will automatically be synchronized between the view and the server controller it feels like you work with the same instance. By doing so you can simply bind a string property to a textfield in the view and observe it's value on the server. The change events will automatically be fired on the server when you start typing in the textfield.
-
-There are a lot of more cool features in the model API but since this should only be a overview I need to stop here :) But there are only a few weeks left till JavaOne where we will release a whole preview with the source, documentation and several samples. As the next step I will post a preview of the view API the next days.
+---
+outdated: true
+showInBlog: false
+title: 'Dolphin Platform: A Sneak Peek of the model API'
+date: "2015-10-06"
+author: hendrik
+categories: [Dolphin Platform, JavaFX, Web Frontends]
+excerpt: 'This is a short overview about the model API of the Dolphin Platform. This defines a model that will automatically synchronized between client and server.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Before I will talk the first time about the Dolphin Platform today at ["Java Forum Nord"](http://javaforumnord.de/programm_3) I will use the time to post the next preview. Today I will give a short overview about the model API of the Dolphin Platform. The last days I already gave a [general overview]({{ site.baseurl }}{% post_url 2015-10-04-dolphin-platform-a-sneak-peek %}
+) and described how the [controller API of Dolphin Platform](/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api) is working.
+
+## The Model API
+
+To describe the API that helps you to define presentation models in Dolphin Platform I will start with an example. Let's say we have the following view that can be part of a photo library app:
+
+
+
+In this view we have several elements that need a data model. If the data of this app is stored on a server the data model must be shared between the client and the server. When having a look at the screen we can see 3 different elements that need data from the data model to visualize itself or provide user interaction:
+
+* The title of the screen needs a String as its content. Here we can display the title of a photo album or an internationalized string
+* The slider that defines a value. Let's imagine that the interaction with the slider changes the size of the pictures in the main area. Maybe the last value of the slider should be stored on the server to automatically save user preferences
+* All pictures in the main area. As you can see each card in this area contains an image and maybe a badge in the top right corner. A badge element in the top right corner visualizes if the photo is flagged.
+
+Based on this definition we would create a presentation model that might look like this one:
+
+
+
+When defining such a model in JavaFX you can use the cool property API and the observable collections that are part of JavaFX. Modern javaScript frameworks like AngularJS or Polymer provide a similar behavior and therefore we decided to offer the same benefits when defining model with the Dolphin Platform. Since [Michael Heinrichs](https://twitter.com/net0pyr) was the project lead of the property and bindings APIs of JavaFX at Oracle we had a lot of knowledge in this area that helped us creating the model API: In Dolphin Platform you work with properties and observable collections, too. Therefore it really easy to define a hierarchical model for your view. A model for the shown view might look like this:
+
+```java@DolphinBean
+public class PhotoOverviewModel {
+
+ private Property title;
+
+ private Property sliderValue;
+
+ private ObservableList photos;
+
+ //getter & setter
+
+}
+
+@DolphinBean
+public class PhotoModel {
+
+ private Property imageUrl;
+
+ private Property flagged;
+
+ //getter & setter
+
+}
```
+
+All properties and collections in Dolphin Platform are observable and therefore it's quite easy to observe them on the client and the server:
+
+```javamyModel.getTitleProperty().onChange(e -> System.out.println("New title: " + e.getNewValue()));
```
+
+For all client APIs we support first class support for the Dolphin Platform properties. When working with JavaFX for example it's quite easy and intuitive to bind a synchronized Dolphin Platform property to a JavaFX property:
+
+```javaFXBinder.bind(booleanJavaFXProperty).bidirectionalTo(booleanDolphinProperty);
```
+
+On JavaScript clients the handling is even more elegant as you can bind the Dolphin Platform model directly in HTML.
+
+The main benefit of this concept is that you can use the same model classes on the server and the client. Because the model will automatically be synchronized between the view and the server controller it feels like you work with the same instance. By doing so you can simply bind a string property to a textfield in the view and observe it's value on the server. The change events will automatically be fired on the server when you start typing in the textfield.
+
+There are a lot of more cool features in the model API but since this should only be a overview I need to stop here :) But there are only a few weeks left till JavaOne where we will release a whole preview with the source, documentation and several samples. As the next step I will post a preview of the view API the next days.
diff --git a/content/posts/2015-10-07-dolphin-platform-a-sneak-peek-of-the-view-api.md b/content/posts/2015-10-07-dolphin-platform-a-sneak-peek-of-the-view-api.md
index d284f51e..d74de99f 100644
--- a/content/posts/2015-10-07-dolphin-platform-a-sneak-peek-of-the-view-api.md
+++ b/content/posts/2015-10-07-dolphin-platform-a-sneak-peek-of-the-view-api.md
@@ -1,75 +1,71 @@
----
-outdated: true
-showInBlog: false
-title: 'Dolphin Platform: A Sneak Peek of the view API'
-date: "2015-10-07"
-author: hendrik
-categories: [Dolphin Platform, JavaFX]
-excerpt: 'This post shows the view API of the Dolphin Platform. The Dolphin Platform is a MVC / MVP based open source framework for enterprise applications.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-The last days I blogged about the [different APIs of the Dolphin Platform]({{< ref "/posts/2015-10-04-dolphin-platform-a-sneak-peek" >}}). The Dolphin Platform is a new Open Source Framework by Canoo that will be released the next weeks. But one part is still missing: the view. Therefore I will show how you can create JavaFX based clients by using the Dolphin Platform. As already mentioned the Dolphin Platform will provide support for several client platforms like __JavaFX__, __AngularJS__ or __Polymer__.
-
-
-
-In this post I will focus on the JavaFX support. Other client libraries and APIs will be described in future posts.
-
-## The View API
-
-Last but not least I will show how a view will be coded based on the Dolphin Platform. Here the client specific APIs differs in some points because we want to support the core concepts of the underlying UI toolkit. One of the most important points is that a developer can use the concepts he already knows and therefore we decided to not provide the exact same API for all client types. But when having a deeper look at the Dolphin Platform client libraries you will see that the core and low level APIs are the same on all platforms. In this first overview I will give a short sample how a view can be coded in JavaFX.
-
-When creating a JavaFX client you will normally use FXML to create your view. Next to the FXML file you will have a view controller to bind all the properties of the view and attach action handlers.
-
-
-
-When talking about the dolphin Platform this view controller is the perfect point to bind the view to the synchronized model and the server side controller. Therefore we call this class the "Binder". There are several ways how you can define such a binding but the most easy one is to use extend the AbstractBinder class that is part of the Dolphin Platform JavaFX library. This class already implements the complete lifecycle of the view and you can simply bind the synchronized presentation model to your view properties. Here is a small example for a view that contains only one textfield and a button:
-
-{{< highlight java >}}
-public class MyBinder extends AbstractBinder {
-
- @FXML
- private Button button;
-
- @FXML
- private Textfield textfield;
-
- public MyController() {
- super(ControllerConstants.NAME);
- }
-
- @Override
- public void onInit() {
- FXBinder.bind(textfield.textProperty()).bidirectionalTo(getModel().nameProperty());
- button.setOnAction(e -> invoke(ControllerConstants.SAVE));
- }
-
-}
-{{< / highlight >}}
-
-Once the view binder is instantiated the server controller and the model will automatically be created on the server. Since the model will be synchronized all the time between client and server you don't need to create it on the client. After this initialization is done the `onInit()` method of the binder will called. Here we bind the the `name property` that is part of the synchronized model to the text property of the textfield. In addition we define an action handler for the button. When the button is pressed a action in the server side controller should be called. Top do so the abstract binder provides the `invoke(String name)` method that triggers actions on the server controller. In this specific case the server controller might look like this:
-
-{{< highlight java >}}
-@DolphinController
-public class Controller {
-
- @Inject
- private PersistenceService persistence;
-
- @DolphinModel
- private MyModel model;
-
- @DolphinAction
- public void save() {
- persistence.insert(model.getName());
- }
-
-}
-{{< / highlight >}}
-
-As you can see we never send any data to the server. Since the model will be automatically synchronized we can directly store the name string in the model to the database. The Dolphin Platform guarantee that the model will be the same as it's on the client when pressing the button.
-
-
-
-Another nice benefit that you might notice is that even if we have communication between the server and the client we don't need to handle several threads. The Dolphin Platform handles all the concurrency and handles all actions in the right thread. By doing so the binding between JavaFX properties and Dolphin properties will automatically be handled on the JavaFX application thread.
-
-I hope this post gives a first overview how a client can be created. As already said the Dolphin Platform will provide support for several client platforms like __JavaFX__, __AngularJS__ or __Polymer__. I will blog about the specific client APIs in future posts.
+---
+outdated: true
+showInBlog: false
+title: 'Dolphin Platform: A Sneak Peek of the view API'
+date: "2015-10-07"
+author: hendrik
+categories: [Dolphin Platform, JavaFX]
+excerpt: 'This post shows the view API of the Dolphin Platform. The Dolphin Platform is a MVC / MVP based open source framework for enterprise applications.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+The last days I blogged about the [different APIs of the Dolphin Platform](/posts/2015-10-04-dolphin-platform-a-sneak-peek). The Dolphin Platform is a new Open Source Framework by Canoo that will be released the next weeks. But one part is still missing: the view. Therefore I will show how you can create JavaFX based clients by using the Dolphin Platform. As already mentioned the Dolphin Platform will provide support for several client platforms like __JavaFX__, __AngularJS__ or __Polymer__.
+
+
+
+In this post I will focus on the JavaFX support. Other client libraries and APIs will be described in future posts.
+
+## The View API
+
+Last but not least I will show how a view will be coded based on the Dolphin Platform. Here the client specific APIs differs in some points because we want to support the core concepts of the underlying UI toolkit. One of the most important points is that a developer can use the concepts he already knows and therefore we decided to not provide the exact same API for all client types. But when having a deeper look at the Dolphin Platform client libraries you will see that the core and low level APIs are the same on all platforms. In this first overview I will give a short sample how a view can be coded in JavaFX.
+
+When creating a JavaFX client you will normally use FXML to create your view. Next to the FXML file you will have a view controller to bind all the properties of the view and attach action handlers.
+
+
+
+When talking about the dolphin Platform this view controller is the perfect point to bind the view to the synchronized model and the server side controller. Therefore we call this class the "Binder". There are several ways how you can define such a binding but the most easy one is to use extend the AbstractBinder class that is part of the Dolphin Platform JavaFX library. This class already implements the complete lifecycle of the view and you can simply bind the synchronized presentation model to your view properties. Here is a small example for a view that contains only one textfield and a button:
+
+```javapublic class MyBinder extends AbstractBinder {
+
+ @FXML
+ private Button button;
+
+ @FXML
+ private Textfield textfield;
+
+ public MyController() {
+ super(ControllerConstants.NAME);
+ }
+
+ @Override
+ public void onInit() {
+ FXBinder.bind(textfield.textProperty()).bidirectionalTo(getModel().nameProperty());
+ button.setOnAction(e -> invoke(ControllerConstants.SAVE));
+ }
+
+}
```
+
+Once the view binder is instantiated the server controller and the model will automatically be created on the server. Since the model will be synchronized all the time between client and server you don't need to create it on the client. After this initialization is done the `onInit()` method of the binder will called. Here we bind the the `name property` that is part of the synchronized model to the text property of the textfield. In addition we define an action handler for the button. When the button is pressed a action in the server side controller should be called. Top do so the abstract binder provides the `invoke(String name)` method that triggers actions on the server controller. In this specific case the server controller might look like this:
+
+```java@DolphinController
+public class Controller {
+
+ @Inject
+ private PersistenceService persistence;
+
+ @DolphinModel
+ private MyModel model;
+
+ @DolphinAction
+ public void save() {
+ persistence.insert(model.getName());
+ }
+
+}
```
+
+As you can see we never send any data to the server. Since the model will be automatically synchronized we can directly store the name string in the model to the database. The Dolphin Platform guarantee that the model will be the same as it's on the client when pressing the button.
+
+
+
+Another nice benefit that you might notice is that even if we have communication between the server and the client we don't need to handle several threads. The Dolphin Platform handles all the concurrency and handles all actions in the right thread. By doing so the binding between JavaFX properties and Dolphin properties will automatically be handled on the JavaFX application thread.
+
+I hope this post gives a first overview how a client can be created. As already said the Dolphin Platform will provide support for several client platforms like __JavaFX__, __AngularJS__ or __Polymer__. I will blog about the specific client APIs in future posts.
diff --git a/content/posts/2015-10-18-dolphin-platform-how-to-create-an-application.md b/content/posts/2015-10-18-dolphin-platform-how-to-create-an-application.md
index 332f4eee..8841fb76 100644
--- a/content/posts/2015-10-18-dolphin-platform-how-to-create-an-application.md
+++ b/content/posts/2015-10-18-dolphin-platform-how-to-create-an-application.md
@@ -1,503 +1,471 @@
----
-outdated: true
-showInBlog: false
-title: 'Dolphin Platform: How to create an application'
-date: "2015-10-18"
-author: hendrik
-categories: [Dolphin Platform, JavaFX]
-excerpt: 'In this post I will show a first end to end example of the Dolphin Platform by creating an application that contains a Spring server and a JavaFX client.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this post I will show a first end to end example of the Dolphin Platform. In my last posts I already gave an overview about the concepts and APIs of the Dolphin Platform. If you have missed this post you can find them [here]({{< ref "/posts/2015-10-04-dolphin-platform-a-sneak-peek" >}}).
-
-## The calculator application
-
-The application that I will create in this post might not be the coolest one but I think that it gives a good overview of the Dolphin Platform concepts and APIs. The final application should calculate the sum of to values and look like it is shown in the following picture:
-
-
-
-A user can type in 2 values in the textfields on the left and the result textfield will automatically be updated. In addition I will add a "reset" button that resets the content of the textfields. In general the complete functionality can be described like it is sketched in this picture:
-
-
-
-As the complete controller logic will be defined on the server when using Dolphin Platform the addition of the values and the reset action will be defined in server side controller. This might be very useful for this small example but think about bigger applications with complex calculation or a persistence layer. In addition you don't need to code the logic several times if you want to support desktop, mobile and web clients.
-
-Before we start to create the application by using the Dolphin Platform I will create a client only application by using JavaFX. That's why I decided to use an example that normally don't need a server. We can create a client side only application by using only JavaFX. By doing so we can compare the 2 solutions later and the Dolphin Platform integration for JavaFX might become more clear. So this post might not show all benefits of the Dolphin Platform but will give a good overview of its basic APIs.
-
-## The JavaFX calculator application
-
-As a first step I will create the layout of the application by using the SceneBuilder that can be [downloaded at Gluon](http://gluonhq.com/open-source/scene-builder/). Here is a picture of my final layout in SceneBuilder:
-
-
-
-Once this is is saved as a view.fxml file we can use it in JavaFX. Here is the content of the fxml file:
-
-{{< highlight xml >}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{< / highlight >}}
-
-As a next step we need a controller class that add some interaction and bindings to our view. In JavaFX you can create a view by bundling a controller class and a fxml file. By doing so you can inject controls that are defined in the fxml description directly in your Java controller.
-
-
-
-Let's start with a controller that injects all controls that we need for our use case:
-
-{{< highlight java >}}
-public class CalculatorController {
-
- @FXML
- private TextField valueAField;
-
- @FXML
- private TextField valueBField;
-
- @FXML
- private TextField resultField;
-
- @FXML
- private Button resetButton;
-
-
- public void initialize() {
- }
-}
-{{< / highlight >}}
-
-In this class I already add a `initialize()` method that will automatically be called by JavaFX after all controls has been injected in the controller instance. Sadly this is done by some kind of magic and JavaFX don't provide an default interface for this behavior. You need to know that you can add this method to your controller class by reading the FXML documentation.
-
-For this small example we don't need to add any other methods to the controller. Everything we want to do can be defined in the init method. Here we need to add an action to the reset button and define an binding for the values to automatically update the result value. I don't want to describe the JavaFX API in deep and just show the final source code of the method:
-
-{{< highlight java >}}
-public void initialize() {
- resultField.textProperty().bind(Bindings.createStringBinding(() -> {
- try {
- int valueA = 0;
- int valueB = 0;
- String stringValue = valueAField.getText();
- if(stringValue != null && !stringValue.trim().isEmpty()) {
- valueA = Integer.parseInt(stringValue);
- }
- stringValue = valueBField.getText();
- if(stringValue != null && !stringValue.trim().isEmpty()) {
- valueB = Integer.parseInt(stringValue);
- }
- return (valueA + valueB) + "";
- } catch (Exception e) {
- return "Error";
- }
- }, valueAField.textProperty(), valueBField.textProperty()));
-
- resetButton.setOnAction(e -> {
- valueAField.setText(null);
- valueBField.setText(null);
- });
-}
-{{< / highlight >}}
-
-As a last step we need to create or view and show it on screen. Here is the main application class that does everything that we need:
-
-{{< highlight java >}}
-public class CalculatorApplication extends Application {
-
- @Override
- public void start(Stage primaryStage) throws Exception {
- FXMLLoader loader = new FXMLLoader(CalculatorApplication.class.getResource("view.fxml"));
- loader.setController(new CalculatorController());
-
- Scene scene = new Scene(loader.load());
- primaryStage.setScene(scene);
- primaryStage.show();
- }
-}
-{{< / highlight >}}
-
-Once this is done we can start our application and it's working as expected:
-
-
-
-## The Dolphin Platform based calculator application
-
-When creating an application based on the Dolphin Platform I start to define the model and code the basic controller functionality. Let's start with the model definition (A first description of the Dolphin Platform model API ca be found [here]({{< ref "/posts/2015-10-06-dolphin-platform-a-sneak-peek-of-the-model-api" >}})). In the given example the model is quite small and a matching Dolphin Platform model will look like this:
-
-{{< highlight java >}}
-@DolphinBean
-public class CalculatorModel {
-
- private Property firstValue;
-
- private Property secondValue;
-
- private Property result;
-
- public Property firstValueProperty() {
- return firstValue;
- }
-
- public Property secondValueProperty() {
- return secondValue;
- }
-
- public Property resultProperty() {
- return result;
- }
-}
-{{< / highlight >}}
-
-If you want to simply use getter and setter methods when working with the model you can add some convenience methods:
-
-{{< highlight java >}}
-@DolphinBean
-public class CalculatorModel {
-
- private Property firstValue;
-
- private Property secondValue;
-
- private Property result;
-
- public Property firstValueProperty() {
- return firstValue;
- }
-
- public Property secondValueProperty() {
- return secondValue;
- }
-
- public Property resultProperty() {
- return result;
- }
-
- public String getFirstValue() {
- return firstValueProperty().get();
- }
-
- public String getSecondValue() {
- return secondValueProperty().get();
- }
-
- public String getResult() {
- return resultProperty().get();
- }
-
- public void setFirstValue(String firstValue) {
- firstValueProperty().set(firstValue);
- }
-
- public void setSecondValue(String secondValue) {
- secondValueProperty().set(secondValue);
- }
-
- public void setResult(String result) {
- resultProperty().set(result);
- }
-}
-{{< / highlight >}}
-
-The model class should be defined in a module that is shared between the client and server sources.
-
-Once the model is done we can start working on the controller. As described in the [first overview]({{< ref "/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api" >}}) a controller will be managed by the web container on server side. Based on this all the well known Spring and JavaEE specifications can be used in Dolphin Platform controllers. In this example we will make use of the `@PostContruct` annotation that marks our `init()` method. This method will automatically be called once the controller has been created. In the `init()` method we can add some listeners to our model since the model instance is already created and injected in the controller instance when the `@PostContruct` is handled.
-
-{{< highlight java >}}
-@DolphinController(Constants.CONTROLLER_NAME)
-public class CalculatorController {
-
- @DolphinModel
- private CalculatorModel model;
-
- @PostConstruct
- public void init() {
- model.firstValueProperty().onChanged(e -> calc());
- model.secondValueProperty().onChanged(e -> calc());
- }
-
- private void calc() {
- //TODO: calc
- }
-}
-{{< / highlight >}}
-
-Once this is done we need to add some additional features to the controller class. Let's start with the calculation. Here we can reuse most of the code that we already used in the JavaFX only example since the Dolphin Platform `Property` definition is similar to the JavaFX one:
-
-{{< highlight java >}}
-private void calc() {
- try {
- int valueA = 0;
- int valueB = 0;
- String stringValue = model.getFirstValue();
- if(stringValue != null && !stringValue.trim().isEmpty()) {
- valueA = Integer.parseInt(stringValue);
- }
- stringValue = model.getSecondValue();
- if(stringValue != null && !stringValue.trim().isEmpty()) {
- valueB = Integer.parseInt(stringValue);
- }
- model.resultProperty().set((valueA + valueB) + "");
- } catch (Exception e) {
- model.resultProperty().set("Error");
- }
-}
-{{< / highlight >}}
-
-The last think that is missing is the "reset" functionality. Here we create a Dolphin Action that can be triggered by a client. To do so the `@DolphinAction` annotation can be used. Once we created the action our controller is done and will look like this:
-
-{{< highlight java >}}
-@DolphinController(Constants.CONTROLLER_NAME)
-public class CalculatorController {
-
- @DolphinModel
- private CalculatorModel model;
-
- @PostConstruct
- public void init() {
- model.firstValueProperty().onChanged(e -> calc());
- model.secondValueProperty().onChanged(e -> calc());
- }
-
- @DolphinAction
- public void reset() {
- model.setFirstValue(null);
- model.setSecondValue(null);
- model.setResult(null);
- }
-
- private void calc() {
- try {
- int valueA = 0;
- int valueB = 0;
- String stringValue = model.getFirstValue();
- if(stringValue != null && !stringValue.trim().isEmpty()) {
- valueA = Integer.parseInt(stringValue);
- }
- stringValue = model.getSecondValue();
- if(stringValue != null && !stringValue.trim().isEmpty()) {
- valueB = Integer.parseInt(stringValue);
- }
- model.resultProperty().set((valueA + valueB) + "");
- } catch (Exception e) {
- model.resultProperty().set("Error");
- }
- }
-}
-{{< / highlight >}}
-
-Now we are mostly done with the server side of our example. Since we want to use Spring Boot to run the server we need to add a main class to our application. Dolphin Platform adds Spring Boot support and therefore such a class is quite small:
-
-{{< highlight java >}}
-@DolphinPlatformApplication
-public class CalculatorServer extends SpringBootServletInitializer {
-
- public static void main(String[] args) throws Exception {
- SpringApplication.run(new Class[]{CalculatorServer.class}, args);
- }
-}
-{{< / highlight >}}
-
-Spring Boot will automatically find the Dolphin controller and create a new instance whenever a client creates a matching view.
-
-For the JavaFX client we will create an application class that extends the `javafx.application.Application` as any other JavaFX application. Here we directly create the connection to our Dolphin Platform based server application that is defined by the `ClientContext` class:
-
-{{< highlight java >}}
-public class CalculatorClient extends Application {
-
- private ClientContext clientContext;
-
- @Override
- public void init() throws Exception {
- ClientConfiguration config = new JavaFXConfiguration("http://localhost:8080/dolphin");
- clientContext = ClientContextFactory.connect(config).get();
- }
-
- @Override
- public void start(Stage primaryStage) throws Exception {
- //TODO
- }
-
- public static void main(String... args) {
- launch(args);
- }
-}
-{{< / highlight >}}
-
-For the view we will use the same MVC and FXML based approach as in the first JavaFx example. Here we can reuse the FXML file ("view.fxml") since the UI won't change. But by using Dolphin Platform the controller will be much smaller. Since the real controller class is already defined on the server we only need to define some bindings here. To do so we can extend the Dolphin Platform class `AbstractViewBinder` that defines all information that we need to create an interactive UI. Here we will inject all UI elements by using the `@FXML` annotation like before. The `AbstractViewBinder` class defines the abstract `init()` method that we need to implement in our class:
-
-{{< highlight java >}}
-public class CalculatorViewBinder extends AbstractViewBinder {
-
- @FXML
- private TextField valueAField;
-
- @FXML
- private TextField valueBField;
-
- @FXML
- private TextField resultField;
-
- @FXML
- private Button resetButton;
-
- public CalculatorViewBinder(ClientContext clientContext) {
- super(clientContext, Constants.CONTROLLER_NAME);
- }
-
- @Override
- protected void init() {
- //TODO
- }
-}
-{{< / highlight >}}
-
-I will define the content of the `init()` method later and finish the application class first. Here we can now load the FXML with the given controller and show it on screen:
-
-{{< highlight java >}}
-public class CalculatorClient extends Application {
-
- private ClientContext clientContext;
-
- @Override
- public void init() throws Exception {
- ClientConfiguration config = new JavaFXConfiguration("http://localhost:8080/dolphin");
- clientContext = ClientContextFactory.connect(config).get();
- }
-
- @Override
- public void start(Stage primaryStage) throws Exception {
-
- FXMLLoader loader = new FXMLLoader(CalculatorClient.class.getResource("view.fxml"));
- loader.setController(new CalculatorViewBinder(clientContext));
-
- Scene scene = new Scene(loader.load());
- primaryStage.setScene(scene);
- primaryStage.show();
- }
-
- public static void main(String... args) {
- launch(args);
- }
-}
-{{< / highlight >}}
-
-As you can see we only use well known JavaFX APIs here. Once this is done you can already start the server and client applications. But you won't see any data on the client since the binding is still missing. To create a binding in JavaFX the Dolphin Platform offers a helper class called `FXBinder`. By using the class you can define (bidirectional) bindings between Dolphin Platform properties and JavaFX properties:
-
-{{< highlight java >}}
-FXBinder.bind(valueAField.textProperty()).bidirectionalTo(getModel().firstValueProperty());
-FXBinder.bind(valueBField.textProperty()).bidirectionalTo(getModel().secondValueProperty());
-FXBinder.bind(resultField.textProperty()).bidirectionalTo(getModel().resultProperty());
-{{< / highlight >}}
-
-As a last step we need to define the rest function. To do so we can add an action handler to the button. In the handler we will trigger the Dolphin Action on server side. Here is the code of the final view binder class:
-
-{{< highlight java >}}
-public class CalculatorViewBinder extends AbstractViewBinder {
-
- @FXML
- private TextField valueAField;
-
- @FXML
- private TextField valueBField;
-
- @FXML
- private TextField resultField;
-
- @FXML
- private Button resetButton;
-
- public CalculatorViewBinder(ClientContext clientContext) {
- super(clientContext, Constants.CONTROLLER_NAME);
- }
-
- @Override
- protected void init() {
- FXBinder.bindBidirectional(valueAField.textProperty(), getModel().firstValueProperty());
- FXBinder.bindBidirectional(valueBField.textProperty(), getModel().secondValueProperty());
- FXBinder.bindBidirectional(resultField.textProperty(), getModel().resultProperty());
- resetButton.setOnAction(e -> invoke("reset"));
- }
-}
-{{< / highlight >}}
-
-Now we can use the client and the calculation and reset will be done on the server :). Well, this might not be necessary for the given small example but for more complex applications this handling is awesome. There are several benefits:
-
-* If you are using a web client the user can't see any business source code since it's completely on the server side
-* In bigger Dolphin Platform based application the client layer is so small that you can easily change it or add an additional client type. By doing so you can easily create an application that is running in the browser and as a desktop application
-* As we will see in a future post the interaction between several clients can easily be created by using Dolphin Platform because the model and the controller for all client instances life on the server side
-* There are several addition benefits like security, authorization, or persistence.
-
-I will blog in more detail about all these benefits in future posts
-
-I think you will see the benefit when thinking about an additional feature. Let's say the data of the application should be stored in a database whenever an calculation has been done. When doing this with JavaFX we need to connect to a database, handle transactions in the client and do a lot of more stuff. Server frameworks already contain all those features and since the Dolphin Platform example is based on Spring Boot we can simply use [Spring Data](http://Spring Data) here. In this case we only need to inject a Spring Data repository in our controller class and simply store the calculation in the DB. All challenges like transaction support will be handled by Spring in this case. When doing so your controller might look like this:
-
-{{< highlight java >}}
-@DolphinController(Constants.CONTROLLER_NAME)
-public class CalculatorController {
-
- @DolphinModel
- private CalculatorModel model;
-
- @Inject
- private SpringDataCalcRepository repository;
-
- @PostConstruct
- public void init() {
- model.firstValueProperty().onChanged(e -> calc());
- model.secondValueProperty().onChanged(e -> calc());
- }
-
- @DolphinAction
- public void reset() {
- model.setFirstValue(null);
- model.setSecondValue(null);
- model.setResult(null);
- }
-
- private void calc() {
- try {
- int valueA = 0;
- int valueB = 0;
- String stringValue = model.getFirstValue();
- if(stringValue != null && !stringValue.trim().isEmpty()) {
- valueA = Integer.parseInt(stringValue);
- }
- stringValue = model.getSecondValue();
- if(stringValue != null && !stringValue.trim().isEmpty()) {
- valueB = Integer.parseInt(stringValue);
- }
- model.resultProperty().set((valueA + valueB) + "");
- repository.save(new CalcEntity(valueA, valueB));
- } catch (Exception e) {
- model.resultProperty().set("Error");
- }
- }
-}
-{{< / highlight >}}
-
-This was the first complete "getting started" example of the Dolphin Platform and I hope that you like the basic concepts. We plan to upload the Dolphin Platform sources to GitHub in the next days and deploy a first preview release to Maven Central before JavaOne.
-
-In addition I plan to add a post about Polymer based clients and how you can create web clients by using the Dolphin Platform. Stay tuned ;)
+---
+outdated: true
+showInBlog: false
+title: 'Dolphin Platform: How to create an application'
+date: "2015-10-18"
+author: hendrik
+categories: [Dolphin Platform, JavaFX]
+excerpt: 'In this post I will show a first end to end example of the Dolphin Platform by creating an application that contains a Spring server and a JavaFX client.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this post I will show a first end to end example of the Dolphin Platform. In my last posts I already gave an overview about the concepts and APIs of the Dolphin Platform. If you have missed this post you can find them [here](/posts/2015-10-04-dolphin-platform-a-sneak-peek).
+
+## The calculator application
+
+The application that I will create in this post might not be the coolest one but I think that it gives a good overview of the Dolphin Platform concepts and APIs. The final application should calculate the sum of to values and look like it is shown in the following picture:
+
+
+
+A user can type in 2 values in the textfields on the left and the result textfield will automatically be updated. In addition I will add a "reset" button that resets the content of the textfields. In general the complete functionality can be described like it is sketched in this picture:
+
+
+
+As the complete controller logic will be defined on the server when using Dolphin Platform the addition of the values and the reset action will be defined in server side controller. This might be very useful for this small example but think about bigger applications with complex calculation or a persistence layer. In addition you don't need to code the logic several times if you want to support desktop, mobile and web clients.
+
+Before we start to create the application by using the Dolphin Platform I will create a client only application by using JavaFX. That's why I decided to use an example that normally don't need a server. We can create a client side only application by using only JavaFX. By doing so we can compare the 2 solutions later and the Dolphin Platform integration for JavaFX might become more clear. So this post might not show all benefits of the Dolphin Platform but will give a good overview of its basic APIs.
+
+## The JavaFX calculator application
+
+As a first step I will create the layout of the application by using the SceneBuilder that can be [downloaded at Gluon](http://gluonhq.com/open-source/scene-builder/). Here is a picture of my final layout in SceneBuilder:
+
+
+
+Once this is is saved as a view.fxml file we can use it in JavaFX. Here is the content of the fxml file:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
```
+
+As a next step we need a controller class that add some interaction and bindings to our view. In JavaFX you can create a view by bundling a controller class and a fxml file. By doing so you can inject controls that are defined in the fxml description directly in your Java controller.
+
+
+
+Let's start with a controller that injects all controls that we need for our use case:
+
+```javapublic class CalculatorController {
+
+ @FXML
+ private TextField valueAField;
+
+ @FXML
+ private TextField valueBField;
+
+ @FXML
+ private TextField resultField;
+
+ @FXML
+ private Button resetButton;
+
+
+ public void initialize() {
+ }
+}
```
+
+In this class I already add a `initialize()` method that will automatically be called by JavaFX after all controls has been injected in the controller instance. Sadly this is done by some kind of magic and JavaFX don't provide an default interface for this behavior. You need to know that you can add this method to your controller class by reading the FXML documentation.
+
+For this small example we don't need to add any other methods to the controller. Everything we want to do can be defined in the init method. Here we need to add an action to the reset button and define an binding for the values to automatically update the result value. I don't want to describe the JavaFX API in deep and just show the final source code of the method:
+
+```javapublic void initialize() {
+ resultField.textProperty().bind(Bindings.createStringBinding(() -> {
+ try {
+ int valueA = 0;
+ int valueB = 0;
+ String stringValue = valueAField.getText();
+ if(stringValue != null && !stringValue.trim().isEmpty()) {
+ valueA = Integer.parseInt(stringValue);
+ }
+ stringValue = valueBField.getText();
+ if(stringValue != null && !stringValue.trim().isEmpty()) {
+ valueB = Integer.parseInt(stringValue);
+ }
+ return (valueA + valueB) + "";
+ } catch (Exception e) {
+ return "Error";
+ }
+ }, valueAField.textProperty(), valueBField.textProperty()));
+
+ resetButton.setOnAction(e -> {
+ valueAField.setText(null);
+ valueBField.setText(null);
+ });
+}
```
+
+As a last step we need to create or view and show it on screen. Here is the main application class that does everything that we need:
+
+```javapublic class CalculatorApplication extends Application {
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ FXMLLoader loader = new FXMLLoader(CalculatorApplication.class.getResource("view.fxml"));
+ loader.setController(new CalculatorController());
+
+ Scene scene = new Scene(loader.load());
+ primaryStage.setScene(scene);
+ primaryStage.show();
+ }
+}
```
+
+Once this is done we can start our application and it's working as expected:
+
+
+
+## The Dolphin Platform based calculator application
+
+When creating an application based on the Dolphin Platform I start to define the model and code the basic controller functionality. Let's start with the model definition (A first description of the Dolphin Platform model API ca be found [here](/posts/2015-10-06-dolphin-platform-a-sneak-peek-of-the-model-api)). In the given example the model is quite small and a matching Dolphin Platform model will look like this:
+
+```java@DolphinBean
+public class CalculatorModel {
+
+ private Property firstValue;
+
+ private Property secondValue;
+
+ private Property result;
+
+ public Property firstValueProperty() {
+ return firstValue;
+ }
+
+ public Property secondValueProperty() {
+ return secondValue;
+ }
+
+ public Property resultProperty() {
+ return result;
+ }
+}
```
+
+If you want to simply use getter and setter methods when working with the model you can add some convenience methods:
+
+```java@DolphinBean
+public class CalculatorModel {
+
+ private Property firstValue;
+
+ private Property secondValue;
+
+ private Property result;
+
+ public Property firstValueProperty() {
+ return firstValue;
+ }
+
+ public Property secondValueProperty() {
+ return secondValue;
+ }
+
+ public Property resultProperty() {
+ return result;
+ }
+
+ public String getFirstValue() {
+ return firstValueProperty().get();
+ }
+
+ public String getSecondValue() {
+ return secondValueProperty().get();
+ }
+
+ public String getResult() {
+ return resultProperty().get();
+ }
+
+ public void setFirstValue(String firstValue) {
+ firstValueProperty().set(firstValue);
+ }
+
+ public void setSecondValue(String secondValue) {
+ secondValueProperty().set(secondValue);
+ }
+
+ public void setResult(String result) {
+ resultProperty().set(result);
+ }
+}
```
+
+The model class should be defined in a module that is shared between the client and server sources.
+
+Once the model is done we can start working on the controller. As described in the [first overview](/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api) a controller will be managed by the web container on server side. Based on this all the well known Spring and JavaEE specifications can be used in Dolphin Platform controllers. In this example we will make use of the `@PostContruct` annotation that marks our `init()` method. This method will automatically be called once the controller has been created. In the `init()` method we can add some listeners to our model since the model instance is already created and injected in the controller instance when the `@PostContruct` is handled.
+
+```java@DolphinController(Constants.CONTROLLER_NAME)
+public class CalculatorController {
+
+ @DolphinModel
+ private CalculatorModel model;
+
+ @PostConstruct
+ public void init() {
+ model.firstValueProperty().onChanged(e -> calc());
+ model.secondValueProperty().onChanged(e -> calc());
+ }
+
+ private void calc() {
+ //TODO: calc
+ }
+}
```
+
+Once this is done we need to add some additional features to the controller class. Let's start with the calculation. Here we can reuse most of the code that we already used in the JavaFX only example since the Dolphin Platform `Property` definition is similar to the JavaFX one:
+
+```javaprivate void calc() {
+ try {
+ int valueA = 0;
+ int valueB = 0;
+ String stringValue = model.getFirstValue();
+ if(stringValue != null && !stringValue.trim().isEmpty()) {
+ valueA = Integer.parseInt(stringValue);
+ }
+ stringValue = model.getSecondValue();
+ if(stringValue != null && !stringValue.trim().isEmpty()) {
+ valueB = Integer.parseInt(stringValue);
+ }
+ model.resultProperty().set((valueA + valueB) + "");
+ } catch (Exception e) {
+ model.resultProperty().set("Error");
+ }
+}
```
+
+The last think that is missing is the "reset" functionality. Here we create a Dolphin Action that can be triggered by a client. To do so the `@DolphinAction` annotation can be used. Once we created the action our controller is done and will look like this:
+
+```java@DolphinController(Constants.CONTROLLER_NAME)
+public class CalculatorController {
+
+ @DolphinModel
+ private CalculatorModel model;
+
+ @PostConstruct
+ public void init() {
+ model.firstValueProperty().onChanged(e -> calc());
+ model.secondValueProperty().onChanged(e -> calc());
+ }
+
+ @DolphinAction
+ public void reset() {
+ model.setFirstValue(null);
+ model.setSecondValue(null);
+ model.setResult(null);
+ }
+
+ private void calc() {
+ try {
+ int valueA = 0;
+ int valueB = 0;
+ String stringValue = model.getFirstValue();
+ if(stringValue != null && !stringValue.trim().isEmpty()) {
+ valueA = Integer.parseInt(stringValue);
+ }
+ stringValue = model.getSecondValue();
+ if(stringValue != null && !stringValue.trim().isEmpty()) {
+ valueB = Integer.parseInt(stringValue);
+ }
+ model.resultProperty().set((valueA + valueB) + "");
+ } catch (Exception e) {
+ model.resultProperty().set("Error");
+ }
+ }
+}
```
+
+Now we are mostly done with the server side of our example. Since we want to use Spring Boot to run the server we need to add a main class to our application. Dolphin Platform adds Spring Boot support and therefore such a class is quite small:
+
+```java@DolphinPlatformApplication
+public class CalculatorServer extends SpringBootServletInitializer {
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(new Class[]{CalculatorServer.class}, args);
+ }
+}
```
+
+Spring Boot will automatically find the Dolphin controller and create a new instance whenever a client creates a matching view.
+
+For the JavaFX client we will create an application class that extends the `javafx.application.Application` as any other JavaFX application. Here we directly create the connection to our Dolphin Platform based server application that is defined by the `ClientContext` class:
+
+```javapublic class CalculatorClient extends Application {
+
+ private ClientContext clientContext;
+
+ @Override
+ public void init() throws Exception {
+ ClientConfiguration config = new JavaFXConfiguration("http://localhost:8080/dolphin");
+ clientContext = ClientContextFactory.connect(config).get();
+ }
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ //TODO
+ }
+
+ public static void main(String... args) {
+ launch(args);
+ }
+}
```
+
+For the view we will use the same MVC and FXML based approach as in the first JavaFx example. Here we can reuse the FXML file ("view.fxml") since the UI won't change. But by using Dolphin Platform the controller will be much smaller. Since the real controller class is already defined on the server we only need to define some bindings here. To do so we can extend the Dolphin Platform class `AbstractViewBinder` that defines all information that we need to create an interactive UI. Here we will inject all UI elements by using the `@FXML` annotation like before. The `AbstractViewBinder` class defines the abstract `init()` method that we need to implement in our class:
+
+```javapublic class CalculatorViewBinder extends AbstractViewBinder {
+
+ @FXML
+ private TextField valueAField;
+
+ @FXML
+ private TextField valueBField;
+
+ @FXML
+ private TextField resultField;
+
+ @FXML
+ private Button resetButton;
+
+ public CalculatorViewBinder(ClientContext clientContext) {
+ super(clientContext, Constants.CONTROLLER_NAME);
+ }
+
+ @Override
+ protected void init() {
+ //TODO
+ }
+}
```
+
+I will define the content of the `init()` method later and finish the application class first. Here we can now load the FXML with the given controller and show it on screen:
+
+```javapublic class CalculatorClient extends Application {
+
+ private ClientContext clientContext;
+
+ @Override
+ public void init() throws Exception {
+ ClientConfiguration config = new JavaFXConfiguration("http://localhost:8080/dolphin");
+ clientContext = ClientContextFactory.connect(config).get();
+ }
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+
+ FXMLLoader loader = new FXMLLoader(CalculatorClient.class.getResource("view.fxml"));
+ loader.setController(new CalculatorViewBinder(clientContext));
+
+ Scene scene = new Scene(loader.load());
+ primaryStage.setScene(scene);
+ primaryStage.show();
+ }
+
+ public static void main(String... args) {
+ launch(args);
+ }
+}
```
+
+As you can see we only use well known JavaFX APIs here. Once this is done you can already start the server and client applications. But you won't see any data on the client since the binding is still missing. To create a binding in JavaFX the Dolphin Platform offers a helper class called `FXBinder`. By using the class you can define (bidirectional) bindings between Dolphin Platform properties and JavaFX properties:
+
+```javaFXBinder.bind(valueAField.textProperty()).bidirectionalTo(getModel().firstValueProperty());
+FXBinder.bind(valueBField.textProperty()).bidirectionalTo(getModel().secondValueProperty());
+FXBinder.bind(resultField.textProperty()).bidirectionalTo(getModel().resultProperty());
```
+
+As a last step we need to define the rest function. To do so we can add an action handler to the button. In the handler we will trigger the Dolphin Action on server side. Here is the code of the final view binder class:
+
+```javapublic class CalculatorViewBinder extends AbstractViewBinder {
+
+ @FXML
+ private TextField valueAField;
+
+ @FXML
+ private TextField valueBField;
+
+ @FXML
+ private TextField resultField;
+
+ @FXML
+ private Button resetButton;
+
+ public CalculatorViewBinder(ClientContext clientContext) {
+ super(clientContext, Constants.CONTROLLER_NAME);
+ }
+
+ @Override
+ protected void init() {
+ FXBinder.bindBidirectional(valueAField.textProperty(), getModel().firstValueProperty());
+ FXBinder.bindBidirectional(valueBField.textProperty(), getModel().secondValueProperty());
+ FXBinder.bindBidirectional(resultField.textProperty(), getModel().resultProperty());
+ resetButton.setOnAction(e -> invoke("reset"));
+ }
+}
```
+
+Now we can use the client and the calculation and reset will be done on the server :). Well, this might not be necessary for the given small example but for more complex applications this handling is awesome. There are several benefits:
+
+* If you are using a web client the user can't see any business source code since it's completely on the server side
+* In bigger Dolphin Platform based application the client layer is so small that you can easily change it or add an additional client type. By doing so you can easily create an application that is running in the browser and as a desktop application
+* As we will see in a future post the interaction between several clients can easily be created by using Dolphin Platform because the model and the controller for all client instances life on the server side
+* There are several addition benefits like security, authorization, or persistence.
+
+I will blog in more detail about all these benefits in future posts
+
+I think you will see the benefit when thinking about an additional feature. Let's say the data of the application should be stored in a database whenever an calculation has been done. When doing this with JavaFX we need to connect to a database, handle transactions in the client and do a lot of more stuff. Server frameworks already contain all those features and since the Dolphin Platform example is based on Spring Boot we can simply use [Spring Data](http://Spring Data) here. In this case we only need to inject a Spring Data repository in our controller class and simply store the calculation in the DB. All challenges like transaction support will be handled by Spring in this case. When doing so your controller might look like this:
+
+```java@DolphinController(Constants.CONTROLLER_NAME)
+public class CalculatorController {
+
+ @DolphinModel
+ private CalculatorModel model;
+
+ @Inject
+ private SpringDataCalcRepository repository;
+
+ @PostConstruct
+ public void init() {
+ model.firstValueProperty().onChanged(e -> calc());
+ model.secondValueProperty().onChanged(e -> calc());
+ }
+
+ @DolphinAction
+ public void reset() {
+ model.setFirstValue(null);
+ model.setSecondValue(null);
+ model.setResult(null);
+ }
+
+ private void calc() {
+ try {
+ int valueA = 0;
+ int valueB = 0;
+ String stringValue = model.getFirstValue();
+ if(stringValue != null && !stringValue.trim().isEmpty()) {
+ valueA = Integer.parseInt(stringValue);
+ }
+ stringValue = model.getSecondValue();
+ if(stringValue != null && !stringValue.trim().isEmpty()) {
+ valueB = Integer.parseInt(stringValue);
+ }
+ model.resultProperty().set((valueA + valueB) + "");
+ repository.save(new CalcEntity(valueA, valueB));
+ } catch (Exception e) {
+ model.resultProperty().set("Error");
+ }
+ }
+}
```
+
+This was the first complete "getting started" example of the Dolphin Platform and I hope that you like the basic concepts. We plan to upload the Dolphin Platform sources to GitHub in the next days and deploy a first preview release to Maven Central before JavaOne.
+
+In addition I plan to add a post about Polymer based clients and how you can create web clients by using the Dolphin Platform. Stay tuned ;)
diff --git a/content/posts/2015-10-19-javaone-preview.md b/content/posts/2015-10-19-javaone-preview.md
index 7630a613..f08b0865 100644
--- a/content/posts/2015-10-19-javaone-preview.md
+++ b/content/posts/2015-10-19-javaone-preview.md
@@ -12,7 +12,7 @@ This year I will give 2 talks at JavaOne. For a short preview of the talks we re
The first talk will be "JavaFX Enterprise 2.0" that is a successor of my last year "JavaFX Enterprise" talk. I will do the talk together with [Alexander Casall](https://twitter.com/sialcasa). Here is the video:
-{{< youtube ouq2mH3Pjio-s >}}
+
The second talk will be about the JavaOne Voting Machine. For JavaOne we (Canoo) created a JavaFX based embedded device to vote all the JavaOne sessions that you will attend directly after the talk.
@@ -20,13 +20,13 @@ The second talk will be about the JavaOne Voting Machine. For JavaOne we (Canoo)
If you will attend JavaOne you will find Voting Machines in every room. If you can't attend the conference I will write a post about the technology and the UI later. I will do the talk together with [Gerrit Grunwald](https://twitter.com/hanSolo_) and [Michael Heinrichs](https://twitter.com/net0pyr). Here is the video:
-{{< youtube 6aLWyhp5F-s >}}
+
-Between the talks I would love to talk with you about the [Dolphin Platform]({{< ref "/posts/2015-10-04-dolphin-platform-a-sneak-peek" >}}) :)
+Between the talks I would love to talk with you about the [Dolphin Platform](/posts/2015-10-04-dolphin-platform-a-sneak-peek) :)

In addition I will use this post to promote another talk about Functional Reactive Programing with UI toolkits by Michael Heinrichs. We created a short video for this talk, too.
-{{< youtube LduW9zq16gA >}}
+
diff --git a/content/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer.md b/content/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer.md
index 867625c5..a3fd30fa 100644
--- a/content/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer.md
+++ b/content/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer.md
@@ -8,9 +8,9 @@ categories: [Dolphin Platform, Polymer, Web Frontends, WebComponents]
excerpt: 'For the Dolphin Platform release we plan to offer several demos and tutorials as a starting point. Today I want to give you an overview of this work'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-For the [Dolphin Platform]({{< ref "/posts/2015-10-04-dolphin-platform-a-sneak-peek" >}}) release we plan to offer several demos and tutorials as a starting point. Currently I'm working on a simple chat app that contains a JavaFX and a web frontend. The web frontend is done by using [Google Polymer]({{< ref "/posts/2015-09-11-creating-an-interactive-application-with-polymer-part-1" >}}) and web components. In this post I will give a preview how you can create web applications with the Dolphin Platform by using Polymer.
+For the [Dolphin Platform](/posts/2015-10-04-dolphin-platform-a-sneak-peek) release we plan to offer several demos and tutorials as a starting point. Currently I'm working on a simple chat app that contains a JavaFX and a web frontend. The web frontend is done by using [Google Polymer](/posts/2015-09-11-creating-an-interactive-application-with-polymer-part-1) and web components. In this post I will give a preview how you can create web applications with the Dolphin Platform by using Polymer.
-All the main concepts are already described in the [post about JavaFX clients]({{< ref "/posts/2015-10-18-dolphin-platform-how-to-create-an-application" >}}) and in this post I will show you that you can reuse all the concepts for a web application.
+All the main concepts are already described in the [post about JavaFX clients](/posts/2015-10-18-dolphin-platform-how-to-create-an-application) and in this post I will show you that you can reuse all the concepts for a web application.
The following picture shows how the final application will look like:
@@ -18,16 +18,14 @@ The following picture shows how the final application will look like:
To create a client that can communicate with the Dolphin Platform server a client context is needed. In an web application this can simply be done by defining a global JavaScript value:
-{{< highlight html >}}
-
-{{< / highlight >}}
+```
As we use web components when creating an application by using Polymer all view elements of our application are defined as components. In the chat example one chat view is defined as a Polymer based web component. For such a component the minimum code looks like this:
-{{< highlight html >}}
-
+```html
@@ -44,20 +42,18 @@ As we use web components when creating an application by using Polymer all view
is: "chat-thread",
});
-{{< / highlight >}}
+```
Once this is done you can simply use the component in your web application as a custom tag:
-{{< highlight html >}}
-
+```html
-{{< / highlight >}}
+```
To create a web component that acts as a Dolphin Platform you only need to add one more line of code:
-{{< highlight html >}}
-//...
+```html//...
-{{< / highlight >}}
+```
-Polymer supports extending custom element prototypes with shared code modules called [behaviors](https://www.polymer-project.org/1.0/docs/devguide/behaviors.html). The Dolphin Platform client API provides such a base behavior and therefore you can connect a web component with a [Dolphin Platform controller]({{< ref "/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api" >}}) by only adding one line of code. The `ThreadViewController` is the server side controller for this view. The code of this Java class looks like this:
+Polymer supports extending custom element prototypes with shared code modules called [behaviors](https://www.polymer-project.org/1.0/docs/devguide/behaviors.html). The Dolphin Platform client API provides such a base behavior and therefore you can connect a web component with a [Dolphin Platform controller](/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api) by only adding one line of code. The `ThreadViewController` is the server side controller for this view. The code of this Java class looks like this:
-{{< highlight java >}}
-@DolphinController("ThreadViewController")
+```java@DolphinController("ThreadViewController")
public class ThreadViewController {
@DolphinModel
@@ -96,12 +91,11 @@ public class ThreadViewController {
}
}
-{{< / highlight >}}
+```
-I don't want to discuss the [Dolphin Platform controller API]({{< ref "/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api" >}}) here and therefore all the methods of the controller are empty at the moment. Here it's important to know that the controller instance and the view share one model that is defined by the `ChatThreadBean` class:
+I don't want to discuss the [Dolphin Platform controller API](/posts/2015-10-05-dolphin-platform-a-sneak-peek-of-the-controller-api) here and therefore all the methods of the controller are empty at the moment. Here it's important to know that the controller instance and the view share one model that is defined by the `ChatThreadBean` class:
-{{< highlight java >}}
-@DolphinBean
+```java@DolphinBean
public class ChatThreadBean {
private Property chatId;
@@ -122,30 +116,28 @@ public class ChatThreadBean {
return typedText;
}
}
-{{< / highlight >}}
+```
As you can see in the code the model contains a chat id, the typed text and a list of all chat messages that should be shown in the chat thread. Let's have a look how we can use this model on the client.
By adding the Polymer behavior the Dolphin Platform model will automatically be injected in the component context. It is stored in the JavaScript `model` value. This means that the following JavaScript call will show a dialog that contains the current typed text:
-{{< highlight js >}}
-alert(model.typedText);
-{{< / highlight >}}
+```jsalert(model.typedText);
+```
In addition Polymer defines a [binding API](https://www.polymer-project.org/1.0/docs/devguide/data-binding.html) this is automatically used by the model. Thanks to this you can simply bind your model or parts of your model to HTML attributes in the web component template by using the mustache syntax. here you see how the typed text is bound to the input field in the chat view:
-{{< highlight html >}}
-
-{{< / highlight >}}
+```html
+```
Easy, isn't it?
Thanks to the modularity of web components you can even go deeper and use your model in sub components. In the chat example each message in the chat is defined by a web component. To do so we created the custom component `chat-message` that defines how one chat message should be visualized. Now we can define the complete chat by only 3 lines of HTML code:
-{{< highlight html >}}
+```html
- {{< / highlight >}}
+```
The `don-repeat` elect is a special Polymer elect that add it's content for each item in a given list. As we said earlier all the chat messages in our model are defined as a list. This list can easily be accessed by calling `model.messages`.
diff --git a/content/posts/2015-11-09-dolphin-platform-has-been-released.md b/content/posts/2015-11-09-dolphin-platform-has-been-released.md
index 61dd3d52..de83d943 100644
--- a/content/posts/2015-11-09-dolphin-platform-has-been-released.md
+++ b/content/posts/2015-11-09-dolphin-platform-has-been-released.md
@@ -1,57 +1,53 @@
----
-outdated: true
-showInBlog: false
-title: 'Dolphin Platform has been released'
-date: "2015-11-09"
-author: hendrik
-categories: [Dolphin Platform, JavaFX, Polymer, Web Frontends]
-excerpt: "Since JavaOne is over for more than a week we found some time to finish all the steps and I'm proud to announce the first Dolphin Platform release"
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-We planed to release the [Dolphin Platform]({{< ref "/posts/2015-10-04-dolphin-platform-a-sneak-peek" >}}) before JavaOne but the preparation of the
-[JavaOne Voting Machines]({{< ref "/posts/2015-10-23-a-short-preview-of-the-javaone-voting-machine" >}}) took more time then expected and we can't finish all the todos that we had to fully open source the Dolphin Platform. Since JavaOne is over for more than a week we found some time to finish all the steps and I'm proud to announce the first Dolphin Platform release :)
-
-
-
-As a first step we uploaded the [Dolphin Platform website](http://www.dolphin-platform.io) and added some descriptions and information about the framework. In addition we created [a first tutorial](http://www.dolphin-platform.io/documentation/tutorial.html) and a [getting started" guide](http://www.dolphin-platform.io/documentation/getting-started.html). All the Java sources (client and server) are uploaded to [GitHub](https://github.com/canoo/dolphin-platform), a first release has been created and was uploaded to [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cdolphin-platform) & [JCenter](https://bintray.com/canoo/dolphin-platform/dolphin-platform/0.6.1/view).
-
-If you want to try Dolphin Platform you can create your first application by simply adding the following dependencies:
-
-For a Spring Boot based server you only need to add the following dependency:
-{{< highlight xml >}}
-
- com.canoo.dolphin-platform
- dolphin-platform-server-spring
- 0.6.1
-
-{{< / highlight >}}
-
-For a JavaFX based client you need to add the following dependency:
-{{< highlight xml >}}
-
- com.canoo.dolphin-platform
- dolphin-platform-client-javafx
- 0.6.1
-
-{{< / highlight >}}
-
-If you are new to Dolphin Platform you can find some post about the API [in my blog]({{< ref "/posts/2015-10-04-dolphin-platform-a-sneak-peek" >}}). In addition we spend some time to create the [JavaDoc of the public API](http://www.dolphin-platform.io/javadoc/index.html). If you have any questions please leave a comment or [ask us on twitter](https://twitter.com/DolphinPlatform). For news about Dolphin Platform you should follow the official twitter account [@DolphinPlatform](https://twitter.com/DolphinPlatform).
-
-## Java Script client libraries
-
-As I [mentioned before]({{< ref "/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer" >}}) Dolphin Platform supports several client technologies. Next to the JavaFX library we hosted the sources for the basic [JavaScript client library](https://github.com/canoo/dolphin-platform-js) and the [Polymer client library](https://github.com/canoo/dolphin-platform-polymer) on github. We will add releases of the libraries this week. Once this is done I will blog how you can simply add Dolphin Platform to your web project by using [bower](http://bower.io).
-
-## Links
-
-Here is an overview of all important links:
-
-* [Dolphin Platform website](http://www.dolphin-platform.io)
-* [Getting started](http://www.dolphin-platform.io/documentation/getting-started.html)
-* [Tutorial](http://www.dolphin-platform.io/documentation/tutorial.html)
-* [JavaDoc](http://www.dolphin-platform.io/javadoc/index.html)
-* [StackOverflow](http://stackoverflow.com/questions/tagged/dolphin-platform)
-* [Blog Posts]({{< ref "/posts/2015-10-04-dolphin-platform-a-sneak-peek" >}})
-* [Java Github Repo](https://github.com/canoo/dolphin-platform)
-* [JavaScript Github Repo](https://github.com/canoo/dolphin-platform-js)
-* [Polymer Github Repo](https://github.com/canoo/dolphin-platform-polymer)
-* [Dolphin Platform @ Twitter](https://twitter.com/DolphinPlatform)
+---
+outdated: true
+showInBlog: false
+title: 'Dolphin Platform has been released'
+date: "2015-11-09"
+author: hendrik
+categories: [Dolphin Platform, JavaFX, Polymer, Web Frontends]
+excerpt: "Since JavaOne is over for more than a week we found some time to finish all the steps and I'm proud to announce the first Dolphin Platform release"
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+We planed to release the [Dolphin Platform](/posts/2015-10-04-dolphin-platform-a-sneak-peek) before JavaOne but the preparation of the
+[JavaOne Voting Machines](/posts/2015-10-23-a-short-preview-of-the-javaone-voting-machine) took more time then expected and we can't finish all the todos that we had to fully open source the Dolphin Platform. Since JavaOne is over for more than a week we found some time to finish all the steps and I'm proud to announce the first Dolphin Platform release :)
+
+
+
+As a first step we uploaded the [Dolphin Platform website](http://www.dolphin-platform.io) and added some descriptions and information about the framework. In addition we created [a first tutorial](http://www.dolphin-platform.io/documentation/tutorial.html) and a [getting started" guide](http://www.dolphin-platform.io/documentation/getting-started.html). All the Java sources (client and server) are uploaded to [GitHub](https://github.com/canoo/dolphin-platform), a first release has been created and was uploaded to [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cdolphin-platform) & [JCenter](https://bintray.com/canoo/dolphin-platform/dolphin-platform/0.6.1/view).
+
+If you want to try Dolphin Platform you can create your first application by simply adding the following dependencies:
+
+For a Spring Boot based server you only need to add the following dependency:
+```xml
+ com.canoo.dolphin-platform
+ dolphin-platform-server-spring
+ 0.6.1
+
```
+
+For a JavaFX based client you need to add the following dependency:
+```xml
+ com.canoo.dolphin-platform
+ dolphin-platform-client-javafx
+ 0.6.1
+
```
+
+If you are new to Dolphin Platform you can find some post about the API [in my blog](/posts/2015-10-04-dolphin-platform-a-sneak-peek). In addition we spend some time to create the [JavaDoc of the public API](http://www.dolphin-platform.io/javadoc/index.html). If you have any questions please leave a comment or [ask us on twitter](https://twitter.com/DolphinPlatform). For news about Dolphin Platform you should follow the official twitter account [@DolphinPlatform](https://twitter.com/DolphinPlatform).
+
+## Java Script client libraries
+
+As I [mentioned before](/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer) Dolphin Platform supports several client technologies. Next to the JavaFX library we hosted the sources for the basic [JavaScript client library](https://github.com/canoo/dolphin-platform-js) and the [Polymer client library](https://github.com/canoo/dolphin-platform-polymer) on github. We will add releases of the libraries this week. Once this is done I will blog how you can simply add Dolphin Platform to your web project by using [bower](http://bower.io).
+
+## Links
+
+Here is an overview of all important links:
+
+* [Dolphin Platform website](http://www.dolphin-platform.io)
+* [Getting started](http://www.dolphin-platform.io/documentation/getting-started.html)
+* [Tutorial](http://www.dolphin-platform.io/documentation/tutorial.html)
+* [JavaDoc](http://www.dolphin-platform.io/javadoc/index.html)
+* [StackOverflow](http://stackoverflow.com/questions/tagged/dolphin-platform)
+* [Blog Posts](/posts/2015-10-04-dolphin-platform-a-sneak-peek)
+* [Java Github Repo](https://github.com/canoo/dolphin-platform)
+* [JavaScript Github Repo](https://github.com/canoo/dolphin-platform-js)
+* [Polymer Github Repo](https://github.com/canoo/dolphin-platform-polymer)
+* [Dolphin Platform @ Twitter](https://twitter.com/DolphinPlatform)
diff --git a/content/posts/2015-11-11-building-modern-web-uis-with-web-components-university-devoxx.md b/content/posts/2015-11-11-building-modern-web-uis-with-web-components-university-devoxx.md
index dd50318b..25b5fd1f 100644
--- a/content/posts/2015-11-11-building-modern-web-uis-with-web-components-university-devoxx.md
+++ b/content/posts/2015-11-11-building-modern-web-uis-with-web-components-university-devoxx.md
@@ -12,4 +12,4 @@ On Monday [Michael Heinrichs](https://twitter.com/net0pyr) and did a 3 hour univ
Next to this the Devoxx team is really fast with the video post production and therefore or talk is already online:
-{{< youtube muqOStp3A_o >}}
+
diff --git a/content/posts/2015-11-11-dolphin-platform-kumuluzee-javaee-microservices-with-dynamic-and-rich-frontends.md b/content/posts/2015-11-11-dolphin-platform-kumuluzee-javaee-microservices-with-dynamic-and-rich-frontends.md
index ade7786a..e789bfbb 100644
--- a/content/posts/2015-11-11-dolphin-platform-kumuluzee-javaee-microservices-with-dynamic-and-rich-frontends.md
+++ b/content/posts/2015-11-11-dolphin-platform-kumuluzee-javaee-microservices-with-dynamic-and-rich-frontends.md
@@ -1,132 +1,124 @@
----
-outdated: true
-showInBlog: false
-title: 'Dolphin Platform & KumuluzEE: JavaEE Microservices with dynamic and rich frontends'
-date: "2015-11-11"
-author: hendrik
-categories: [General]
-excerpt: "Have you heard of KumuluzEE that is one of the 2015 Java Duke's Choice Award winners? This post shows how you can combine it with the Dolphin Platform."
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Have you heard of [KumuluzEE](https://ee.kumuluz.com) that is one of the 2015 Java Duke's Choice Award winners? Well, if you haven't heard about this cool project you should have a look. KumuluzEE is a JavaEE based framework to create microservices and JavaEE based applications that can start on their own without deploying them to an application server. If you know [Spring Boot](http://projects.spring.io/spring-boot/) the description is quite easy: KumuluzEE is Spring Boot for the JavaEE framework. In this post I will show how you combine kumuluzEE with [Dolphin Platform](http://www.dolphin-platform.io) to create lightweight microservices with a dynamic frontend.
-
-## KumuluzEE overview
-
-When using KumuluzEE you can work with all the JavaEE specs that you already know. Let's say you want to create an application that provides some REST endpoints and uses CDI internally. To do so you need to add the following dependencies to your project:
-
-{{< highlight xml >}}
-
- com.kumuluz.ee
- kumuluzee-core
- ${kumuluzee.version}
-
-
- com.kumuluz.ee
- kumuluzee-servlet-jetty
- ${kumuluzee.version}
-
-
- com.kumuluz.ee
- kumuluzee-cdi
- ${kumuluzee.version}
-
-
- com.kumuluz.ee
- kumuluzee-jax-rs
- ${kumuluzee.version}
-
-{{< / highlight >}}
-
-Let's have a deeper look what this dependencies define and add to your project:
-
-* The `kumuluzee-core` dependencies is the basic dependency of KumuluzEE and must be added to each project
-* The `kumuluzee-servlet-jetty` dependencies adds an embedded jetty. This includes the implementation of the servlet API. If you only want to code based on servlets you are done now.
-* The `kumuluzee-cdi` dependencies adds CDI support to you application. Once this dependency is on your class path you can use CDI in your server application.
-* The `kumuluzee-jax-rs` dependencies adds support for JAX-RS. By adding this dependency you can add REST endpoints to your application.
-
-Once this is done you can create your (microservice) JavaEE application. You can use all the defaults of the specs that are added as dependencies. The following code shows how a REST endpoint might look like:
-
-{{< highlight java >}}
-@Path("/orders")
-@Produces(MediaType.APPLICATION_JSON)
-@Consumes(MediaType.APPLICATION_JSON)
-@RequestScoped
-public class OrdersResource {
-
- @Inject
- private MyService service;
-
- @GET
- @Path("/{id}")
- public Response getOrder(@PathParam("id") Integer id) {
- BookOrder o = service.find(BookOrderid);
- if (o == null)
- return Response.status(Response.Status.NOT_FOUND).build();
- return Response.ok(o).build();
- }
-}
-{{< / highlight >}}
-
-To start your app kumuluzEE adds the class `com.kumuluz.ee.EeApplication` that contains a default main method. By starting the application your endpoints will be up faster than you can spell "weblogic".
-
-## KumuluzEE and Dolphin Platform
-
-Since KumuluzEE supports all the JavaEE specs that are needed for the Dolphin Platform it's quite easy to create a Dolphin Platform application based on KumuluzEE. To do so you only need to add the following dependencies to your application:
-
-{{< highlight xml >}}
-
- com.canoo.dolphin-platform
- dolphin-platform-server-javaee
- 0.7.0-SNAPSHOT
-
-
- com.kumuluz.ee
- kumuluzee-core
- 1.0.0
-
-
- com.kumuluz.ee
- kumuluzee-servlet-jetty
- 1.0.0
-
-
- com.kumuluz.ee
- kumuluzee-cdi
- 1.0.0
-
-{{< / highlight >}}
-
-Please notice that the feature is still in development and will be part of Dolphin Platform 0.7.0 ;)
-
-Once this is done you can start to create your Dolphin Controllers that will automatically be managed by JavaEE and support features like CDI.
-
-{{< highlight java >}}
-@DolphinController
-public class MyController {
-
- @DolphinModel
- private MyModel model;
-
- @Inject
- private MyJavaEEService service;
-
- @PostConstruct
- public void onInit() {
- System.out.println("Init");
- }
-
- @PreDestroy
- public void onDestroy() {
- System.out.println("Destroyed");
- }
-
- @DolphinAction
- public void someAction() {
- System.out.println("Action");
- }
-}
-{{< / highlight >}}
-
-## Conclusion
-
-Thanks to KumuluzEE you can create lightweight Dolphin Platform applications by using the enterprise framework APIs that you might now and like since years. The best: Since you don't use specific JavaEE or Spring code in your Dolphin Platform controllers they will work in both Spring and JavaEE. Just add the right dependency and your controllers will be automatically managed by the container. In my last tests both implementations bootstrapped in under 7 seconds :)
+---
+outdated: true
+showInBlog: false
+title: 'Dolphin Platform & KumuluzEE: JavaEE Microservices with dynamic and rich frontends'
+date: "2015-11-11"
+author: hendrik
+categories: [General]
+excerpt: "Have you heard of KumuluzEE that is one of the 2015 Java Duke's Choice Award winners? This post shows how you can combine it with the Dolphin Platform."
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Have you heard of [KumuluzEE](https://ee.kumuluz.com) that is one of the 2015 Java Duke's Choice Award winners? Well, if you haven't heard about this cool project you should have a look. KumuluzEE is a JavaEE based framework to create microservices and JavaEE based applications that can start on their own without deploying them to an application server. If you know [Spring Boot](http://projects.spring.io/spring-boot/) the description is quite easy: KumuluzEE is Spring Boot for the JavaEE framework. In this post I will show how you combine kumuluzEE with [Dolphin Platform](http://www.dolphin-platform.io) to create lightweight microservices with a dynamic frontend.
+
+## KumuluzEE overview
+
+When using KumuluzEE you can work with all the JavaEE specs that you already know. Let's say you want to create an application that provides some REST endpoints and uses CDI internally. To do so you need to add the following dependencies to your project:
+
+```xml
+ com.kumuluz.ee
+ kumuluzee-core
+ ${kumuluzee.version}
+
+
+ com.kumuluz.ee
+ kumuluzee-servlet-jetty
+ ${kumuluzee.version}
+
+
+ com.kumuluz.ee
+ kumuluzee-cdi
+ ${kumuluzee.version}
+
+
+ com.kumuluz.ee
+ kumuluzee-jax-rs
+ ${kumuluzee.version}
+
```
+
+Let's have a deeper look what this dependencies define and add to your project:
+
+* The `kumuluzee-core` dependencies is the basic dependency of KumuluzEE and must be added to each project
+* The `kumuluzee-servlet-jetty` dependencies adds an embedded jetty. This includes the implementation of the servlet API. If you only want to code based on servlets you are done now.
+* The `kumuluzee-cdi` dependencies adds CDI support to you application. Once this dependency is on your class path you can use CDI in your server application.
+* The `kumuluzee-jax-rs` dependencies adds support for JAX-RS. By adding this dependency you can add REST endpoints to your application.
+
+Once this is done you can create your (microservice) JavaEE application. You can use all the defaults of the specs that are added as dependencies. The following code shows how a REST endpoint might look like:
+
+```java@Path("/orders")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@RequestScoped
+public class OrdersResource {
+
+ @Inject
+ private MyService service;
+
+ @GET
+ @Path("/{id}")
+ public Response getOrder(@PathParam("id") Integer id) {
+ BookOrder o = service.find(BookOrderid);
+ if (o == null)
+ return Response.status(Response.Status.NOT_FOUND).build();
+ return Response.ok(o).build();
+ }
+}
```
+
+To start your app kumuluzEE adds the class `com.kumuluz.ee.EeApplication` that contains a default main method. By starting the application your endpoints will be up faster than you can spell "weblogic".
+
+## KumuluzEE and Dolphin Platform
+
+Since KumuluzEE supports all the JavaEE specs that are needed for the Dolphin Platform it's quite easy to create a Dolphin Platform application based on KumuluzEE. To do so you only need to add the following dependencies to your application:
+
+```xml
+ com.canoo.dolphin-platform
+ dolphin-platform-server-javaee
+ 0.7.0-SNAPSHOT
+
+
+ com.kumuluz.ee
+ kumuluzee-core
+ 1.0.0
+
+
+ com.kumuluz.ee
+ kumuluzee-servlet-jetty
+ 1.0.0
+
+
+ com.kumuluz.ee
+ kumuluzee-cdi
+ 1.0.0
+
```
+
+Please notice that the feature is still in development and will be part of Dolphin Platform 0.7.0 ;)
+
+Once this is done you can start to create your Dolphin Controllers that will automatically be managed by JavaEE and support features like CDI.
+
+```java@DolphinController
+public class MyController {
+
+ @DolphinModel
+ private MyModel model;
+
+ @Inject
+ private MyJavaEEService service;
+
+ @PostConstruct
+ public void onInit() {
+ System.out.println("Init");
+ }
+
+ @PreDestroy
+ public void onDestroy() {
+ System.out.println("Destroyed");
+ }
+
+ @DolphinAction
+ public void someAction() {
+ System.out.println("Action");
+ }
+}
```
+
+## Conclusion
+
+Thanks to KumuluzEE you can create lightweight Dolphin Platform applications by using the enterprise framework APIs that you might now and like since years. The best: Since you don't use specific JavaEE or Spring code in your Dolphin Platform controllers they will work in both Spring and JavaEE. Just add the right dependency and your controllers will be automatically managed by the container. In my last tests both implementations bootstrapped in under 7 seconds :)
diff --git a/content/posts/2015-11-12-dolphin-platform-in-15-minutes-nighthacking.md b/content/posts/2015-11-12-dolphin-platform-in-15-minutes-nighthacking.md
index 012671bd..6320b388 100644
--- a/content/posts/2015-11-12-dolphin-platform-in-15-minutes-nighthacking.md
+++ b/content/posts/2015-11-12-dolphin-platform-in-15-minutes-nighthacking.md
@@ -10,4 +10,4 @@ preview_image: "/posts/preview-images/software-development-green.svg"
---
Michael and I were interviewed at Devoxx about the [Dolphin Platform](http://www.dolphin-platform.io). In the interview we explain the benefits of the framework and show some code. The video was uploaded some minutes ago and you can find it here:
-{{< youtube _AoHizQpJZ8 >}}
+
diff --git a/content/posts/2015-12-02-dolphin-platform-jumpstart.md b/content/posts/2015-12-02-dolphin-platform-jumpstart.md
index 12ef197e..74693389 100644
--- a/content/posts/2015-12-02-dolphin-platform-jumpstart.md
+++ b/content/posts/2015-12-02-dolphin-platform-jumpstart.md
@@ -18,6 +18,6 @@ The Maven multi module project that is created by using this first archetype con
The following video shows how you can create your first Dolphin Platform application in 1 minute by using IntelliJ:
-{{< youtube e0vdf0coNuc >}}
+
-I will post about other IDE and the commandline usage later. If you have any questions about Dolphin Platform you can now use the ["dolphin-platform" tag at stackoverflow](http://stackoverflow.com/questions/tagged/dolphin-platform). If you are new to Dolphin Platform you can find general information and tutorials [here](http://www.dolphin-platform.io) and [here]({{< ref "/posts/2015-11-09-dolphin-platform-has-been-released" >}}).
+I will post about other IDE and the commandline usage later. If you have any questions about Dolphin Platform you can now use the ["dolphin-platform" tag at stackoverflow](http://stackoverflow.com/questions/tagged/dolphin-platform). If you are new to Dolphin Platform you can find general information and tutorials [here](http://www.dolphin-platform.io) and [here](/posts/2015-11-09-dolphin-platform-has-been-released).
diff --git a/content/posts/2015-12-16-dolphin-platform-0-7-has-been-released.md b/content/posts/2015-12-16-dolphin-platform-0-7-has-been-released.md
index 93c8a933..b8ac1d3c 100644
--- a/content/posts/2015-12-16-dolphin-platform-0-7-has-been-released.md
+++ b/content/posts/2015-12-16-dolphin-platform-0-7-has-been-released.md
@@ -1,19 +1,17 @@
----
-outdated: true
-showInBlog: false
-title: 'Dolphin Platform 0.7 has been released'
-date: "2015-12-16"
-author: hendrik
-categories: [Dolphin Platform]
-excerpt: 'We released version 0.7 of the Dolphin Platform today. Next to the framework we updated the Spring Boot archetype for Maven and added a KumuluzEE Maven archetype.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-We released version 0.7 of the [Dolphin Platform](http://www.dolphin-platform.io) today. Next to the framework we updated the Spring Boot archetype for Maven and added a KumuluzEE Maven archetype. By using this archetypes you can create a Dolphin Platform based client server application in a minute. An example how you can use the archetypes can be found [here]({{< ref "/posts/2015-12-02-dolphin-platform-jumpstart" >}}).
-
-If you want to create your new project from command line you can simply call this Maven command and select one of the shown Dolphin Platform archetypes:
-
-{{< highlight shell >}}
-mvn archetype:generate -Dfilter=com.canoo.dolphin-platform:
-{{< / highlight >}}
-
-Currently the projects contains only a JavaFX based client but it's planned to add a Polymer based client to the archetypes with the next release.
+---
+outdated: true
+showInBlog: false
+title: 'Dolphin Platform 0.7 has been released'
+date: "2015-12-16"
+author: hendrik
+categories: [Dolphin Platform]
+excerpt: 'We released version 0.7 of the Dolphin Platform today. Next to the framework we updated the Spring Boot archetype for Maven and added a KumuluzEE Maven archetype.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+We released version 0.7 of the [Dolphin Platform](http://www.dolphin-platform.io) today. Next to the framework we updated the Spring Boot archetype for Maven and added a KumuluzEE Maven archetype. By using this archetypes you can create a Dolphin Platform based client server application in a minute. An example how you can use the archetypes can be found [here](/posts/2015-12-02-dolphin-platform-jumpstart).
+
+If you want to create your new project from command line you can simply call this Maven command and select one of the shown Dolphin Platform archetypes:
+
+```shellmvn archetype:generate -Dfilter=com.canoo.dolphin-platform:
```
+
+Currently the projects contains only a JavaFX based client but it's planned to add a Polymer based client to the archetypes with the next release.
diff --git a/content/posts/2015-12-16-dolphin-platform-and-polymer.md b/content/posts/2015-12-16-dolphin-platform-and-polymer.md
index 560d7e72..aba42359 100644
--- a/content/posts/2015-12-16-dolphin-platform-and-polymer.md
+++ b/content/posts/2015-12-16-dolphin-platform-and-polymer.md
@@ -8,4 +8,4 @@ categories: [Dolphin Platform, JavaFX, Polymer, Web Frontends, WebComponents]
excerpt: 'Starting with version 0.7 the Dolphin Platform JavaScript and Polymer API has been released.'
preview_image: "/posts/preview-images/software-development-green.svg"
---
-Starting with [version 0.7]({{< ref "/posts/2015-12-16-dolphin-platform-0-7-has-been-released" >}}) the Dolphin Platform JavaScript and [Polymer]({{< ref "/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer" >}}) API has been released. Now you can easily create desktop, mobile and web clients for your application by using the same controller and presentation model. You only need to change the thin view layer. The Dolphin Platform repository at GitHub already contains a small client server application with a JavaFX based client and a Polymer client. In addition the example contains a [Spring Boot](http://spring boot tutorial) and a [KumuluzEE](http://www.kumuluz.com) server. By doing so you can select the environment that fits perfectly to your needs. You can find there project [here](https://github.com/canoo/dolphin-platform/tree/46bf958b5f50a9d9517ca03176dfda40f2a0801c/todo-example). A short description about the Polymer client API can be found [here]({{< ref "/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer" >}}).
+Starting with [version 0.7](/posts/2015-12-16-dolphin-platform-0-7-has-been-released) the Dolphin Platform JavaScript and [Polymer](/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer) API has been released. Now you can easily create desktop, mobile and web clients for your application by using the same controller and presentation model. You only need to change the thin view layer. The Dolphin Platform repository at GitHub already contains a small client server application with a JavaFX based client and a Polymer client. In addition the example contains a [Spring Boot](http://spring boot tutorial) and a [KumuluzEE](http://www.kumuluz.com) server. By doing so you can select the environment that fits perfectly to your needs. You can find there project [here](https://github.com/canoo/dolphin-platform/tree/46bf958b5f50a9d9517ca03176dfda40f2a0801c/todo-example). A short description about the Polymer client API can be found [here](/posts/2015-10-23-dolphin-platform-web-frontends-with-polymer).
diff --git a/content/posts/2016-01-13-the-javaone-voting-machine.md b/content/posts/2016-01-13-the-javaone-voting-machine.md
index 495d74ae..6d5b545a 100644
--- a/content/posts/2016-01-13-the-javaone-voting-machine.md
+++ b/content/posts/2016-01-13-the-javaone-voting-machine.md
@@ -42,7 +42,7 @@ We found a good designer that already had some knowledge in drawing Duke since h
You can find a short example how these animations look like in this YouTube video:
-{{< youtube GTFJ_1CoeU >}}
+
Even if the designer already drew some Duke images he misunderstood the face of Duke and thought Duke is a Cyclops as you can see in this first preview of the sleeping animation:
diff --git a/content/posts/2016-02-04-dolphin-platform-0-8-has-beed-released.md b/content/posts/2016-02-04-dolphin-platform-0-8-has-beed-released.md
index 4672adf6..12836845 100644
--- a/content/posts/2016-02-04-dolphin-platform-0-8-has-beed-released.md
+++ b/content/posts/2016-02-04-dolphin-platform-0-8-has-beed-released.md
@@ -1,69 +1,61 @@
----
-outdated: true
-showInBlog: false
-title: 'Dolphin Platform 0.8 has beed released'
-date: "2016-02-04"
-author: hendrik
-categories: [Dolphin Platform, JavaFX, Polymer]
-excerpt: 'The 0.8 version of Dolphin Platform provides several new features like Java Bean Validation support of new bindings for JavaFX.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Yesterday we released version 0.8 of Dolphin Platform. The version contains several bugfixes and some new features that I want to show here.
-
-## Validation
-
-I think the biggest new feature is the support of Java Bean Validation (JSR-303). For this feature we introduce a new module to Dolphin Platform that you can easily add to your application dependencies:
-
-{{< highlight xml >}}
-
- com.canoo.dolphin-platform
- dolphin-platform-bean-validation
- DOLPHIN_PLATFORM_VERSION
-
-{{< / highlight >}}
-
-Once this is done you can use bean validation in the model layer. By doing so you can define your beans like this:
-
-{{< highlight java >}}
-@DolphinBean
-public class MyModel {
-
- @NotNull
- private Property value;
-
- public Property valueProperty() {
- return value1;
- }
-}
-{{< / highlight >}}
-
-As you can see the `@NotNull` annotation is added to the property in the bean class. By doing so you can simply validate instances of the bean by using a `Validator`
-
-Currently not all validation annotations are supported but this is just an open todo. at the moment the following annotations are supported:
-
-* `@AssertFalse`
-* `@AssertTrue`
-* `@DecimalMax`
-* `@DecimalMin`
-* `@NotNull`
-* `@Null`
-
-For more information about the bean validation support in Dolphin Platform you should have a look at the [readme](https://github.com/canoo/dolphin-platform/tree/master/java-bean-validation).
-
-## JavaFX bindings
-
-For version 0.8 we added a lot of functionality to the JavaFX binding layer. Based on this it's no possible to simply bind a JavaFX list to an observable list of the Dolphin Platform model layer. To do so only one line if code is needed:
-
-{{< highlight java >}}
-FXBinder.bind(javaFXList).to(modelList);
-{{< / highlight >}}
-
-Next to this we added support for converters. By doing so you can bind properties of lists of a different type to each other. This is interesting if you want to bind UI specific classes to the model layer. When using the JavaFX chart API the data model of the charts is defined by JavaFX specific classes. Since you don't want to have this classes in the model layer that is shared between client and server you can simply define a converter and bind the model of a chart to your custom bean type. Using such a converter is as easy as a normal binding:
-
-{{< highlight java >}}
-FXBinder.bind(javaFXChartModel).to(dolphinModel, myCustomConverter);
-{{< / highlight >}}
-
-## Additional changes
-
-Next to this we added some minor features like new convenience methods in the `ObservableList` and fixed some bugs. A complete list of the changes can be found [here](https://github.com/canoo/dolphin-platform/issues?q=milestone%3A0.8.0).
+---
+outdated: true
+showInBlog: false
+title: 'Dolphin Platform 0.8 has beed released'
+date: "2016-02-04"
+author: hendrik
+categories: [Dolphin Platform, JavaFX, Polymer]
+excerpt: 'The 0.8 version of Dolphin Platform provides several new features like Java Bean Validation support of new bindings for JavaFX.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Yesterday we released version 0.8 of Dolphin Platform. The version contains several bugfixes and some new features that I want to show here.
+
+## Validation
+
+I think the biggest new feature is the support of Java Bean Validation (JSR-303). For this feature we introduce a new module to Dolphin Platform that you can easily add to your application dependencies:
+
+```xml
+ com.canoo.dolphin-platform
+ dolphin-platform-bean-validation
+ DOLPHIN_PLATFORM_VERSION
+
```
+
+Once this is done you can use bean validation in the model layer. By doing so you can define your beans like this:
+
+```java@DolphinBean
+public class MyModel {
+
+ @NotNull
+ private Property value;
+
+ public Property valueProperty() {
+ return value1;
+ }
+}
```
+
+As you can see the `@NotNull` annotation is added to the property in the bean class. By doing so you can simply validate instances of the bean by using a `Validator`
+
+Currently not all validation annotations are supported but this is just an open todo. at the moment the following annotations are supported:
+
+* `@AssertFalse`
+* `@AssertTrue`
+* `@DecimalMax`
+* `@DecimalMin`
+* `@NotNull`
+* `@Null`
+
+For more information about the bean validation support in Dolphin Platform you should have a look at the [readme](https://github.com/canoo/dolphin-platform/tree/master/java-bean-validation).
+
+## JavaFX bindings
+
+For version 0.8 we added a lot of functionality to the JavaFX binding layer. Based on this it's no possible to simply bind a JavaFX list to an observable list of the Dolphin Platform model layer. To do so only one line if code is needed:
+
+```javaFXBinder.bind(javaFXList).to(modelList);
```
+
+Next to this we added support for converters. By doing so you can bind properties of lists of a different type to each other. This is interesting if you want to bind UI specific classes to the model layer. When using the JavaFX chart API the data model of the charts is defined by JavaFX specific classes. Since you don't want to have this classes in the model layer that is shared between client and server you can simply define a converter and bind the model of a chart to your custom bean type. Using such a converter is as easy as a normal binding:
+
+```javaFXBinder.bind(javaFXChartModel).to(dolphinModel, myCustomConverter);
```
+
+## Additional changes
+
+Next to this we added some minor features like new convenience methods in the `ObservableList` and fixed some bugs. A complete list of the changes can be found [here](https://github.com/canoo/dolphin-platform/issues?q=milestone%3A0.8.0).
diff --git a/content/posts/2016-02-04-round-images-with-css.md b/content/posts/2016-02-04-round-images-with-css.md
index 01de4605..bfcbe27d 100644
--- a/content/posts/2016-02-04-round-images-with-css.md
+++ b/content/posts/2016-02-04-round-images-with-css.md
@@ -1,43 +1,37 @@
----
-outdated: true
-showInBlog: false
-title: 'Round Images with CSS'
-date: "2016-02-04"
-author: hendrik
-categories: [Web Frontends]
-excerpt: 'Always wanted to create round images in your web page? Instead of doing this with a graphic editor by hand you can use CSS to show a rounded image based on a regular image on your page.'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this post I will show the easiest way how a rounded image can be defined in CSS. This example is for HTML. If you want to create a rounded image with JavaFX you should [read this post]({{< ref "/posts/2015-11-30-round-images-with-javafx" >}}).
-
-An image is defined by the `img` tag. To define some CSS for the image we should add a style class like "avatar":
-
-{{< highlight html >}}
-
-{{< / highlight >}}
-
-In this first example I will show how you can define a rounded image for a square image. To do so we define the size of the image in CSS:
-
-{{< highlight css >}}
-.avatar {
- width: 64px;
- height: 64px;
-}
-{{< / highlight >}}
-
-Once this is done it's quite easy to create the round effect by defining a rounded border. Here the radius of the border must be defined as the half width / height. In addition we could define a border color and a border width to add a visual contrast.
-
-{{< highlight css >}}
-.avatar {
- width: 64px;
- height: 64px;
- border-radius: 50%;
- border-style: solid;
- border-width: 1px;
- border-color: lightgrey;
-}
-{{< / highlight >}}
-
-Once this is done you could use the image on any background and it's looks quite nice:
-
-
+---
+outdated: true
+showInBlog: false
+title: 'Round Images with CSS'
+date: "2016-02-04"
+author: hendrik
+categories: [Web Frontends]
+excerpt: 'Always wanted to create round images in your web page? Instead of doing this with a graphic editor by hand you can use CSS to show a rounded image based on a regular image on your page.'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this post I will show the easiest way how a rounded image can be defined in CSS. This example is for HTML. If you want to create a rounded image with JavaFX you should [read this post](/posts/2015-11-30-round-images-with-javafx).
+
+An image is defined by the `img` tag. To define some CSS for the image we should add a style class like "avatar":
+
+```html
```
+
+In this first example I will show how you can define a rounded image for a square image. To do so we define the size of the image in CSS:
+
+```css.avatar {
+ width: 64px;
+ height: 64px;
+}
```
+
+Once this is done it's quite easy to create the round effect by defining a rounded border. Here the radius of the border must be defined as the half width / height. In addition we could define a border color and a border width to add a visual contrast.
+
+```css.avatar {
+ width: 64px;
+ height: 64px;
+ border-radius: 50%;
+ border-style: solid;
+ border-width: 1px;
+ border-color: lightgrey;
+}
```
+
+Once this is done you could use the image on any background and it's looks quite nice:
+
+
diff --git a/content/posts/2016-02-07-javafx-and-css.md b/content/posts/2016-02-07-javafx-and-css.md
index 4da01c9d..0844a4c3 100644
--- a/content/posts/2016-02-07-javafx-and-css.md
+++ b/content/posts/2016-02-07-javafx-and-css.md
@@ -1,89 +1,75 @@
----
-outdated: true
-showInBlog: false
-title: 'JavaFX and CSS'
-date: "2016-02-07"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'One of the cool features of JavaFX is the CSS support. By using CSS you can simply style a single control or a complete application. This post gives a first introduction to the CSS usage and API in JavaFX'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-One of the cool features of JavaFX is the CSS support. By using CSS you can simply style a single control or a complete application. The CSS support in JavaFX is based on the W3C CSS version 2.1. There are some minor differences that can be found in the [JavaFX CSS documentation](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html) that is the best source to check a specific property or value type when using CSS in JavaFX.
-
-
-
-## How to define CSS rules in JavaFX
-
-Normally CSS rules are defined in a CSS file called stylesheet. A CSS file normally uses the `*.css` extension like `style.css`. A stylesheet can contain one or several CSS rules. Here is an content for a stylesheet that contains only one CSS rule:
-
-{{< highlight css >}}
-.button {
- -fx-background-color: blue;
-}
-{{< / highlight >}}
-
-If you are familiar with the general CSS syntax you can see that defining a CSS rules in JavaFX is exactly the same as for the web. Only the name of the CSS property looks different.
-
-In JavaFX a stylesheet can be applied to the scene graph or to any node that is part of a scene graph. A stylesheet that is applied to the scene graph will affect all nodes that are part of the scene graph. If the stylesheet is applied to only a specific node it will affect this node and all its children (recursively). Several stylesheets can be applied to the scene graph or a single node. Internally the applied stylesheets are organized in a list. The following code snippet shows how you can set a stylesheet for a scene graph or a node:
-
-{{< highlight java >}}
-// load the stylesheet
-String style = getClass().getResource("style.css").toExternalForm();
-
-// apply stylesheet to the scene graph
-myScene.getStylesheets().addAll(style);
-
-// apply stylesheet to a node
-parentPanel.getStylesheets().addAll(style);
-{{< / highlight >}}
-
-Next to stylesheets that are defined in CSS files JavaFX supports inline stylesheets. With this feature you can define a CSS rules directly in your Java code as a String. In this case you don't need to define a CSS selector.
-
-{{< highlight java >}}
-button.setStyle("-fx-background-color: green;");
-{{< / highlight >}}
-
-Using inline styles isn't best practice and destroys the benefit of separation between code and style. I would recommend to use this feature only for visual debugging and testing.
-
-## CSS selectors in JavaFX
-
-To apply a CSS rule to a JavaFX node the selector of the rule must match to the node. JavaFX provides the possibility to define an `id`, `style classes` and `pseudo classes` for any node. All this metadata can be used to select a specific or several nodes based on a CSS selector at runtime. JavaFX provides some methods to define the metadata. Let's start with the `id`:
-
-As defined in the specification a node can have one id that is specified by a string value:
-
-{{< highlight java >}}
-mySaveButton.setId("my-save-button");
-{{< / highlight >}}
-
-A CSS rule with a selector that matches to the button can look like this:
-
-{{< highlight css >}}
-/* The # sign in the selector defines an id string */
-#my-save-button {
--fx-background-color: blue;
-}
-{{< / highlight >}}
-
-Next to the id a JavaFX can contain several style classes. Like the id all style classes are defined by strings. Internally all nodes contains a list for the style classes. A new style class can easily be added to a node like shown in this code snippet:
-
-{{< highlight java >}}
-button.getStyleClass().add("toolbar-button");
-{{< / highlight >}}
-
-Most of the basic JavaFX controls define one or several style classes by default. For example each Button has already defined the `.button` style class. By doing so the style of all buttons can easily be changed by this CSS rule:
-
-{{< highlight css >}}
-.button {
- -fx-background-color: red;
- -fx-text-fill: white;
- -fx-background-radius: 16px;
-}
-{{< / highlight >}}
-
-Once the stylesheet is added to the scene the buttons in your application will look like this:
-
-
-
-As you can see in the CSS definition all properties that are used until know are defined by the "-fx-" prefix. This is specific to JavaFX and defines a change against the CSS how you use it for styling in the web. Since most of the properties that you know from the web are supported all of them start with a `-fx-`. By doing so you could create a global stylesheet that styles your web frontend and JavaFX frontend.
-
-Based on this post I added a [second post]({{< ref "/posts/2016-02-09-javafx-and-css-pseudo-classes" >}}) the shows how you can use pseudo classes in JavaFX.
+---
+outdated: true
+showInBlog: false
+title: 'JavaFX and CSS'
+date: "2016-02-07"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'One of the cool features of JavaFX is the CSS support. By using CSS you can simply style a single control or a complete application. This post gives a first introduction to the CSS usage and API in JavaFX'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+One of the cool features of JavaFX is the CSS support. By using CSS you can simply style a single control or a complete application. The CSS support in JavaFX is based on the W3C CSS version 2.1. There are some minor differences that can be found in the [JavaFX CSS documentation](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html) that is the best source to check a specific property or value type when using CSS in JavaFX.
+
+
+
+## How to define CSS rules in JavaFX
+
+Normally CSS rules are defined in a CSS file called stylesheet. A CSS file normally uses the `*.css` extension like `style.css`. A stylesheet can contain one or several CSS rules. Here is an content for a stylesheet that contains only one CSS rule:
+
+```css.button {
+ -fx-background-color: blue;
+}
```
+
+If you are familiar with the general CSS syntax you can see that defining a CSS rules in JavaFX is exactly the same as for the web. Only the name of the CSS property looks different.
+
+In JavaFX a stylesheet can be applied to the scene graph or to any node that is part of a scene graph. A stylesheet that is applied to the scene graph will affect all nodes that are part of the scene graph. If the stylesheet is applied to only a specific node it will affect this node and all its children (recursively). Several stylesheets can be applied to the scene graph or a single node. Internally the applied stylesheets are organized in a list. The following code snippet shows how you can set a stylesheet for a scene graph or a node:
+
+```java// load the stylesheet
+String style = getClass().getResource("style.css").toExternalForm();
+
+// apply stylesheet to the scene graph
+myScene.getStylesheets().addAll(style);
+
+// apply stylesheet to a node
+parentPanel.getStylesheets().addAll(style);
```
+
+Next to stylesheets that are defined in CSS files JavaFX supports inline stylesheets. With this feature you can define a CSS rules directly in your Java code as a String. In this case you don't need to define a CSS selector.
+
+```javabutton.setStyle("-fx-background-color: green;");
```
+
+Using inline styles isn't best practice and destroys the benefit of separation between code and style. I would recommend to use this feature only for visual debugging and testing.
+
+## CSS selectors in JavaFX
+
+To apply a CSS rule to a JavaFX node the selector of the rule must match to the node. JavaFX provides the possibility to define an `id`, `style classes` and `pseudo classes` for any node. All this metadata can be used to select a specific or several nodes based on a CSS selector at runtime. JavaFX provides some methods to define the metadata. Let's start with the `id`:
+
+As defined in the specification a node can have one id that is specified by a string value:
+
+```javamySaveButton.setId("my-save-button");
```
+
+A CSS rule with a selector that matches to the button can look like this:
+
+```css/* The # sign in the selector defines an id string */
+#my-save-button {
+-fx-background-color: blue;
+}
```
+
+Next to the id a JavaFX can contain several style classes. Like the id all style classes are defined by strings. Internally all nodes contains a list for the style classes. A new style class can easily be added to a node like shown in this code snippet:
+
+```javabutton.getStyleClass().add("toolbar-button");
```
+
+Most of the basic JavaFX controls define one or several style classes by default. For example each Button has already defined the `.button` style class. By doing so the style of all buttons can easily be changed by this CSS rule:
+
+```css.button {
+ -fx-background-color: red;
+ -fx-text-fill: white;
+ -fx-background-radius: 16px;
+}
```
+
+Once the stylesheet is added to the scene the buttons in your application will look like this:
+
+
+
+As you can see in the CSS definition all properties that are used until know are defined by the "-fx-" prefix. This is specific to JavaFX and defines a change against the CSS how you use it for styling in the web. Since most of the properties that you know from the web are supported all of them start with a `-fx-`. By doing so you could create a global stylesheet that styles your web frontend and JavaFX frontend.
+
+Based on this post I added a [second post](/posts/2016-02-09-javafx-and-css-pseudo-classes) the shows how you can use pseudo classes in JavaFX.
diff --git a/content/posts/2016-02-09-javafx-and-css-pseudo-classes.md b/content/posts/2016-02-09-javafx-and-css-pseudo-classes.md
index 2d80e049..9196b726 100644
--- a/content/posts/2016-02-09-javafx-and-css-pseudo-classes.md
+++ b/content/posts/2016-02-09-javafx-and-css-pseudo-classes.md
@@ -1,129 +1,117 @@
----
-outdated: true
-showInBlog: false
-title: 'JavaFX and CSS: Pseudo Classes'
-date: "2016-02-09"
-author: hendrik
-categories: [JavaFX]
-excerpt: 'Pseudo classes are a really cool CSS feature that you can use to define styles for different states of a component. This post gives an overview how pseudo classes can be used in JavaFX'
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In [my last post]({{< ref "/posts/2016-02-07-javafx-and-css" >}}) I gave a quick overview of the how CSS can be used in JavaFX by styling nodes based on an id or style classes. Today I want to explain what a pseudo class is and how you can use it to style dynamic controls.
-
-## CSS Pseudo Classes
-
-In CSS a pseudo class is used to define a specific state of a node. In general a node can have `0-n` pseudo classes. Let's think about a regular JavaFX Button and how it is rendered. When thinking about this the first visualization that comes into mind is this one:
-
-
-
-The button that is shown on the picture has a defined state:
-
-* The button is not disabled
-* The button is not armed
-* The button is focused
-* The mouse cursor is not over the button (no hover)
-
-Based on this definition the state of the button instance is defined what ends in a specific visualization. Next to the visualization that is shown on the image a button can be rendered in several different ways that reflect the current state of the button. Here is an overview of some buttons that are rendered in different states:
-
-
-
-Since all JavaFX controls are styled by CSS all the different states must be specified in CSS. To do so you need pseudo classes to define specific styles for states of the control.
-
-## How to use a pseudo class in CSS
-
-Since all JavaFX controls already support several pseudo classes you can simply define a CSS rule for a specific pseudo class. Let's say you want to change the font color of a button whenever the mouse cursor is over the button. For this special state of a node the `hover` pseudo class is defined in JavaFX. Therefore you can simply define the following CSS rule:
-
-{{< highlight css >}}
-#my-button:hover {
- -fx-text-fill: orange;
-}
-{{< / highlight >}}
-
-As you can see a pseudo class can simply be added to a CSS selector by using the ":" as a prefix for the pseudo class. In this example the rule is defined for a specific button that is defined by an id (`my-button`) but you can use a pseudo class in combination with every CSS selector. In the last post I described how a selection can be done by using a style class. By doing so you can simply define a specific CSS rule for all buttons by using the following selector:
-
-{{< highlight css >}}
-.button:hover {
- -fx-text-fill: orange;
-}
-{{< / highlight >}}
-
-Next to the `hover` pseudo class JavaFX controls support several other pseudo classes. An overview can be found in the [JavaFX CSS documentation](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html).
-
-## How to define new pseudo classes
-
-As you have seen the basic JavaFX controls already support several pseudo classes to style specific states of a control. But maybe that is not enough for your current project. If you extend a control and add new states or create a custom control you need to define your own pseudo classes if you want to support styling with CSS. To define a pseudo class JavaFX contains the class `PseudoClass` that can be used to create a new pseudo class definition for your control. Here it's best practice to use a static instance directly in your control class:
-
-{{< highlight java >}}
-public class MyCustomButton extends Button {
-
- private static PseudoClass EXPLODING_PSEUDO_CLASS = PseudoClass.getPseudoClass("exploding");
-
-}
-{{< / highlight >}}
-
-The pseudo class that is created in the code snippet can be used in CSS selectors by its given name ("exploding"). As a next step we need to active and deactivate the pseudo class. To do so it's best practice to create a boolean property in you control that reflects the state of the pseudo class. By doing so you can simply mutate and check the state in Java by using the property. Internally the state of the pseudo class changes whenever the value of the property changes. To set the state of a pseudo class the JavaFX `Node` class provides the method `pseudoClassStateChanged(PseudoClass pseudoClass, boolean active)`. The following code snippet shows how you can create a control that defines a new state by using a property and automatically updates the pseudo class based on the property value:
-
-{{< highlight java >}}
-public class MyCustomButton extends Button {
-
- private static PseudoClass EXPLODING_PSEUDO_CLASS = PseudoClass.getPseudoClass("exploding");
-
- BooleanProperty exploding = new BooleanPropertyBase(false) {
- public void invalidated() {
- pseudoClassStateChanged(EXPLODING_PSEUDO_CLASS, get());
- }
-
- @Override public Object getBean() {
- return MyControl.this;
- }
-
- @Override public String getName() {
- return "exploding";
- }
- };
-
- public void setExploding(boolean exploding) {
- this.exploding.set(exploding);
- }
-}
-{{< / highlight >}}
-
-The code snippet shows the best practice how it's defined in the JavaFX documentation. If this code is too long for you or you don't like to override the property class you could get the same result by using a listener:
-
-{{< highlight java >}}
-public class MyCustomButton extends Button {
-
- private static PseudoClass EXPLODING_PSEUDO_CLASS = PseudoClass.getPseudoClass("exploding");
-
- BooleanProperty exploding;
-
- public MyCustomButton() {
- exploding = new SimpleBooleanProperty(false);
- exploding.addListener(e -> pseudoClassStateChanged(EXPLODING_PSEUDO_CLASS, exploding.get()));
-
- getStyleClasses().add("exploding-button");
- }
-
- public void setExploding(boolean exploding) {
- this.exploding.set(exploding);
- }
-
- public boolean isExploding() {
- return this.exploding.get();
- }
-}
-{{< / highlight >}}
-
-As you can see in the last code snippet I added the style class `exploding-button` to the costume control. By doing so I can now define the following CSS Rule that will effect my new control type if the `exploding` style class is active:
-
-{{< highlight java >}}
-.exploding-button:exploding {
- -fx-background-color: red;
-}
-{{< / highlight >}}
-
-## Conclusion
-
-As you can see pseudo classes adds an important feature to JavaFX and CSS. By using pseudo classes you can define custom styles for specific states of a control and simply reflect the state of a control in it's visualization.
-
-As a next step I will blog about the different property types that are supported by CSS in JavaFX.
+---
+outdated: true
+showInBlog: false
+title: 'JavaFX and CSS: Pseudo Classes'
+date: "2016-02-09"
+author: hendrik
+categories: [JavaFX]
+excerpt: 'Pseudo classes are a really cool CSS feature that you can use to define styles for different states of a component. This post gives an overview how pseudo classes can be used in JavaFX'
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In [my last post](/posts/2016-02-07-javafx-and-css) I gave a quick overview of the how CSS can be used in JavaFX by styling nodes based on an id or style classes. Today I want to explain what a pseudo class is and how you can use it to style dynamic controls.
+
+## CSS Pseudo Classes
+
+In CSS a pseudo class is used to define a specific state of a node. In general a node can have `0-n` pseudo classes. Let's think about a regular JavaFX Button and how it is rendered. When thinking about this the first visualization that comes into mind is this one:
+
+
+
+The button that is shown on the picture has a defined state:
+
+* The button is not disabled
+* The button is not armed
+* The button is focused
+* The mouse cursor is not over the button (no hover)
+
+Based on this definition the state of the button instance is defined what ends in a specific visualization. Next to the visualization that is shown on the image a button can be rendered in several different ways that reflect the current state of the button. Here is an overview of some buttons that are rendered in different states:
+
+
+
+Since all JavaFX controls are styled by CSS all the different states must be specified in CSS. To do so you need pseudo classes to define specific styles for states of the control.
+
+## How to use a pseudo class in CSS
+
+Since all JavaFX controls already support several pseudo classes you can simply define a CSS rule for a specific pseudo class. Let's say you want to change the font color of a button whenever the mouse cursor is over the button. For this special state of a node the `hover` pseudo class is defined in JavaFX. Therefore you can simply define the following CSS rule:
+
+```css#my-button:hover {
+ -fx-text-fill: orange;
+}
```
+
+As you can see a pseudo class can simply be added to a CSS selector by using the ":" as a prefix for the pseudo class. In this example the rule is defined for a specific button that is defined by an id (`my-button`) but you can use a pseudo class in combination with every CSS selector. In the last post I described how a selection can be done by using a style class. By doing so you can simply define a specific CSS rule for all buttons by using the following selector:
+
+```css.button:hover {
+ -fx-text-fill: orange;
+}
```
+
+Next to the `hover` pseudo class JavaFX controls support several other pseudo classes. An overview can be found in the [JavaFX CSS documentation](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html).
+
+## How to define new pseudo classes
+
+As you have seen the basic JavaFX controls already support several pseudo classes to style specific states of a control. But maybe that is not enough for your current project. If you extend a control and add new states or create a custom control you need to define your own pseudo classes if you want to support styling with CSS. To define a pseudo class JavaFX contains the class `PseudoClass` that can be used to create a new pseudo class definition for your control. Here it's best practice to use a static instance directly in your control class:
+
+```javapublic class MyCustomButton extends Button {
+
+ private static PseudoClass EXPLODING_PSEUDO_CLASS = PseudoClass.getPseudoClass("exploding");
+
+}
```
+
+The pseudo class that is created in the code snippet can be used in CSS selectors by its given name ("exploding"). As a next step we need to active and deactivate the pseudo class. To do so it's best practice to create a boolean property in you control that reflects the state of the pseudo class. By doing so you can simply mutate and check the state in Java by using the property. Internally the state of the pseudo class changes whenever the value of the property changes. To set the state of a pseudo class the JavaFX `Node` class provides the method `pseudoClassStateChanged(PseudoClass pseudoClass, boolean active)`. The following code snippet shows how you can create a control that defines a new state by using a property and automatically updates the pseudo class based on the property value:
+
+```javapublic class MyCustomButton extends Button {
+
+ private static PseudoClass EXPLODING_PSEUDO_CLASS = PseudoClass.getPseudoClass("exploding");
+
+ BooleanProperty exploding = new BooleanPropertyBase(false) {
+ public void invalidated() {
+ pseudoClassStateChanged(EXPLODING_PSEUDO_CLASS, get());
+ }
+
+ @Override public Object getBean() {
+ return MyControl.this;
+ }
+
+ @Override public String getName() {
+ return "exploding";
+ }
+ };
+
+ public void setExploding(boolean exploding) {
+ this.exploding.set(exploding);
+ }
+}
```
+
+The code snippet shows the best practice how it's defined in the JavaFX documentation. If this code is too long for you or you don't like to override the property class you could get the same result by using a listener:
+
+```javapublic class MyCustomButton extends Button {
+
+ private static PseudoClass EXPLODING_PSEUDO_CLASS = PseudoClass.getPseudoClass("exploding");
+
+ BooleanProperty exploding;
+
+ public MyCustomButton() {
+ exploding = new SimpleBooleanProperty(false);
+ exploding.addListener(e -> pseudoClassStateChanged(EXPLODING_PSEUDO_CLASS, exploding.get()));
+
+ getStyleClasses().add("exploding-button");
+ }
+
+ public void setExploding(boolean exploding) {
+ this.exploding.set(exploding);
+ }
+
+ public boolean isExploding() {
+ return this.exploding.get();
+ }
+}
```
+
+As you can see in the last code snippet I added the style class `exploding-button` to the costume control. By doing so I can now define the following CSS Rule that will effect my new control type if the `exploding` style class is active:
+
+```java.exploding-button:exploding {
+ -fx-background-color: red;
+}
```
+
+## Conclusion
+
+As you can see pseudo classes adds an important feature to JavaFX and CSS. By using pseudo classes you can define custom styles for specific states of a control and simply reflect the state of a control in it's visualization.
+
+As a next step I will blog about the different property types that are supported by CSS in JavaFX.
diff --git a/content/posts/2016-10-28-my-thoughts-about-java-build-tools.md b/content/posts/2016-10-28-my-thoughts-about-java-build-tools.md
index bb263c30..9714db25 100644
--- a/content/posts/2016-10-28-my-thoughts-about-java-build-tools.md
+++ b/content/posts/2016-10-28-my-thoughts-about-java-build-tools.md
@@ -1,168 +1,156 @@
----
-outdated: true
-title: 'Maven vs. Gradle and the Best of Both Worlds'
-date: "2016-10-28"
-author: hendrik
-categories: [Java]
-excerpt: 'See how both Maven and Gradle succeed and fail and consider static modules, an idea that would bring out and combine their best aspects.'
-origin: https://dzone.com/articles/maven-vs-gradle-and-the-best-of-both-worlds
-preview_image: "/posts/preview-images/duke-yellow.svg"
----
-Since several years I’m really frustrated of the build tools that can currently be used to build Java based projects. In my daily job I have seen several Java projects and modules that use different build systems. Thankfully mostly all projects I have seen the last years are build on [Maven](https://maven.apache.org) or [Gradle](https://gradle.org). Based on this you need to know only 2 different systems to understand the basic structure and dependencies of a project. I don’t want to give an overview of all build systems that can currently be used to define the build of a Java based project since I think that they all can easily be splitted in 2 different types:
-
-* Script based build system
-* Configuration based build systems
-
-Currently Maven and Gradle are the best known build systems and each of them is related to one type. Let's have a deeper look at both of them.
-
-## About Gradle
-
-From my point of view Gradle is a script based build system. For such a build system you can define your own tasks based on commands or an API. In Gradle you can [write custom build tasks](https://docs.gradle.org/current/userguide/custom_tasks.html) easily by using [Groovy](http://groovy script). Gradle provides some [basic plugins](https://docs.gradle.org/current/userguide/tutorial_java_projects.html) for a common build workflow of Java projects. Based on this you do not need to define any task like the compilation of the Java sources for each project again and again. But since Gradle is based on tasks that can easily be defined in the build script you do not have any defined structure or best practice how you should structure your build script and how you should define information like the project name or the dependencies of a project. Don’t get me wrong: Gradle provides good APIs for all this but it’s up to the developer where in the build script he for example defines the dependencies of a project. In addition you always need to run the build script to get information about the project.
-
-## About Maven
-
-The functionality of Maven is against a script based build tool very limited. All information about the project and how to build it must be specified in a [pom.xml](http://pom.xml dependency) file. Internally you can configure the project and the build by using XML syntax. All possibilities that you have to configure the project are defined by [Maven in a XSD file](https://maven.apache.org/xsd/maven-4.0.0.xsd). By doing so it’s quite easy to define static metadata of the project like the name or the project description. Even technical information like groupId, artifactId, version or static dependencies can easily be defined. By using Maven as a build tool your project will be build by using [a best practice workflow](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html) to build Java projects that is defined in several tasks. This is fine for small projects and APIs but if you need to do something special you need to add plugins to Maven. Such a plugin must be defined for your project by using the limited XML syntax of Maven. The functionality of such a plugin must be [coded in Java](https://darylmathison.com/2015/04/12/there-is-a-mojo-in-my-dojo-how-to-write-a-maven-plugin/) and provided as a JAR. For large and complex projects you will need several of this projects that will always end in a large and unreadable XML file as description and build definition of your project.
-
-## Conclusion
-
-One point that thankfully both approaches have in common is the way how dependencies will be revolved. Both, Maven and Gradle, will download (transitive) dependencies from any artifact repository. Maven uses [Maven Central](http://search.maven.org) here as default and Gradle uses [JCenter](https://bintray.com/bintray/jcenter). In addition any other repository (like a private company repository) can easily be defined. Since artifact repositories follow some common standards all mentioned repositories can easily be used in Maven or Gradle.
-
-On the other hand both tools / build systems have some big disadvantage from my point of view. Since it's quite easy to define project metadata and dependencies in Maven it's absolutely horrible to create a highly customized build with Maven. If you want to create a asciidoc based documentation or upload the final artifact to a JavaEE server your pom file will fast become unreadable. The [Maven pom of the hazelcast project](https://github.com/hazelcast/hazelcast/blob/master/pom.xml) has for example over 1000 lines. Understanding a 1000 line XML based build definition can be very frustrated for a new developer. So Maven is nice for small modules and APIs like [Apache commons](https://commons.apache.org) or [GSON](https://github.com/google/gson). Developers can get really fast an overview about the project and its dependencies by simply having a look at the pom file. In addition tools do not need to run a build process / script to get information. The pom file can simply be parsed.
-
-Gradle on the other hand provides a lot of flexibility. Since it is based on a script you can do really everything and supporting custom build steps is much easier than in Maven. This is very good if you want to deploy your artifacts to a server or create for example a documentation. But based on the flexibility a build script can become complex, too. In most big Java projects have seen the last years only some developers know how to change something in the gradle build. In addition any tool needs to run a gradle build to get basic information about the project. Since Gradle build scripts are based on a script language it's impossible to parse them. So at the end Gradle is sadly not the perfect solution for building Java projects.
-
-Based on this I would say that currently no Java build tool is the prefect solution for all Java based projects. Maven is to limited but great for small projects that follow the defined Maven lifecycle and definitions. Gradle on the other hand can do everything that you want but even small projects may differ in it’s definition since you can structure / define your build description in any way. In addition you need to run the build to receive information about the project.
-
-Based on this points I think that there is a way how all the benefits can be simply combined. When having a look at [JavaScript](http://www.w3schools.com/js/) and build systems for JavaScript you can see a difference. Modern build systems for JavaScript like [gulp](http://gulpjs.com) work more or less like Gradle. You can easily define your own custom tasks based on a script language. In addition the metadata of the project is often defined in a separate file. Most projects that I have seen the last months use [bower](https://bower.io) to define the static metadata of a project. This include a description of the project (name, description, license, …) and its dependencies. Build tools like gulp can now use the information of bower to build the project (yes, this is a very easy description of the internal process). Based on this I ask myself why Gradle for example can’t do the same. Let’s think about a static definition for Java projects and modules that can easily integrated in a Gradle or Maven build. Since such a definition would be used by both tools it would be much easier for developers to learn how to read and use such a static definition. In addition tools do not need to start any external process like a build script to get information about the Java project. For complete projects you can simply create custom Gradle tasks that internally get get all the information of the static definition and reuse it for the real build.
-
-In the following paragraphs I will try to sketch how such a static definition might look like and how it could be used.
-
-## Defining a static module description
-
-A static module definition should contain a readable description of the module. This should include several parameters like:
-
-* module name
-* module description
-* licence
-* urls (repo, issue tracker, doc, …)
-* developer information (name, mail, …)
-
-Based on this information a module description might look like this:
-
-{{< highlight json >}}
-{
-"name": "My cool API",
-"description": "A very cool API",
-"licence": "Apache 2.0",
-"urls": [{
- "name": "Github repository",
- "url": "www.github.com/cool/api",
- "type": "repo"
- },{
- "name": "Stackoverflow section",
- "url": "www.stackoverflow.com/cool",
- "type": "custom"
- }],
-"developers": [{
- "name": "John Doe",
- "mail": "john.doe@mail.com"
- }]
-}
-{{< / highlight >}}
-
-Next to this information a project needs a unique identifier. Since in Maven and Gradle this can easily be defined by the groupId and artifactId a static definition should reuse this properties:
-
-{{< highlight json >}}
-{
-"groupId": "com.cool.api",
-"artifactId": "cool-api"
-}
-{{< / highlight >}}
-
-To define a specific version of a project the versionId should be added, too. Based on this information everything to provide the module to Maven Central or JCenter is defined. In addition a Maven pom.xml can easily be created based on this information and other modules can depend on this module. After adding the properties a static project definition might look like this:
-
-{{< highlight json >}}
-{
- "name": "My cool API",
- "description": "A very cool API",
- "licence": "Apache 2.0",
- "groupId": "com.cool.api",
- "artifactId": "cool-api",
- "version": "2.1.9"
-}
-{{< / highlight >}}
-
-To compile a java module we need some additional information. I think the most basic informations are the source encoding and the Java version that should be used to compile. Here we need to specify a Java version that defines the minimum version that is needed to compile the sources and a java version that defined the compile target version. Adding this information to a module description might end in the following file:
-
-{{< highlight json >}}
-{
-"name": "My cool API",
-"description": "A very cool API",
-"licence": "Apache 2.0",
-
-"groupId": "com.cool.api",
-"artifactId": "cool-api",
-"version": "2.1.9",
-
-"encoding": "UTF-8",
-"source-java": "8",
-"target-java": "8"
-}
-{{< / highlight >}}
-
-Based on this information a project that needs no additional classes next to the basic Java classes in the class path can easily be compiled. Since the complete module definition is provided in a static way a support for this can easily be integrated in any IDE or build tool.
-
-Since most projects depend on external APIs and modules the static module definition should provide information about the dependencies of the module. Like in Maven or Gradle a definition of the dependencies based on artifactId, groupId and version is the best way to do it. At compilation a build tool or IDE can than easily download the (transitive) dependencies from Maven Central or JCenter. A static project definition should offer mostly all features that are part of the Maven dependency definition but in most use cases simply adding the needed dependencies is all you need. By adding dependency information a module definition will look like this:
-
-{{< highlight json >}}
-{
-"name": "My cool API",
-"description": "A very cool API",
-"licence": "Apache 2.0",
-
-"groupId": "com.cool.api",
-"artifactId": "cool-api",
-"version": "2.1.9",
-
-"encoding": "UTF-8",
-"source-java": "8",
-"target-java": "8",
-
-"dependencies": [{
- "groupId": "com.cool.spi",
- "artifactId": "cool-spi",
- "version": "1.0.0"
- },{
- "groupId": "com.cool.logging",
- "artifactId": "cool-logging",
- "version": "1.0.0"
- }]
-}
-{{< / highlight >}}
-
-A Java module that is defined by such a static structure must follow some best practices and basic rules that are well known from Maven and Gradle based project:
-
-* All Java sources must be placed under src/main/java
-* All resources like images or configuration files must be placed under src/main/resources
-* All Java sources for unit tests must be placed under src/test/java
-* All resources for unit tests must be placed under src/test/resources
-* The static definition of the project must be defined in a UTF-8 based file in the root folder of the project. The file must be named „metadata.jmm“ (jmm stands for Java module metadata).
-
-## Why should I use such a static description in my Java project?
-
-Most of you will already use a build tool like Maven, Gradle or maybe Ant to define the build of a Java project. I think this is quite fine and should be used in future, too. But especially when using Gradle, which is the newest of the mentioned build tools, developers have so many possibilities to create a custom build file that normally each build works in a different way and it can be hard to understand the build process. In all this files the information about the build process (like a build script) and the metadata of a project are mixed. By encapsulating the metadata from the build it will be much easier to get a general overview of a module or a build. In addition each build file or script depends on the used build system. This means that a developer that always used Maven often can not read or interpret a Gradle build script. By defining the metadata in a tool independent way any developer can understand the information of any Java project as soon as he worked at least with one project that provide static metadata. But the metadata will not only offer a better readability for developers. Build tools could provide support to interpret the metadata. By doing so all information that is part of the metadata file should not be redefined in the build script. The build tool can directly use the information of the metadata file to build the project. By doing so a Gradle file only build a JAR file based on a module that has a static metadata description can look like this:
-
-{{< highlight java >}}
-apply plugin: 'java'
-apply plugin: 'jmm'
-{{< / highlight >}}
-
-This will be enough to compile all sources of the project, run all unit tests and build a JAR which name is created by the artifactId and version value of the metadata file.
-
-Next to general build tools IDEs can provide support for the static module metadata. In this case you do not even need a build script. Based on the information that can be defined in the metadata an IDE can download all needed dependencies, compile the sources of the project and run all the unit tests. And this is only the beginning. Based on this approach it would be possible to scan all java projects at GitHub, GitLab and BitBucket and find the usage of a module. Providing a graphical overview of the transitive dependencies of a module will be easy, too. Instead of running a Gradle build to receive information of the dependencies any tool can simply parse the static metadata. Not even any build tool must be installed to do so. Next to build tools and IDEs several other tools like build servers will benefit by this approach.
-
-Once the most important tools will offer support for static metadata the maintenance of mostly all Java projects will be much easier. Thinks like the version will be defined at only one central point and changing the version for a release will be really easy.
-
-## Limitations of the approach
-
-To be true static metadata will not work perfect for any project. Some projects need to generate sources at runtime or have dynamic dependencies. For such projects the static metadata might not be enough to compile the project. But even here such a metadata definition is not useless. Readable metadata like the name or the license can be specified and all non-dynamic dependencies can be part of the metadata file, too. This will end in a less code that is needed for the build file and tools that interpret the static metadata can at least work with a subset of the project description. And yes, this approach is currently not useable for projects that are based on another programming language like Kotlin or Groovy. But as said: this is just an initial idea and I would like to get your thoughts about this topic ;)
+---
+outdated: true
+title: 'Maven vs. Gradle and the Best of Both Worlds'
+date: "2016-10-28"
+author: hendrik
+categories: [Java]
+excerpt: 'See how both Maven and Gradle succeed and fail and consider static modules, an idea that would bring out and combine their best aspects.'
+origin: https://dzone.com/articles/maven-vs-gradle-and-the-best-of-both-worlds
+preview_image: "/posts/preview-images/duke-yellow.svg"
+---
+Since several years I’m really frustrated of the build tools that can currently be used to build Java based projects. In my daily job I have seen several Java projects and modules that use different build systems. Thankfully mostly all projects I have seen the last years are build on [Maven](https://maven.apache.org) or [Gradle](https://gradle.org). Based on this you need to know only 2 different systems to understand the basic structure and dependencies of a project. I don’t want to give an overview of all build systems that can currently be used to define the build of a Java based project since I think that they all can easily be splitted in 2 different types:
+
+* Script based build system
+* Configuration based build systems
+
+Currently Maven and Gradle are the best known build systems and each of them is related to one type. Let's have a deeper look at both of them.
+
+## About Gradle
+
+From my point of view Gradle is a script based build system. For such a build system you can define your own tasks based on commands or an API. In Gradle you can [write custom build tasks](https://docs.gradle.org/current/userguide/custom_tasks.html) easily by using [Groovy](http://groovy script). Gradle provides some [basic plugins](https://docs.gradle.org/current/userguide/tutorial_java_projects.html) for a common build workflow of Java projects. Based on this you do not need to define any task like the compilation of the Java sources for each project again and again. But since Gradle is based on tasks that can easily be defined in the build script you do not have any defined structure or best practice how you should structure your build script and how you should define information like the project name or the dependencies of a project. Don’t get me wrong: Gradle provides good APIs for all this but it’s up to the developer where in the build script he for example defines the dependencies of a project. In addition you always need to run the build script to get information about the project.
+
+## About Maven
+
+The functionality of Maven is against a script based build tool very limited. All information about the project and how to build it must be specified in a [pom.xml](http://pom.xml dependency) file. Internally you can configure the project and the build by using XML syntax. All possibilities that you have to configure the project are defined by [Maven in a XSD file](https://maven.apache.org/xsd/maven-4.0.0.xsd). By doing so it’s quite easy to define static metadata of the project like the name or the project description. Even technical information like groupId, artifactId, version or static dependencies can easily be defined. By using Maven as a build tool your project will be build by using [a best practice workflow](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html) to build Java projects that is defined in several tasks. This is fine for small projects and APIs but if you need to do something special you need to add plugins to Maven. Such a plugin must be defined for your project by using the limited XML syntax of Maven. The functionality of such a plugin must be [coded in Java](https://darylmathison.com/2015/04/12/there-is-a-mojo-in-my-dojo-how-to-write-a-maven-plugin/) and provided as a JAR. For large and complex projects you will need several of this projects that will always end in a large and unreadable XML file as description and build definition of your project.
+
+## Conclusion
+
+One point that thankfully both approaches have in common is the way how dependencies will be revolved. Both, Maven and Gradle, will download (transitive) dependencies from any artifact repository. Maven uses [Maven Central](http://search.maven.org) here as default and Gradle uses [JCenter](https://bintray.com/bintray/jcenter). In addition any other repository (like a private company repository) can easily be defined. Since artifact repositories follow some common standards all mentioned repositories can easily be used in Maven or Gradle.
+
+On the other hand both tools / build systems have some big disadvantage from my point of view. Since it's quite easy to define project metadata and dependencies in Maven it's absolutely horrible to create a highly customized build with Maven. If you want to create a asciidoc based documentation or upload the final artifact to a JavaEE server your pom file will fast become unreadable. The [Maven pom of the hazelcast project](https://github.com/hazelcast/hazelcast/blob/master/pom.xml) has for example over 1000 lines. Understanding a 1000 line XML based build definition can be very frustrated for a new developer. So Maven is nice for small modules and APIs like [Apache commons](https://commons.apache.org) or [GSON](https://github.com/google/gson). Developers can get really fast an overview about the project and its dependencies by simply having a look at the pom file. In addition tools do not need to run a build process / script to get information. The pom file can simply be parsed.
+
+Gradle on the other hand provides a lot of flexibility. Since it is based on a script you can do really everything and supporting custom build steps is much easier than in Maven. This is very good if you want to deploy your artifacts to a server or create for example a documentation. But based on the flexibility a build script can become complex, too. In most big Java projects have seen the last years only some developers know how to change something in the gradle build. In addition any tool needs to run a gradle build to get basic information about the project. Since Gradle build scripts are based on a script language it's impossible to parse them. So at the end Gradle is sadly not the perfect solution for building Java projects.
+
+Based on this I would say that currently no Java build tool is the prefect solution for all Java based projects. Maven is to limited but great for small projects that follow the defined Maven lifecycle and definitions. Gradle on the other hand can do everything that you want but even small projects may differ in it’s definition since you can structure / define your build description in any way. In addition you need to run the build to receive information about the project.
+
+Based on this points I think that there is a way how all the benefits can be simply combined. When having a look at [JavaScript](http://www.w3schools.com/js/) and build systems for JavaScript you can see a difference. Modern build systems for JavaScript like [gulp](http://gulpjs.com) work more or less like Gradle. You can easily define your own custom tasks based on a script language. In addition the metadata of the project is often defined in a separate file. Most projects that I have seen the last months use [bower](https://bower.io) to define the static metadata of a project. This include a description of the project (name, description, license, …) and its dependencies. Build tools like gulp can now use the information of bower to build the project (yes, this is a very easy description of the internal process). Based on this I ask myself why Gradle for example can’t do the same. Let’s think about a static definition for Java projects and modules that can easily integrated in a Gradle or Maven build. Since such a definition would be used by both tools it would be much easier for developers to learn how to read and use such a static definition. In addition tools do not need to start any external process like a build script to get information about the Java project. For complete projects you can simply create custom Gradle tasks that internally get get all the information of the static definition and reuse it for the real build.
+
+In the following paragraphs I will try to sketch how such a static definition might look like and how it could be used.
+
+## Defining a static module description
+
+A static module definition should contain a readable description of the module. This should include several parameters like:
+
+* module name
+* module description
+* licence
+* urls (repo, issue tracker, doc, …)
+* developer information (name, mail, …)
+
+Based on this information a module description might look like this:
+
+```json{
+"name": "My cool API",
+"description": "A very cool API",
+"licence": "Apache 2.0",
+"urls": [{
+ "name": "Github repository",
+ "url": "www.github.com/cool/api",
+ "type": "repo"
+ },{
+ "name": "Stackoverflow section",
+ "url": "www.stackoverflow.com/cool",
+ "type": "custom"
+ }],
+"developers": [{
+ "name": "John Doe",
+ "mail": "john.doe@mail.com"
+ }]
+}
```
+
+Next to this information a project needs a unique identifier. Since in Maven and Gradle this can easily be defined by the groupId and artifactId a static definition should reuse this properties:
+
+```json{
+"groupId": "com.cool.api",
+"artifactId": "cool-api"
+}
```
+
+To define a specific version of a project the versionId should be added, too. Based on this information everything to provide the module to Maven Central or JCenter is defined. In addition a Maven pom.xml can easily be created based on this information and other modules can depend on this module. After adding the properties a static project definition might look like this:
+
+```json{
+ "name": "My cool API",
+ "description": "A very cool API",
+ "licence": "Apache 2.0",
+ "groupId": "com.cool.api",
+ "artifactId": "cool-api",
+ "version": "2.1.9"
+}
```
+
+To compile a java module we need some additional information. I think the most basic informations are the source encoding and the Java version that should be used to compile. Here we need to specify a Java version that defines the minimum version that is needed to compile the sources and a java version that defined the compile target version. Adding this information to a module description might end in the following file:
+
+```json{
+"name": "My cool API",
+"description": "A very cool API",
+"licence": "Apache 2.0",
+
+"groupId": "com.cool.api",
+"artifactId": "cool-api",
+"version": "2.1.9",
+
+"encoding": "UTF-8",
+"source-java": "8",
+"target-java": "8"
+}
```
+
+Based on this information a project that needs no additional classes next to the basic Java classes in the class path can easily be compiled. Since the complete module definition is provided in a static way a support for this can easily be integrated in any IDE or build tool.
+
+Since most projects depend on external APIs and modules the static module definition should provide information about the dependencies of the module. Like in Maven or Gradle a definition of the dependencies based on artifactId, groupId and version is the best way to do it. At compilation a build tool or IDE can than easily download the (transitive) dependencies from Maven Central or JCenter. A static project definition should offer mostly all features that are part of the Maven dependency definition but in most use cases simply adding the needed dependencies is all you need. By adding dependency information a module definition will look like this:
+
+```json{
+"name": "My cool API",
+"description": "A very cool API",
+"licence": "Apache 2.0",
+
+"groupId": "com.cool.api",
+"artifactId": "cool-api",
+"version": "2.1.9",
+
+"encoding": "UTF-8",
+"source-java": "8",
+"target-java": "8",
+
+"dependencies": [{
+ "groupId": "com.cool.spi",
+ "artifactId": "cool-spi",
+ "version": "1.0.0"
+ },{
+ "groupId": "com.cool.logging",
+ "artifactId": "cool-logging",
+ "version": "1.0.0"
+ }]
+}
```
+
+A Java module that is defined by such a static structure must follow some best practices and basic rules that are well known from Maven and Gradle based project:
+
+* All Java sources must be placed under src/main/java
+* All resources like images or configuration files must be placed under src/main/resources
+* All Java sources for unit tests must be placed under src/test/java
+* All resources for unit tests must be placed under src/test/resources
+* The static definition of the project must be defined in a UTF-8 based file in the root folder of the project. The file must be named „metadata.jmm“ (jmm stands for Java module metadata).
+
+## Why should I use such a static description in my Java project?
+
+Most of you will already use a build tool like Maven, Gradle or maybe Ant to define the build of a Java project. I think this is quite fine and should be used in future, too. But especially when using Gradle, which is the newest of the mentioned build tools, developers have so many possibilities to create a custom build file that normally each build works in a different way and it can be hard to understand the build process. In all this files the information about the build process (like a build script) and the metadata of a project are mixed. By encapsulating the metadata from the build it will be much easier to get a general overview of a module or a build. In addition each build file or script depends on the used build system. This means that a developer that always used Maven often can not read or interpret a Gradle build script. By defining the metadata in a tool independent way any developer can understand the information of any Java project as soon as he worked at least with one project that provide static metadata. But the metadata will not only offer a better readability for developers. Build tools could provide support to interpret the metadata. By doing so all information that is part of the metadata file should not be redefined in the build script. The build tool can directly use the information of the metadata file to build the project. By doing so a Gradle file only build a JAR file based on a module that has a static metadata description can look like this:
+
+```javaapply plugin: 'java'
+apply plugin: 'jmm'
```
+
+This will be enough to compile all sources of the project, run all unit tests and build a JAR which name is created by the artifactId and version value of the metadata file.
+
+Next to general build tools IDEs can provide support for the static module metadata. In this case you do not even need a build script. Based on the information that can be defined in the metadata an IDE can download all needed dependencies, compile the sources of the project and run all the unit tests. And this is only the beginning. Based on this approach it would be possible to scan all java projects at GitHub, GitLab and BitBucket and find the usage of a module. Providing a graphical overview of the transitive dependencies of a module will be easy, too. Instead of running a Gradle build to receive information of the dependencies any tool can simply parse the static metadata. Not even any build tool must be installed to do so. Next to build tools and IDEs several other tools like build servers will benefit by this approach.
+
+Once the most important tools will offer support for static metadata the maintenance of mostly all Java projects will be much easier. Thinks like the version will be defined at only one central point and changing the version for a release will be really easy.
+
+## Limitations of the approach
+
+To be true static metadata will not work perfect for any project. Some projects need to generate sources at runtime or have dynamic dependencies. For such projects the static metadata might not be enough to compile the project. But even here such a metadata definition is not useless. Readable metadata like the name or the license can be specified and all non-dynamic dependencies can be part of the metadata file, too. This will end in a less code that is needed for the build file and tools that interpret the static metadata can at least work with a subset of the project description. And yes, this approach is currently not useable for projects that are based on another programming language like Kotlin or Groovy. But as said: this is just an initial idea and I would like to get your thoughts about this topic ;)
diff --git a/content/posts/2018-09-16-java-11-licence.md b/content/posts/2018-09-16-java-11-licence.md
index e793e4c5..c7b40130 100644
--- a/content/posts/2018-09-16-java-11-licence.md
+++ b/content/posts/2018-09-16-java-11-licence.md
@@ -42,7 +42,7 @@ Based on this information each developer needs to carefully decide which Java bu
## Think out of the box
-For several years other vendors provide free and commercial builds for Java. Most developers may have already seen IBM, Azul, or Red Hat JDK somewhere in the wild. With the new Java release train, most of these companies updated their strategy, licenses, and business model for JDKs and provide several alternatives to Oracle's JDK. In [our article about the price and support models for Java]({{< ref "/posts/2018-06-25-java-releases" >}}), you can find a good overview of the most popular vendors. Based on your development workflow and future plans, one of the Java builds from another vendor might suit you better than the Oracle one. Since all these builds are based on the same sources from OpenJDK and successfully passed the [TCK](https://en.wikipedia.org/wiki/Technology_Compatibility_Kit) you do not need to be afraid to use them. Most likely the number of Java vendors will increase because of the new Java release train. This will help developers and companies to find a release and license model that fits to their internal needs. And once you found "the perfect Java" for your - it's time to think again about creating cool applications, frameworks, and architecture.
+For several years other vendors provide free and commercial builds for Java. Most developers may have already seen IBM, Azul, or Red Hat JDK somewhere in the wild. With the new Java release train, most of these companies updated their strategy, licenses, and business model for JDKs and provide several alternatives to Oracle's JDK. In [our article about the price and support models for Java](/posts/2018-06-25-java-releases), you can find a good overview of the most popular vendors. Based on your development workflow and future plans, one of the Java builds from another vendor might suit you better than the Oracle one. Since all these builds are based on the same sources from OpenJDK and successfully passed the [TCK](https://en.wikipedia.org/wiki/Technology_Compatibility_Kit) you do not need to be afraid to use them. Most likely the number of Java vendors will increase because of the new Java release train. This will help developers and companies to find a release and license model that fits to their internal needs. And once you found "the perfect Java" for your - it's time to think again about creating cool applications, frameworks, and architecture.
Do not stress yourself with the changes in the Java ecosystem. Inform yourself about the alternatives next to Oracle within the next month and be prepared for the bright future of Java. By doing so you can be relaxed ;)
diff --git a/content/posts/2018-09-25-java11-release-event.md b/content/posts/2018-09-25-java11-release-event.md
index 8451165f..349e9665 100644
--- a/content/posts/2018-09-25-java11-release-event.md
+++ b/content/posts/2018-09-25-java11-release-event.md
@@ -14,4 +14,4 @@ preview_image: "/posts/preview-images/software-development-green.svg"
---
Together with Oracle and [Heise](https://www.heise.de/developer/meldung/Jetzt-vormerken-Launch-Event-zu-Java-11-4168709.html), we will do a Java 11 release event on September 25th, 2018. This event will be followed by Hendrik Ebbers and Michael Heinrichs. There will be a YouTube Live Stream from 6 pm UTC+2. We are looking forward to many viewers!
-{{< youtube CUuCVHWeO-Y >}}
+
diff --git a/content/posts/2018-11-23-amazon-corretto.md b/content/posts/2018-11-23-amazon-corretto.md
index 062db8b3..5f3e8f06 100644
--- a/content/posts/2018-11-23-amazon-corretto.md
+++ b/content/posts/2018-11-23-amazon-corretto.md
@@ -1,70 +1,66 @@
----
-outdated: true
-showInBlog: false
-title: 'Amazon Corretto announced'
-date: "2018-11-23"
-author: hendrik
-excerpt: 'At the Devoxx conference 2 weeks ago, Amazon announced Corretto as a new player in the OpenJDK market. Next to companies like SAP, Oracle or Bellsoft, the cloud computing company now provides a custom OpenJDK build. On the website Amazon Corretto is described as
-"No-cost, multiplatform, production-ready distribution of OpenJDK". In this post I will have a deeper look at Corretto and explain why Amazon did this move.'
-categories: [Java, OpenJDK]
-origin: https://dev.karakun.com
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Based on the changes that Oracle announced a year ago about [the new release train and licenses of Java](/java/2018/06/25/java-releases.html) and the Oracle Java distributions it was completely obvious and only a matter of time when additional big players start to distribute custom OpenJDK builds. Some companies like RedHat or IBM did this already for some years to provide custom Java support for existing enterprise customers. The first big player that offered a more general OpenJDK build with custom support was Azul.
-
-With the new license model of Oracle that only provides free updates for java version (even LTS versions) for 6 months, the door was open for new vendors. Especially cloud providers needed to find a solution for the new situation. If you have Java installed on millions of containers that are running in your cloud you do not want to buy commercial support at Oracle for all of them. But you do not want to use outdated Java versions in production either. Especially in a public cloud infrastructure, you need security fixes as fast as possible. Based on this Microsoft already [announced a partnership with Azul](https://azure.microsoft.com/en-us/blog/microsoft-and-azul-systems-bring-free-java-lts-support-to-azure/) a month ago.
-
-Amazon decided to not cooperate with a given JDK vendor and provide its distribution as they have announced at Devoxx 2018. The Java distribution of Amazon is named Corretto. [On the product website](https://aws.amazon.com/de/corretto/), Amazon describes Corretto as a "No-cost, multiplatform, production-ready distribution of OpenJDK". Let's have a deeper look at it.
-
-
-
-## About multiplatform support
-
-Currently, a Java 8 based preview can be downloaded for Linux, Mac, and Windows. Until now, Amazon provides only 64 bit version. Against some other distributions, the download contains an installer (at least for Windows and Mac) that will install the Java distribution on your machine. This is a huge benefit compared to some other vendors that only offer a packed (like tar or zip) folder of the JDK. Plus, Amazon already offers ready to use docker support. If you want to run a java application in a container by using the Corretto JDK you only need to build the open source image:
-
-{{< highlight shell >}}
-docker build -t amazon-corretto-8 github.com/corretto/corretto-8-docker
-{{< / highlight >}}
-
-I am sure that Amazon will offer the images in the official docker hub in the near future.
-
-Once you have installed Corretto it is ready to use. By calling `java -version` the current preview build of Corretto will give you the following version information:
-
-{{< highlight shell >}}
-openjdk version "1.8.0_192"
-OpenJDK Runtime Environment (build 1.8.0_192-amazon-corretto-preview-b12)
-OpenJDK 64-Bit Server VM (build 25.192-b12, mixed mode)
-{{< / highlight >}}
-
-## Is Corretto a no-cost JDK?
-
-For now, you can easily download a Java 11 version everywhere. You can choose between Oracle JDK, Oracle OpenJDK builds, AdoptOpenJDK builds, and many more. While all (except for the Oracle JDK build) can easily be used in production it will become much harder in some months when Java 12 hits the market and the 6 month period of Java 11 ends. Even Java 11 is a so-called LTS release (Long Term Support) companies like Oracle or Azul will only offer updates on Java 11 if you pay commercial support to them. Amazon plans to offer free support and will provide updates for Java 11 with patches (security fixes and bugfixes) for several years. On the FAQ page of Corretto Amazon describes the model like this:
-
-* Corretto is distributed by Amazon under an Open Source license at no cost to you. It is licensed under the terms of the GNU
-* Public License version 2 with the Classpath Exception (GPLv2 with CPE). Amazon does not charge for its use or distribution.
-* Amazon will provide security updates for Corretto 8 until at least June 2023. Updates are planned to be released quarterly.
-* Corretto 11, corresponding to OpenJDK 11, will be available during the first half of 2019. Amazon will support Corretto 11 with quarterly updates until at least August 2024
-
-Based on this you can definitely say that Corretto will be free. To be true Amazon does not provide any commercial support for Corretto.If this is positive or negative depends on your opinion about commercial support. In general, it is positive to have a distributor that offers free LTS support for Java.
-
-## Is Corretto production ready?
-
-Since Corretto is based on the sources of OpenJDK and therefore has mostly no functional change against other distributions, this question can be answered in general with “yes”. If you install the Java 8 preview of Corretto, you normally will have absolutely no problems. From my point of view, a more important question is if Corretto will stay production-ready in the future. By providing long term support for Java versions Amazon needs to merge and implement fixes into the Corretto repositories since the work on the OpenJDK branches for a specific version will stop after 6 months. When having a look at the OpenJDK contributors of the last year you will see that Amazon is already an OpenJDK committer. The following diagram gives an idea about the work that some JDK vendors did the last year on OpenJDK. As you can see Amazon was not that active as the big vendors like SAP or Bellsoft:
-
-
-
-Based on this, only time will tell if Amazon can provide fast bugfixes and updates based on security issues and general bugs. I hope that they will increase the work on OpenJDK in near future and provide a new and good version of Java 11 each quarter.
-
-As already said Corretto is built on the same OpenJDK sources just like all other Java distribution. For sure the sources will change after 6 months once the LTS period begins. At that moment companies will continue to work on Java 11 in a closed branch. I do not like this workflow and plan to write an additional post about that topic soon. Based on this Corretto contains everything that you need to run Java applications. By taking a closer look at Corretto you can find some differences. Since the current download is a preview we will see how this emerges in the future. Currently, I can see some positive and some negative aspects about Corretto:
-
-* Corretto contains JavaFX and can, therefore, be used to easily start a JavaFX based application. Several other vendors do not bundle JavaFX in the JDK artifacts
-* Next to the JavaFX API the Amazon JDK contains the javafxpackager tool. This can be found in the bin folder and allows users to create native applications based on a Java application
-* As all other JDK vendors (besides Oracle) no WebStart functionality can be found in Corretto. An explanation of the WebStart absence in OpenJDK distributions can be found on [Karakun DevHub](https://dev.karakun.com/webstart/)
-
-Based on all this, one can say that Amazon is on a really good way to offer a production-ready OpenJDK distribution.
-
-## Conclusion and additional thoughts
-
-Considering all the given facts, Corretto looks promising. In March 2019, Java 12 will be released and Java 11 will go in LTS mode. So, somewhere in the summer of 2019, we will see if Amazon will release a free update of Corretto that is based on Java 11 containing all needed bugfixes and security fixes. Taking into account the size, power, and knowledge of Amazon, I do not expect any issue here. On the other hand, we will never know when Amazon stops the work and support for specific Java versions. Since Corretto is 100% free no one will have any contract about future support and therefore it will just be in Amazons' hands to support the Java community with future updates.
-
-Since Corretto is completely free I would love to see that Amazon contributes some of the work (like bugfixes or security fixes) back to OpenJDK. This would help all Java users and especially community-based organizations like [AdoptOpenJDK](https://adoptopenjdk.net). With this community, we have a 100% free and open initiative to provide future open Java versions. If big vendors that work on OpenJDK and provide LTS support for Java would contribute their changes to AdoptOpenJDK instead or next to a closed branch, the future of Java as an open source project would even be brighter. But that discussion will contain more than enough content for a future post ;)
+---
+outdated: true
+showInBlog: false
+title: 'Amazon Corretto announced'
+date: "2018-11-23"
+author: hendrik
+excerpt: 'At the Devoxx conference 2 weeks ago, Amazon announced Corretto as a new player in the OpenJDK market. Next to companies like SAP, Oracle or Bellsoft, the cloud computing company now provides a custom OpenJDK build. On the website Amazon Corretto is described as
+"No-cost, multiplatform, production-ready distribution of OpenJDK". In this post I will have a deeper look at Corretto and explain why Amazon did this move.'
+categories: [Java, OpenJDK]
+origin: https://dev.karakun.com
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Based on the changes that Oracle announced a year ago about [the new release train and licenses of Java](/java/2018/06/25/java-releases.html) and the Oracle Java distributions it was completely obvious and only a matter of time when additional big players start to distribute custom OpenJDK builds. Some companies like RedHat or IBM did this already for some years to provide custom Java support for existing enterprise customers. The first big player that offered a more general OpenJDK build with custom support was Azul.
+
+With the new license model of Oracle that only provides free updates for java version (even LTS versions) for 6 months, the door was open for new vendors. Especially cloud providers needed to find a solution for the new situation. If you have Java installed on millions of containers that are running in your cloud you do not want to buy commercial support at Oracle for all of them. But you do not want to use outdated Java versions in production either. Especially in a public cloud infrastructure, you need security fixes as fast as possible. Based on this Microsoft already [announced a partnership with Azul](https://azure.microsoft.com/en-us/blog/microsoft-and-azul-systems-bring-free-java-lts-support-to-azure/) a month ago.
+
+Amazon decided to not cooperate with a given JDK vendor and provide its distribution as they have announced at Devoxx 2018. The Java distribution of Amazon is named Corretto. [On the product website](https://aws.amazon.com/de/corretto/), Amazon describes Corretto as a "No-cost, multiplatform, production-ready distribution of OpenJDK". Let's have a deeper look at it.
+
+
+
+## About multiplatform support
+
+Currently, a Java 8 based preview can be downloaded for Linux, Mac, and Windows. Until now, Amazon provides only 64 bit version. Against some other distributions, the download contains an installer (at least for Windows and Mac) that will install the Java distribution on your machine. This is a huge benefit compared to some other vendors that only offer a packed (like tar or zip) folder of the JDK. Plus, Amazon already offers ready to use docker support. If you want to run a java application in a container by using the Corretto JDK you only need to build the open source image:
+
+```shelldocker build -t amazon-corretto-8 github.com/corretto/corretto-8-docker
```
+
+I am sure that Amazon will offer the images in the official docker hub in the near future.
+
+Once you have installed Corretto it is ready to use. By calling `java -version` the current preview build of Corretto will give you the following version information:
+
+```shellopenjdk version "1.8.0_192"
+OpenJDK Runtime Environment (build 1.8.0_192-amazon-corretto-preview-b12)
+OpenJDK 64-Bit Server VM (build 25.192-b12, mixed mode)
```
+
+## Is Corretto a no-cost JDK?
+
+For now, you can easily download a Java 11 version everywhere. You can choose between Oracle JDK, Oracle OpenJDK builds, AdoptOpenJDK builds, and many more. While all (except for the Oracle JDK build) can easily be used in production it will become much harder in some months when Java 12 hits the market and the 6 month period of Java 11 ends. Even Java 11 is a so-called LTS release (Long Term Support) companies like Oracle or Azul will only offer updates on Java 11 if you pay commercial support to them. Amazon plans to offer free support and will provide updates for Java 11 with patches (security fixes and bugfixes) for several years. On the FAQ page of Corretto Amazon describes the model like this:
+
+* Corretto is distributed by Amazon under an Open Source license at no cost to you. It is licensed under the terms of the GNU
+* Public License version 2 with the Classpath Exception (GPLv2 with CPE). Amazon does not charge for its use or distribution.
+* Amazon will provide security updates for Corretto 8 until at least June 2023. Updates are planned to be released quarterly.
+* Corretto 11, corresponding to OpenJDK 11, will be available during the first half of 2019. Amazon will support Corretto 11 with quarterly updates until at least August 2024
+
+Based on this you can definitely say that Corretto will be free. To be true Amazon does not provide any commercial support for Corretto.If this is positive or negative depends on your opinion about commercial support. In general, it is positive to have a distributor that offers free LTS support for Java.
+
+## Is Corretto production ready?
+
+Since Corretto is based on the sources of OpenJDK and therefore has mostly no functional change against other distributions, this question can be answered in general with “yes”. If you install the Java 8 preview of Corretto, you normally will have absolutely no problems. From my point of view, a more important question is if Corretto will stay production-ready in the future. By providing long term support for Java versions Amazon needs to merge and implement fixes into the Corretto repositories since the work on the OpenJDK branches for a specific version will stop after 6 months. When having a look at the OpenJDK contributors of the last year you will see that Amazon is already an OpenJDK committer. The following diagram gives an idea about the work that some JDK vendors did the last year on OpenJDK. As you can see Amazon was not that active as the big vendors like SAP or Bellsoft:
+
+
+
+Based on this, only time will tell if Amazon can provide fast bugfixes and updates based on security issues and general bugs. I hope that they will increase the work on OpenJDK in near future and provide a new and good version of Java 11 each quarter.
+
+As already said Corretto is built on the same OpenJDK sources just like all other Java distribution. For sure the sources will change after 6 months once the LTS period begins. At that moment companies will continue to work on Java 11 in a closed branch. I do not like this workflow and plan to write an additional post about that topic soon. Based on this Corretto contains everything that you need to run Java applications. By taking a closer look at Corretto you can find some differences. Since the current download is a preview we will see how this emerges in the future. Currently, I can see some positive and some negative aspects about Corretto:
+
+* Corretto contains JavaFX and can, therefore, be used to easily start a JavaFX based application. Several other vendors do not bundle JavaFX in the JDK artifacts
+* Next to the JavaFX API the Amazon JDK contains the javafxpackager tool. This can be found in the bin folder and allows users to create native applications based on a Java application
+* As all other JDK vendors (besides Oracle) no WebStart functionality can be found in Corretto. An explanation of the WebStart absence in OpenJDK distributions can be found on [Karakun DevHub](https://dev.karakun.com/webstart/)
+
+Based on all this, one can say that Amazon is on a really good way to offer a production-ready OpenJDK distribution.
+
+## Conclusion and additional thoughts
+
+Considering all the given facts, Corretto looks promising. In March 2019, Java 12 will be released and Java 11 will go in LTS mode. So, somewhere in the summer of 2019, we will see if Amazon will release a free update of Corretto that is based on Java 11 containing all needed bugfixes and security fixes. Taking into account the size, power, and knowledge of Amazon, I do not expect any issue here. On the other hand, we will never know when Amazon stops the work and support for specific Java versions. Since Corretto is 100% free no one will have any contract about future support and therefore it will just be in Amazons' hands to support the Java community with future updates.
+
+Since Corretto is completely free I would love to see that Amazon contributes some of the work (like bugfixes or security fixes) back to OpenJDK. This would help all Java users and especially community-based organizations like [AdoptOpenJDK](https://adoptopenjdk.net). With this community, we have a 100% free and open initiative to provide future open Java versions. If big vendors that work on OpenJDK and provide LTS support for Java would contribute their changes to AdoptOpenJDK instead or next to a closed branch, the future of Java as an open source project would even be brighter. But that discussion will contain more than enough content for a future post ;)
diff --git a/content/posts/2019-01-09-integration-docker.md b/content/posts/2019-01-09-integration-docker.md
index ce1c06c1..f2df5d93 100644
--- a/content/posts/2019-01-09-integration-docker.md
+++ b/content/posts/2019-01-09-integration-docker.md
@@ -1,294 +1,274 @@
----
-outdated: true
-showInBlog: false
-title: 'Integration tests with Docker'
-date: "2019-01-09"
-author: hendrik
-origin: "https://dev.karakun.com"
-excerpt: 'This post gives an overview how we at Karakun use Docker to create integration tests for
-JavaEE / JakartaEE based libraries and frameworks.'
-categories: [ Java, Docker, Integration Tests, Tests, JavaEE, JakartaEE ]
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-
-When writing software that is based on [JavaEE / JakartaEE](https://jakarta.ee) you have one big benefit: All APIs are
-specified and therefore your software will run on any application server 🙂
-
-Unfortunately, real life is different. While the introduction is true for most of all use cases, there are still some
-pitfalls. Since all application servers like [TomEE](http://tomee.apache.org), [Wildfly](http://www.wildfly.org),
-or [Payara](https://www.payara.fish) are developed by humans, they all have bugs. But I do not want to say that they are
-not usable. To be true the big players are stable and flexible. But sometimes you will find some behavior that is
-different in one application compared to others. If you write an application that is not that important you will
-normally run it only on a single application server. It won't make sense to test your application on Wildfly and use
-TomEE in production. But if you want to develop a library or a framework that depends on the JavaEE specification and it
-should be usable with any application server it makes sense to test your code as often as you can. This post will give
-you an overview of how you can achieve this goal by using [Docker](https://www.docker.com).
-
-## How to write tests for an enterprise library
-
-Let's assume you develop a library that adds [Server Timing](https://www.w3.org/TR/server-timing/) information to HTTP
-responses. Server Timing is a new W3C feature that allows you to add some metrics about the request handling to the
-response. The following image shows how such information would be rendered in the developer console of Chrome:
-
-
-
-When developing such a feature for JavaEE an implementation of the `javax.servlet.Filter` interface is a good choice. In
-our library we could provide the following class:
-
-{{< highlight java >}}
-package com.karakun.enterprise;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-public class ServerTimingFilter implements Filter {
-
- @Override
- public void init(final FilterConfig filterConfig) {}
-
- @Override
- public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) {
- chain.doFilter(request, response);
- ServerTiming.writeTiming(response);
- }
-
- @Override
- public void destroy() {}
-
-}
-{{< / highlight >}}
-
-As you see, we call the static `ServerTiming.writeTiming()` method in our filter. This methods adds some headers to the
-HTTP response which is represented by the `ServletResponse` instance that is passed to the method. Even if this method
-is using APIs from the JavaEE specifications (the `ServletResponse` interface that is part of the servlet specification)
-we can easily provide some unit tests to check the functionality of the method. A test method could look like this:
-
-{{< highlight java >}}
-@Test
-public void testServerTiming() {
-final ServletResponse response = new ResponseMock();
-ServerTiming.addTiming("Call DB", 3450);
-ServerTiming.writeTiming(response);
-assertTrue(response.containsTiming("Call DB", 3450));
-}
-{{< / highlight >}}
-
-Thus, we can easily test that all information is added to the response and our Server Timing implementation is working.
-If you want to see how the Server Timing feature can be implemented in detail you can find an implementation
-as [part of our open source product Rico](https://github.com/rico-projects/rico/blob/1.0.0-CR2/base/rico-server/src/main/java/dev/rico/internal/server/timing/ServerTimingImpl.java).
-
-One thing that we cannot test is the usage of the `javax.servlet.Filter`. Such a filter can be added to a servlet
-context and then mutate every response for a defined endpoint. If you want to add the filtering to all requests that a
-server application receives you can add the `javax.servlet.annotation.WebFilter` annotation to your class or do the
-registration in code like it is shown in the following snippet:
-
-{{< highlight java >}}
-final Filter filter = new ServerTimingFilter(true);
-final FilterRegistration.Dynamic createdFilter = servletContext.addFilter("ServerTiming", filter);
-createdFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
-{{< / highlight >}}
-
-To check that the code snippet is working and your custom filter will be called for every request you need to test your
-library with an application server.
-
-
-
-Since your library will be used in several applications soon it is important to test it with all application servers (
-and releases) that are used by your customers.
-
-The given example will easily work on every application server since it only uses some common and well-tested features
-of the servlet API. Since the main focus of this article should be the workflow to provide integration tests, the
-example is kept as simple as possible.
-
-Let’s assume you need to check that your library is running fine on TomEE and Payara. You can easily install local
-instances of the application servers on your machine, deploy a test application that internally uses your library, and
-open some endpoints in your browser. You can then check if you see the Server Timing information in the developer view
-of your browser.
-
-While the described workflow is fine for a first test you do not want to do this after every change in the source code
-of the library. After the first 3 tests, you probably know that you need to automate the workflow in some way. Plus,
-your team members maybe do not know how you do the tests and push code changes without checking the functionality on
-TomEE.
-
-## Integration tests with Docker
-
-Since we want to test the integration of our library in specific application servers, integration tests are the solution
-to our problem. To test this automatically after every code change or with every build we need to automate the following
-steps:
-
-* Build the library
-* Build a sample application that uses the library
-* Install a Payara
-* Install a TomEE
-* Configure Payara and TomEE to use different ports on the local machine
-* Deploy the sample app in Payara and TomEE
-* Trigger some Endpoints
-* Check the response
-
-Let's start with the most simple part which can be done 100% in Java: Writing a test that triggers endpoints and checks
-the response. TestNG's data provider functionality can be used to write a test which calls multiple server instances. We
-can provide a list of configurations for our tests. The following snippet contains a method that is annotated with
-the `org.testng.annotations.DataProvider` annotation and provides the configurations for our tests:
-
-{{< highlight java >}}
-@DataProvider(name = "endpoints")
-public Object[][] getEndpoints() {
-return new Object[][]{
-new Object[]{"TomEE", "8080"},
-new Object[]{"Payara", "8081"}
-};
-}
-{{< / highlight >}}
-
-The method provides the configuration for 2 endpoints (TomEE on port 8080 and Payara on port 8081).
-
-This configurations can now be used in a test method:
-
-{{< highlight java >}}
-@Test(dataProvider = "endpoints")
-public void testEndpoints(String containerType, String port) {
-print("Testing " + containerType);
-final String url = "http://localhost:" + port + "/test";
-final Map timings = callEndpoint(url);
-assertContains(timings, "Call DB", 3450);
-}
-{{< / highlight >}}
-
-By executing the test, TestNG will automatically call it once for every given configuration. At the moment the tests
-will fail since we do not have any applications running or maybe an application is not even deployed.
-
-To automatically bootstrap an application server with our test application we will use Docker. I will not describe the
-functionality of Docker since this would be beyond the scope of this article.
-
-Adam Bien provides some good Docker containers for JavaEE application servers that can be used as a base for our
-containers. You can find all the needed Docker files [at Github](https://github.com/AdamBien/docklands). For our sample,
-we will use these container descriptions as a base and extend them with the needed functionality. For TomEE, our Docker
-file will look like this:
-
-{{< highlight docker >}}
-FROM airhacks/tomee:7.0.4-plus
-MAINTAINER Hendrik Ebbers, karakun.com
-COPY sample.war ${DEPLOYMENT_DIR}
-{{< / highlight >}}
-
-The `DEPLOYMENT_DIR` variable is already defined in the Docker file from Adam and we can easily use it to add our
-application (the `sample.war`) to the TomEE instance that is running in the Docker container. The only important point
-is that the war is in the same folder as the Docker file when you build the image file. When starting the container by
-hand you can easily map the internal port of the application server (8080) to any free port of your local system by
-adding a port mapping:
-
-{{< highlight shell >}}
-docker run -p 8080:8080
-{{< / highlight >}}
-
-After starting the containers in Docker we need to wait until the containers are started and the internal application is
-deployed. To do so we can write a small Java method that for example checks if a health-endpoint of the app can be
-reached.
-
-
-
-Since we want to access the Docker containers for each test run they must be started automatically before the tests and
-shut down after the tests. In TestNG, we can use the `@BeforeClass` and `@AfterClass` (or `@BeforeGroup`
-and `@AfterGroup`) annotations to execute good before running the tests after and all tests are executed. Since we can
-start a native process in Java the following code gives an idea of how a first implementation to run our integration
-tests might look like:
-
-{{< highlight java >}}
-public class DockerBasedTest() {
-
- @BeforeClass
- public void init() {
- Runtime.getRuntime().exec("cd docker/tomee && docker run -p 8080:8080 -n TomEE");
- Runtime.getRuntime().exec("cd docker/tomee && docker run -p 8080:8081 -n Payara");
- Helper.WaitTillPortsAvailable(8080, 8081);
- }
-
- @DataProvider(name = "endpoints")
- public Object[][] getEndpoints() {
- return new Object[][]{
- new Object[]{"TomEE", "8080"},
- new Object[]{"Payara", "8081"}
- };
- }
-
- @Test(dataProvider = "endpoints")
- public void testEndpoints(String containerType, String port) {
- print("Testing " + containerType);
- final String url = "http://localhost:" + port + "/test";
- final Map timings = callEndpoint(url);
- assertContains(timings, "Call DB", 3450);
- }
-
- @AfterClass
- public void destroy() {
- Runtime.getRuntime().exec("docker stop TomEE");
- Runtime.getRuntime().exec("docker stop Payara");
- }
-
-}
-{{< / highlight >}}
-
-With this class, we already defined a full workflow to test the internals of the sample app on several application
-servers. The following diagram gives an overview of the implemented steps:
-
-
-
-By starting any test of the given test class the needed Docker containers will automatically be created and destroyed
-after the test was executed. To be true, you do not want to write the Docker commands in every test class. Here you can
-create your custom abstraction or use a library that provides such functionality.
-
-## The future is testcontainers.org
-
-From my point of view, [testcontainers](https://www.testcontainers.org) is a very good library to implement such
-workflows today. The library contains APIs to create unit tests that need Docker containers at runtime. At the moment
-the library is limited to JUnit support and therefore TestNG is not supported.
-
-The testcontainers library uses the rule support of JUnit to define Docker containers that should be automatically be
-created for unit tests. The library provides a pretty good API that lets you easily define containers. The following
-example shows how a container with a [Redis](https://redis.io) instance can be defined for unit tests:
-
-{{< highlight java >}}
-@ClassRule
-public static GenericContainer redis =
-new GenericContainer("redis:3.0.2")
-.withExposedPorts(6379);
-{{< / highlight >}}
-
-Additionally, testcontainers provides support for Docker Compose. With this, you can easily create a container landscape
-for tests. All containers that are needed for your tests can be defined in a yml file that Docker Compose will use to
-start several Docker containers. The following snippet shows how Docker Compose can be used with testcontainers:
-
-{{< highlight java >}}
-@ClassRule
-public static DockerComposeContainer environment =
-new DockerComposeContainer(new File("src/test/resources/compose-test.yml"));
-{{< / highlight >}}
-
-From my point of view, the biggest limitation of testcontainer is that you can only use it with JUnit at the moment. If
-your tests are based on TestNG for example you cannot easily integrate it into your project. In this case, you need to
-create a minimal API to bootsrap Docker containers as described before. We already talked with the maintainers of
-testcontainers and the project is aware of this issue and will work on it in the future. If you want to see a more
-concrete example that uses Docker for integration and unit tests in TestNG you can have a look at
-the [integration tests of Rico](https://github.com/rico-projects/rico/tree/1.0.0-CR2/integration-tests/integration-tests/src/test/java/dev/rico/integrationtests).
-We use Docker to test our server and client API with 3 different application server types automatically.
-
-## Conclusion
-
-To be true there are still some pitfalls if you want to integrate Docker-based containers in your test suite and run
-unit and integration tests against services that are provided by Docker containers. If you use JUnit in your tests you
-should have a deeper look at [testcontainers](https://www.testcontainers.org) and contribute to this project if some
-points are missing for your use cases. But even if you use a different test framework the hints and descriptions in this
-article should help you to create your custom API to boot Docker containers for unit tests.
-
-Once you have the first tests running the integration to other tests and the definition of new tests is quite easy.
-Plus, most CI pipelines already offer Docker support. Maybe you need to install Docker and Docker Compose on your build
-nodes but that should not be a real problem.
-
-As already said we use this approach for [Rico](https://github.com/rico-projects/rico) and are happy with the outcome.
-New tests that need external services can be created easily and we can test our complete API automatically in different
-environments. Since tools like [Travis CI](https://travis-ci.org) already offer support for Docker we can even run all
-the integration tests of our open source platform without any cost in the cloud.
+---
+outdated: true
+showInBlog: false
+title: 'Integration tests with Docker'
+date: "2019-01-09"
+author: hendrik
+origin: "https://dev.karakun.com"
+excerpt: 'This post gives an overview how we at Karakun use Docker to create integration tests for
+JavaEE / JakartaEE based libraries and frameworks.'
+categories: [ Java, Docker, Integration Tests, Tests, JavaEE, JakartaEE ]
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+
+When writing software that is based on [JavaEE / JakartaEE](https://jakarta.ee) you have one big benefit: All APIs are
+specified and therefore your software will run on any application server 🙂
+
+Unfortunately, real life is different. While the introduction is true for most of all use cases, there are still some
+pitfalls. Since all application servers like [TomEE](http://tomee.apache.org), [Wildfly](http://www.wildfly.org),
+or [Payara](https://www.payara.fish) are developed by humans, they all have bugs. But I do not want to say that they are
+not usable. To be true the big players are stable and flexible. But sometimes you will find some behavior that is
+different in one application compared to others. If you write an application that is not that important you will
+normally run it only on a single application server. It won't make sense to test your application on Wildfly and use
+TomEE in production. But if you want to develop a library or a framework that depends on the JavaEE specification and it
+should be usable with any application server it makes sense to test your code as often as you can. This post will give
+you an overview of how you can achieve this goal by using [Docker](https://www.docker.com).
+
+## How to write tests for an enterprise library
+
+Let's assume you develop a library that adds [Server Timing](https://www.w3.org/TR/server-timing/) information to HTTP
+responses. Server Timing is a new W3C feature that allows you to add some metrics about the request handling to the
+response. The following image shows how such information would be rendered in the developer console of Chrome:
+
+
+
+When developing such a feature for JavaEE an implementation of the `javax.servlet.Filter` interface is a good choice. In
+our library we could provide the following class:
+
+```javapackage com.karakun.enterprise;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+public class ServerTimingFilter implements Filter {
+
+ @Override
+ public void init(final FilterConfig filterConfig) {}
+
+ @Override
+ public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) {
+ chain.doFilter(request, response);
+ ServerTiming.writeTiming(response);
+ }
+
+ @Override
+ public void destroy() {}
+
+}
```
+
+As you see, we call the static `ServerTiming.writeTiming()` method in our filter. This methods adds some headers to the
+HTTP response which is represented by the `ServletResponse` instance that is passed to the method. Even if this method
+is using APIs from the JavaEE specifications (the `ServletResponse` interface that is part of the servlet specification)
+we can easily provide some unit tests to check the functionality of the method. A test method could look like this:
+
+```java@Test
+public void testServerTiming() {
+final ServletResponse response = new ResponseMock();
+ServerTiming.addTiming("Call DB", 3450);
+ServerTiming.writeTiming(response);
+assertTrue(response.containsTiming("Call DB", 3450));
+}
```
+
+Thus, we can easily test that all information is added to the response and our Server Timing implementation is working.
+If you want to see how the Server Timing feature can be implemented in detail you can find an implementation
+as [part of our open source product Rico](https://github.com/rico-projects/rico/blob/1.0.0-CR2/base/rico-server/src/main/java/dev/rico/internal/server/timing/ServerTimingImpl.java).
+
+One thing that we cannot test is the usage of the `javax.servlet.Filter`. Such a filter can be added to a servlet
+context and then mutate every response for a defined endpoint. If you want to add the filtering to all requests that a
+server application receives you can add the `javax.servlet.annotation.WebFilter` annotation to your class or do the
+registration in code like it is shown in the following snippet:
+
+```javafinal Filter filter = new ServerTimingFilter(true);
+final FilterRegistration.Dynamic createdFilter = servletContext.addFilter("ServerTiming", filter);
+createdFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
```
+
+To check that the code snippet is working and your custom filter will be called for every request you need to test your
+library with an application server.
+
+
+
+Since your library will be used in several applications soon it is important to test it with all application servers (
+and releases) that are used by your customers.
+
+The given example will easily work on every application server since it only uses some common and well-tested features
+of the servlet API. Since the main focus of this article should be the workflow to provide integration tests, the
+example is kept as simple as possible.
+
+Let’s assume you need to check that your library is running fine on TomEE and Payara. You can easily install local
+instances of the application servers on your machine, deploy a test application that internally uses your library, and
+open some endpoints in your browser. You can then check if you see the Server Timing information in the developer view
+of your browser.
+
+While the described workflow is fine for a first test you do not want to do this after every change in the source code
+of the library. After the first 3 tests, you probably know that you need to automate the workflow in some way. Plus,
+your team members maybe do not know how you do the tests and push code changes without checking the functionality on
+TomEE.
+
+## Integration tests with Docker
+
+Since we want to test the integration of our library in specific application servers, integration tests are the solution
+to our problem. To test this automatically after every code change or with every build we need to automate the following
+steps:
+
+* Build the library
+* Build a sample application that uses the library
+* Install a Payara
+* Install a TomEE
+* Configure Payara and TomEE to use different ports on the local machine
+* Deploy the sample app in Payara and TomEE
+* Trigger some Endpoints
+* Check the response
+
+Let's start with the most simple part which can be done 100% in Java: Writing a test that triggers endpoints and checks
+the response. TestNG's data provider functionality can be used to write a test which calls multiple server instances. We
+can provide a list of configurations for our tests. The following snippet contains a method that is annotated with
+the `org.testng.annotations.DataProvider` annotation and provides the configurations for our tests:
+
+```java@DataProvider(name = "endpoints")
+public Object[][] getEndpoints() {
+return new Object[][]{
+new Object[]{"TomEE", "8080"},
+new Object[]{"Payara", "8081"}
+};
+}
```
+
+The method provides the configuration for 2 endpoints (TomEE on port 8080 and Payara on port 8081).
+
+This configurations can now be used in a test method:
+
+```java@Test(dataProvider = "endpoints")
+public void testEndpoints(String containerType, String port) {
+print("Testing " + containerType);
+final String url = "http://localhost:" + port + "/test";
+final Map timings = callEndpoint(url);
+assertContains(timings, "Call DB", 3450);
+}
```
+
+By executing the test, TestNG will automatically call it once for every given configuration. At the moment the tests
+will fail since we do not have any applications running or maybe an application is not even deployed.
+
+To automatically bootstrap an application server with our test application we will use Docker. I will not describe the
+functionality of Docker since this would be beyond the scope of this article.
+
+Adam Bien provides some good Docker containers for JavaEE application servers that can be used as a base for our
+containers. You can find all the needed Docker files [at Github](https://github.com/AdamBien/docklands). For our sample,
+we will use these container descriptions as a base and extend them with the needed functionality. For TomEE, our Docker
+file will look like this:
+
+```dockerFROM airhacks/tomee:7.0.4-plus
+MAINTAINER Hendrik Ebbers, karakun.com
+COPY sample.war ${DEPLOYMENT_DIR}
```
+
+The `DEPLOYMENT_DIR` variable is already defined in the Docker file from Adam and we can easily use it to add our
+application (the `sample.war`) to the TomEE instance that is running in the Docker container. The only important point
+is that the war is in the same folder as the Docker file when you build the image file. When starting the container by
+hand you can easily map the internal port of the application server (8080) to any free port of your local system by
+adding a port mapping:
+
+```shelldocker run -p 8080:8080
```
+
+After starting the containers in Docker we need to wait until the containers are started and the internal application is
+deployed. To do so we can write a small Java method that for example checks if a health-endpoint of the app can be
+reached.
+
+
+
+Since we want to access the Docker containers for each test run they must be started automatically before the tests and
+shut down after the tests. In TestNG, we can use the `@BeforeClass` and `@AfterClass` (or `@BeforeGroup`
+and `@AfterGroup`) annotations to execute good before running the tests after and all tests are executed. Since we can
+start a native process in Java the following code gives an idea of how a first implementation to run our integration
+tests might look like:
+
+```javapublic class DockerBasedTest() {
+
+ @BeforeClass
+ public void init() {
+ Runtime.getRuntime().exec("cd docker/tomee && docker run -p 8080:8080 -n TomEE");
+ Runtime.getRuntime().exec("cd docker/tomee && docker run -p 8080:8081 -n Payara");
+ Helper.WaitTillPortsAvailable(8080, 8081);
+ }
+
+ @DataProvider(name = "endpoints")
+ public Object[][] getEndpoints() {
+ return new Object[][]{
+ new Object[]{"TomEE", "8080"},
+ new Object[]{"Payara", "8081"}
+ };
+ }
+
+ @Test(dataProvider = "endpoints")
+ public void testEndpoints(String containerType, String port) {
+ print("Testing " + containerType);
+ final String url = "http://localhost:" + port + "/test";
+ final Map timings = callEndpoint(url);
+ assertContains(timings, "Call DB", 3450);
+ }
+
+ @AfterClass
+ public void destroy() {
+ Runtime.getRuntime().exec("docker stop TomEE");
+ Runtime.getRuntime().exec("docker stop Payara");
+ }
+
+}
```
+
+With this class, we already defined a full workflow to test the internals of the sample app on several application
+servers. The following diagram gives an overview of the implemented steps:
+
+
+
+By starting any test of the given test class the needed Docker containers will automatically be created and destroyed
+after the test was executed. To be true, you do not want to write the Docker commands in every test class. Here you can
+create your custom abstraction or use a library that provides such functionality.
+
+## The future is testcontainers.org
+
+From my point of view, [testcontainers](https://www.testcontainers.org) is a very good library to implement such
+workflows today. The library contains APIs to create unit tests that need Docker containers at runtime. At the moment
+the library is limited to JUnit support and therefore TestNG is not supported.
+
+The testcontainers library uses the rule support of JUnit to define Docker containers that should be automatically be
+created for unit tests. The library provides a pretty good API that lets you easily define containers. The following
+example shows how a container with a [Redis](https://redis.io) instance can be defined for unit tests:
+
+```java@ClassRule
+public static GenericContainer redis =
+new GenericContainer("redis:3.0.2")
+.withExposedPorts(6379);
```
+
+Additionally, testcontainers provides support for Docker Compose. With this, you can easily create a container landscape
+for tests. All containers that are needed for your tests can be defined in a yml file that Docker Compose will use to
+start several Docker containers. The following snippet shows how Docker Compose can be used with testcontainers:
+
+```java@ClassRule
+public static DockerComposeContainer environment =
+new DockerComposeContainer(new File("src/test/resources/compose-test.yml"));
```
+
+From my point of view, the biggest limitation of testcontainer is that you can only use it with JUnit at the moment. If
+your tests are based on TestNG for example you cannot easily integrate it into your project. In this case, you need to
+create a minimal API to bootsrap Docker containers as described before. We already talked with the maintainers of
+testcontainers and the project is aware of this issue and will work on it in the future. If you want to see a more
+concrete example that uses Docker for integration and unit tests in TestNG you can have a look at
+the [integration tests of Rico](https://github.com/rico-projects/rico/tree/1.0.0-CR2/integration-tests/integration-tests/src/test/java/dev/rico/integrationtests).
+We use Docker to test our server and client API with 3 different application server types automatically.
+
+## Conclusion
+
+To be true there are still some pitfalls if you want to integrate Docker-based containers in your test suite and run
+unit and integration tests against services that are provided by Docker containers. If you use JUnit in your tests you
+should have a deeper look at [testcontainers](https://www.testcontainers.org) and contribute to this project if some
+points are missing for your use cases. But even if you use a different test framework the hints and descriptions in this
+article should help you to create your custom API to boot Docker containers for unit tests.
+
+Once you have the first tests running the integration to other tests and the definition of new tests is quite easy.
+Plus, most CI pipelines already offer Docker support. Maybe you need to install Docker and Docker Compose on your build
+nodes but that should not be a real problem.
+
+As already said we use this approach for [Rico](https://github.com/rico-projects/rico) and are happy with the outcome.
+New tests that need external services can be created easily and we can test our complete API automatically in different
+environments. Since tools like [Travis CI](https://travis-ci.org) already offer support for Docker we can even run all
+the integration tests of our open source platform without any cost in the cloud.
diff --git a/content/posts/2019-01-15-rico-server-timing.md b/content/posts/2019-01-15-rico-server-timing.md
index e84f810d..9aea7195 100644
--- a/content/posts/2019-01-15-rico-server-timing.md
+++ b/content/posts/2019-01-15-rico-server-timing.md
@@ -1,105 +1,97 @@
----
-outdated: true
-showInBlog: false
-title: 'Server Timing with Rico'
-date: "2019-01-15"
-author: hendrik
-excerpt: 'This post gives an overview about the new server timing specification of the w3c and how server timing can be used in any enterprise Java server by using Rico.'
-categories: [Java, Rico]
-origin: https://dev.karakun.com
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In our open source project [Rico](https://github.com/rico-projects/rico) we introduced the support of "server timing" for JavaEE and Spring. Server Timing is [a new W3C feature](https://www.w3.org/TR/server-timing/) that allows you to add some metrics about the request handling to the response. I already introduced server timing in [one of my last posts]({% post_url 2019-01-09-integration-docker %}). The following image shows how such information would be rendered in the developer console of chrome:
-
-
-
-The feature is very useful when you develop a client that uses HTTP calls to communicate with the server. In this case, the client sends an HTTP request to the server and receives an HTTP response after some time. The functionality that the server executes to create the response based on the request is a black box for the client. Normally this is not really a problem but let's think about a possible bottleneck on the server. Sometimes your HTTP call takes much longer than normal. To make it worse the problem only happens when you do not debug the server. In such case "server timing" is a really helpful feature since you can display some timing information about the server functionality in the client.
-
-## Using Server Timing with Rico
-
-Rico provides a managed component that can easily be injected in any Spring or JavaEE bean. This component is defined by the `dev.rico.server.timing.ServerTiming` interface and lives in the request scope. By injection the component you can easily create metrics in your server that will automatically be added to the HTTP response. Here the w3c specification for server timing is used. Such `dev.rico.server.timing.ServerTiming` instance can be used to create metrics. A metric is defined by the `dev.rico.server.timing.Metric` interface and can be used to automatically add timing information to an HTTP response. The following code snippet shows the basic usage of the API:
-
-{{< highlight java >}}
-final ServerTiming timing = ... // will be injected
-
-final Metric dbMetric = timing.start("DB-Operation");
-//Do some work on the database
-dbMetric.stop();
-{{< / highlight >}}
-
-The given sample creates a metric with the given name "DB-Operation" and will automatically record the duration until the `stop()` method of the metric is called. If this happens during an HTTP call you can see the duration of the "DB-Operation" directly in the developer console of your chrome browser.
-
-Let's have a look how you can use this feature is a simple REST endpoint in JavaEE. The following code shows how timing metrics will be created for a REST endpoint:
-
-{{< highlight java >}}
-@Path("/api/delete")
-public class MyEndpoint {
-
- @Inject
- private ServerTiming timing;
-
- @Inject
- private Database dabase;
-
- @GET
- public void clearAllData() {
- final Metric metric1 = timing.start("delete-users", "Deletes all users in the DB");
- database.deleteAllUsers();
- metric1.stop();
-
- final Metric metric2 = timing.start("delete-items", "Deletes all items in the DB");
- database.deleteAllItems();
- metric2.stop();
- }
-}
-{{< / highlight >}}
-
-Before we discuss this sample let's have a look at the same endpoint in Spring:
-
-{{< highlight java >}}
-@RestController
-public class MyEndpoint {
-
- @Autowired
- private ServerTiming timing;
-
- @Autowired
- private Database dabase;
-
- @RequestMapping("/api/delete")
- public void clearAllData() {
- final Metric metric1 = timing.start("delete-users", "Deletes all users in the DB");
- database.deleteAllUsers();
- metric1.stop();
-
- final Metric metric2 = timing.start("delete-items", "Deletes all items in the DB");
- database.deleteAllItems();
- metric2.stop();
- }
-}
-{{< / highlight >}}
-
-As you can see the use of the Rico API is 100% the same in JavaEE and Spring. This is one of the big benefits of Rico that offers all its services and components as managed beans for JavaEE and Spring. In the example, an endpoint is defined that does 2 calls against a database. For both of this calls a `dev.rico.server.timing.Metric` instance is created to measure the duration of the calls. Since the "server timing" specification supports a description next to a name for a timing entry, Rico allows to create metrics with a name and an optional description. In the given sample both metrics are defined with a description. Once a client calls the endpoint the htpp response will automatically contain the timing information and you can see the duration for the "deleteAllUsers" and the duration for the "deleteAllItems" step directly in your browser.
-
-## Better integration in enterprise frameworks
-
-The given example is just the beginning and with the next Rico release metrics to create "server timing" records can easily be defined by an annotation. This feature will first be available for JavaEE but will be added for Spring in the near future. Instead of injecting a `dev.rico.server.timing.ServerTiming` instance and create metrics by hand you can add the `dev.rico.server.timing.Timing` annotation to each method of a managed bean that duration you want to record. The following code shows how you can easily record the duration of an HTTP endpoint by doing so:
-
-{{< highlight java >}}
-@Path("/api/delete")
-public class MyEndpoint {
-
- @GET
- @Timing("item-count-metric")
- public int getItemCount() {
- final int count = ... // do some calculations;
- return count;
- }
-}
-{{< / highlight >}}
-
-Like the basic API the `Timing` annotation supports of a name and a description for a metric.
-
-
-
-Since you do not want to send metrics with every request to the client we currently add some configuration properties to Rico that let you configure when metrics should be added to a response. By doing so you can easily activate metrics in case of an issue when you want to have a look at the server timing information.
+---
+outdated: true
+showInBlog: false
+title: 'Server Timing with Rico'
+date: "2019-01-15"
+author: hendrik
+excerpt: 'This post gives an overview about the new server timing specification of the w3c and how server timing can be used in any enterprise Java server by using Rico.'
+categories: [Java, Rico]
+origin: https://dev.karakun.com
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In our open source project [Rico](https://github.com/rico-projects/rico) we introduced the support of "server timing" for JavaEE and Spring. Server Timing is [a new W3C feature](https://www.w3.org/TR/server-timing/) that allows you to add some metrics about the request handling to the response. I already introduced server timing in [one of my last posts]({% post_url 2019-01-09-integration-docker %}). The following image shows how such information would be rendered in the developer console of chrome:
+
+
+
+The feature is very useful when you develop a client that uses HTTP calls to communicate with the server. In this case, the client sends an HTTP request to the server and receives an HTTP response after some time. The functionality that the server executes to create the response based on the request is a black box for the client. Normally this is not really a problem but let's think about a possible bottleneck on the server. Sometimes your HTTP call takes much longer than normal. To make it worse the problem only happens when you do not debug the server. In such case "server timing" is a really helpful feature since you can display some timing information about the server functionality in the client.
+
+## Using Server Timing with Rico
+
+Rico provides a managed component that can easily be injected in any Spring or JavaEE bean. This component is defined by the `dev.rico.server.timing.ServerTiming` interface and lives in the request scope. By injection the component you can easily create metrics in your server that will automatically be added to the HTTP response. Here the w3c specification for server timing is used. Such `dev.rico.server.timing.ServerTiming` instance can be used to create metrics. A metric is defined by the `dev.rico.server.timing.Metric` interface and can be used to automatically add timing information to an HTTP response. The following code snippet shows the basic usage of the API:
+
+```javafinal ServerTiming timing = ... // will be injected
+
+final Metric dbMetric = timing.start("DB-Operation");
+//Do some work on the database
+dbMetric.stop();
```
+
+The given sample creates a metric with the given name "DB-Operation" and will automatically record the duration until the `stop()` method of the metric is called. If this happens during an HTTP call you can see the duration of the "DB-Operation" directly in the developer console of your chrome browser.
+
+Let's have a look how you can use this feature is a simple REST endpoint in JavaEE. The following code shows how timing metrics will be created for a REST endpoint:
+
+```java@Path("/api/delete")
+public class MyEndpoint {
+
+ @Inject
+ private ServerTiming timing;
+
+ @Inject
+ private Database dabase;
+
+ @GET
+ public void clearAllData() {
+ final Metric metric1 = timing.start("delete-users", "Deletes all users in the DB");
+ database.deleteAllUsers();
+ metric1.stop();
+
+ final Metric metric2 = timing.start("delete-items", "Deletes all items in the DB");
+ database.deleteAllItems();
+ metric2.stop();
+ }
+}
```
+
+Before we discuss this sample let's have a look at the same endpoint in Spring:
+
+```java@RestController
+public class MyEndpoint {
+
+ @Autowired
+ private ServerTiming timing;
+
+ @Autowired
+ private Database dabase;
+
+ @RequestMapping("/api/delete")
+ public void clearAllData() {
+ final Metric metric1 = timing.start("delete-users", "Deletes all users in the DB");
+ database.deleteAllUsers();
+ metric1.stop();
+
+ final Metric metric2 = timing.start("delete-items", "Deletes all items in the DB");
+ database.deleteAllItems();
+ metric2.stop();
+ }
+}
```
+
+As you can see the use of the Rico API is 100% the same in JavaEE and Spring. This is one of the big benefits of Rico that offers all its services and components as managed beans for JavaEE and Spring. In the example, an endpoint is defined that does 2 calls against a database. For both of this calls a `dev.rico.server.timing.Metric` instance is created to measure the duration of the calls. Since the "server timing" specification supports a description next to a name for a timing entry, Rico allows to create metrics with a name and an optional description. In the given sample both metrics are defined with a description. Once a client calls the endpoint the htpp response will automatically contain the timing information and you can see the duration for the "deleteAllUsers" and the duration for the "deleteAllItems" step directly in your browser.
+
+## Better integration in enterprise frameworks
+
+The given example is just the beginning and with the next Rico release metrics to create "server timing" records can easily be defined by an annotation. This feature will first be available for JavaEE but will be added for Spring in the near future. Instead of injecting a `dev.rico.server.timing.ServerTiming` instance and create metrics by hand you can add the `dev.rico.server.timing.Timing` annotation to each method of a managed bean that duration you want to record. The following code shows how you can easily record the duration of an HTTP endpoint by doing so:
+
+```java@Path("/api/delete")
+public class MyEndpoint {
+
+ @GET
+ @Timing("item-count-metric")
+ public int getItemCount() {
+ final int count = ... // do some calculations;
+ return count;
+ }
+}
```
+
+Like the basic API the `Timing` annotation supports of a name and a description for a metric.
+
+
+
+Since you do not want to send metrics with every request to the client we currently add some configuration properties to Rico that let you configure when metrics should be added to a response. By doing so you can easily activate metrics in case of an issue when you want to have a look at the server timing information.
diff --git a/content/posts/2019-01-25-security-exploits.md b/content/posts/2019-01-25-security-exploits.md
index 8827f8e4..e9f78fd6 100644
--- a/content/posts/2019-01-25-security-exploits.md
+++ b/content/posts/2019-01-25-security-exploits.md
@@ -1,297 +1,275 @@
----
-outdated: true
-showInBlog: false
-title: 'How a single request can kill your enterprise'
-date: "2019-01-25"
-author: hendrik
-excerpt: 'As developers we always try to create bug free and secure applications.
-Sometimes the most critical issues are not part of our code but of its dependencies.
-This post shows how security issues in dependencies can be used to create horrible attack scenarios of your systems.
-I will show one exploit in a simply Java based server application that can be used to do mostly everything with your whole system.'
-categories: [Java, OpenJDK]
-origin: https://dev.karakun.com
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-In this post, I will show a possible exploit of a small Java based enterprise application. The bugs that I use for the exploit are already fixed since 2017 and new versions of the libraries are available for more than a year. I do not want to blame any library or developer with this blog post. My main goal is to show you how important it is to know the dependencies of your application and the importance of having an up-to-date version of your dependencies. By updating to the latest releases you will always benefit from security fixes and avoid being attackable by exploits that were made available to the public.
-
-
-
-## Creating a small server application
-
-To give you an example of a security issue and an exploit that will use this issue to do really bad things I will create a minimalistic server application in Java. The application will handle some data items and will provide an HTTP endpoint so that a client can receive the current item set and mutate the data.
-
-To create such an application you can choose between several Java based frameworks like Spring (Boot) or JakartaEE. In this specific example, I decided to use one of the smallest frameworks that I know for such a use case. By using [spark](http://sparkjava.com) I can easily define a small HTTP server in just 1 Java class. To make life easier I will add [jackson](https://github.com/FasterXML/jackson) and [xalan](https://xalan.apache.org) as additional dependencies to provide automatic JSON-Object-Mapping for my application. Since I decided to use Maven for this example the `pom.xml` file might look like this:
-
-{{< highlight xml >}}
-
- com.karakun.dev
- exploit
- 1.0-SNAPSHOT
-
-
-
- com.sparkjava
- spark-core
- 2.7.2
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.8.8
-
-
- xalan
- xalan
- 2.7.2
-
-
-
-{{< / highlight >}}
-
-As you can see in the maven definition our application will only need 3 dependencies. Having a deeper look you realize that we already depend on **23** libraries as the 3 dependencies defined in the pom file depend on several other libraries. All these dependencies are transitive dependencies of our application and will be added to the classpath. The following graph shows all libraries our application depends on based on the above pom:
-
-
-
-Most dependencies in the graph are transitive dependencies from spark. Even if this library is one of the smallest HTTP server libs available it already brings a lot of things with it. In our example this is much more than we need since we do not want to add security, use websockets or program against the servlet API. This should not be any blame against spark. I just want to show you that your applications often depend on many more things than you might know. ;)
-
-## Let's start coding
-
-The first thing that we want to define is a plain POJO. I decided to call it "Product" and defined it as a small Java bean with some properties/fields. As you can see in the following definition of the class there is absolutely no magic in this code. I even do not define `toString()`, `equals()`, or `hashcode()` (which could be done but does not change anything in the sample). This "Product" data type will be the only data that our application can handle. Here is the complete code of the `Product` class:
-
-{{< highlight java >}}
-public class Product {
-
- private String name;
-
- private Object data;
-
- public Product() {
- }
-
- public Product(final String name, final Object data) {
- this.name = name;
- this.data = data;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(final String name) {
- this.name = name;
- }
-
- public Object getData() {
- return data;
- }
-
- public void setData(final Object data) {
- this.data = data;
- }
-}
-{{< / highlight >}}
-
-In our application, we want to manage the above products. Instead of using a database and maybe JPA (as most of us would do for real applications) I have chosen the easiest way to manage such data: a `List`. By defining and managing collections in our application we can easily hold a list of products in memory and work with them at runtime. Since several clients might access our sever I decided to use a `CopyOnWriteArrayList` as a concrete list type in my application. Thus, we won't end in any `ConcurrentModificationException`. The following code snippet shows how a collection with some initial data can be created:
-
-{{< highlight java >}}
-final List database = new CopyOnWriteArrayList<>();
-database.add(new Product("car", randomData()));
-database.add(new Product("boat", randomData()));
-database.add(new Product("plane", randomData()));
-{{< / highlight >}}
-
-The `randomData()` method used in this snippet creates some random metadata for the `Product` instances. You will see the code of this method later. For our example, these few lines of code are really everything we need as a small in-memory data store. By using a list we can easily add new products to our "database" or return the complete content.
-
-In the next step, we will use spark to provide HTTP/rest endpoints for exactly this functionality. We want to define an endpoint that can be reached by a `GET` request to return all our products and a second endpoint that can be reached by a `POST` request. The POST endpoint will add a new product as defined in the body of the HTTP request to our database.
-
-
-
-The following code snippet shows in a simplified way how this can be achieved by using spark:
-
-{{< highlight java >}}
-//Configure HTTP server
-Spark.port(8888);
-
-//Define endpoints
-Spark.get("/products", (request, response) -> serializer.writeValueAsString(database));
-Spark.post("/products", (request, response) -> database.add(deserializer.readValue(request.body(), Product.class)));
-{{< / highlight >}}
-
-For sure the post lambda needs null checks and exception handling. Plus, the `serializer` and `deserializer` objects that are used in the snippet are instances of the `ObjectMapper` class from jackson. These objects will be used to transform the JSON of the HTTP requests and responses to Java objects. Let's put the database and server code together in a single Java class. As you can see in the following snippet you can easily create such simple servers with only 50 lines of code:
-
-{{< highlight java >}}
-public class MyServer {
-
- private static final List database = new CopyOnWriteArrayList<>();
-
- private static final ObjectMapper deserializer = new ObjectMapper().enableDefaultTyping();
- private static final ObjectMapper serializer = new ObjectMapper();
-
- public static void main(String[] args) {
-
- //Adding some basic data
- database.add(new Product("car", randomData()));
- database.add(new Product("boat", randomData()));
- database.add(new Product("plane", randomData()));
-
- //Configure HTTP server
- Spark.port(8888);
-
- //Define endpoints
- Spark.get("/products", (request, response) -> {
- return serializer.writeValueAsString(database);
- });
-
- Spark.post("/products", (request, response) -> {
- try {
- final Product product = deserializer.readValue(request.body(), Product.class);
- Optional.ofNullable(product).ifPresent(p -> database.add(p));
- return "THANKS";
- } catch (final Exception e) {
- return "ERROR";
- }
- });
- }
-
- private static Map randomData() {
- final String[] colors = {"yellow", "red", "green"};
- final Map data = new HashMap<>();
- data.put("cost", new Random().nextInt(100_000) + "");
- data.put("color", colors[new Random().nextInt(colors.length)]);
- return data;
- }
-}
-{{< / highlight >}}
-
-At this point, we can start our server and call the defined endpoints. To do such calls you can use any tool that provides the functionality to execute HTTP requests. I use [PAW](https://paw.cloud) on my Mac but you can use any other tool like [curl](https://curl.haxx.se) or [postman](https://www.getpostman.com) for example. Also, all major browsers offer plugins or extensions to trigger HTTP requests.
-
-The following snippet shows the raw content of a GET request to receive the product list from the server
-
-{{< highlight java >}}
-GET /products HTTP/1.1
-Host: localhost:8888
-Connection: close
-User-Agent: Paw/3.1.7 (Macintosh; OS X/10.14.2) GCDHTTPRequest
-{{< / highlight >}}
-
-When doing the request you will receive a response that contains the product list in JSON format as you can see in the following screenshot of Paw:
-
-
-
-Once you added a new product by doing a `POST` HTTP request you see the new product in this JSON list when doing a new `GET` request. For posting a new product the body of your HTTP requests needs to look like this:
-
-{{< highlight json >}}
-{
- "name":"jetpack",
- "data":["java.util.HashMap",{"cost":"200_000","color":"yellow"}]
-}
-{{< / highlight >}}
-
-Thanks to the jackson and xalan dependency our server application will automatically create a new `Product` instance from the given JSON definition.
-
-## Let's hack
-
-Based on the current state of our application and the information we have about its implementation and endpoints we could consider our application as bulletproof that cannot be hacked in any way. Reviewing the following points might support this opinion:
-
-* The application can only be accessed by 2 endpoints
-* The endpoints are well defined and based on the HTTP standard
-* Internally exception handling is added to the endpoints
-* Internally the endpoints only have access to the data list
-* The application is very small and therefore we understand the complete code
-* We only use well-known dependencies
-* All dependencies are open source
-
-With all this in mind, you might be shocked when I tell you that I can get access to the native file system by only doing 1 HTTP request against this application. And: the file system is only one example. I showed the very same sample at a JUG session and created a request against the application that changed the wallpaper of my operation system. While this is not really dangerous it had a nice effect on the audience to visualize that I can really do more or less everything on the system that hosts the given application.
-
-
-
-All this can be easily achieved by using a simple exploit. Everything I need to do is a `POST` request against the endpoint that our application offers to add a new `Product` instance. Instead of just sending a JSON based description of a product (which I want to add), the body of my HTTP request looks like this:
-
-{{< highlight json >}}
-{
- "name": "bomb",
- "data": ["org.apache.xalan.xsltc.trax.TemplatesImpl",
- {
- "transletBytecodes" : [ "yv66vgAAADQAy........ABAHoAAwB7AHwAew==" ],
- "transletName": "oops!",
- "outputProperties": {}
- }
- ]
-}
-{{< / highlight >}}
-
-The content of the `transletBytecodes` property is much longer than shown in this snippet. But since you cannot really read the content it doesn't make sense to show it completely. Much more interesting is the general workflow that I used to create this HTTP body and how it will be handled in our server application.
-
-The content of the `transletBytecodes` property is a base64 encoded byte array. This byte array is the byte representation of a compiled Java class. To create the base 64 string I wrote a java class compiled it and simply converted the content of the class file to base64.
-
-
-
-If you want to try this on your own just compile a Java class and use any converter to create a base64 based string out of the content of the class file. You can even create such tool by yourself with some lines of Java code:
-
-{{< highlight java >}}
-public class Encoder {
-
- public static void main(String[] args) throws Exception {
- byte[] classBytes = Files.readAllBytes(new File("target/classes/com/karakun/dev/Bomb.class").toPath());
- byte[] encodedBytes = Base64.getEncoder().encode(classBytes);
- System.out.println(new String(encodedBytes));
- }
-}
-{{< / highlight >}}
-
-The given code directly prints the base64 encoded string as the output of the program to your terminal. If you want to do this with a class that you can use for the exploit you need to extend a specific class that is defined by xalan. Simply add `org.apache.xalan.xsltc.runtime.AbstractTranslet` class. The 2 abstract methods can be implemented with an empty body they are not used for the exploit. The really interesting part is the constructor of your class. Here you can easily add some custom code like I did in the following sample:
-
-{{< highlight java >}}
-public class Bomb extends org.apache.xalan.xsltc.runtime.AbstractTranslet {
-
- public Bomb() {
- super.transletVersion = CURRENT_TRANSLET_VERSION;
-
- //Now we can do evil stuff
- System.out.println("BOOOOOOOOM!");
- }
-
- @Override
- public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
- // empty
- }
-
- @Override
- public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
- // empty
- }
-}
-{{< / highlight >}}
-
-If you transform such a class to a base64 string as described above and send it to your server application the constructor of your custom class will be called on the server. With the given example the server would print "BOOOOOOOOM!" as output in the terminal. Before we have a look at the internals and how this is even possible think about the evil potential of this security issue. Instead of just printing a funny string we could write an algorithm that does horrible things on your system as you can see in the following code snippet:
-
-{{< highlight java >}}
-public Bomb() {
- super.transletVersion = CURRENT_TRANSLET_VERSION;
-
- //the byte content of a native tool as base64
- String snifferBinaryStream = "yv66vgAAADQAy........ABAHoAAwB7AHwAew"
-
- //Let's create an executable on the local machine
- File executable = copyToExe(snifferBinaryStream);
-
- //Let's start our native executable
- run(executable);
-}
-{{< / highlight >}}
-
-## Some background to the vulnerability
-
-The exploit that I used in the sample is a security issue that occurred in several versions of the jackson-databind library (All versions before 2.6.7.1, 2.7.9.1 and 2.8.9 are affected). The issue was reported in 2017 and is fixed in new releases of the library. Internally the problem is defined like this: `jackson-databind` will perform code execution by sending maliciously crafted input to the readValue method of the `ObjectMapper`.
-
-You can find more information about the vulnerability [here](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7525)
-
-## Conclusion
-
-This small example shows that even common and popular libraries can have security issues which can be used for exploits. Sometimes such bugs (and the exploits) can be harmless but the given sample shows how such exploits could kill your complete system. We as developers need to know about such problems in the libraries our systems depend on and try to get rid of them. The following thoughts can help us not to end in creating insecure applications or get hacked:
-
-* The most important step is to know the internal dependencies and remove frameworks and libraries that you don't really need.
-* You should keep all your dependencies up-to-date.
-* All security issues are captured in [databases](http://cve.mitre.org) and tools can help us to check our applications and their dependencies against these databases.
-
-I plan to write an article in the near future about helpful tools that will notify you automatically about possible security issues in your software stack.
+---
+outdated: true
+showInBlog: false
+title: 'How a single request can kill your enterprise'
+date: "2019-01-25"
+author: hendrik
+excerpt: 'As developers we always try to create bug free and secure applications.
+Sometimes the most critical issues are not part of our code but of its dependencies.
+This post shows how security issues in dependencies can be used to create horrible attack scenarios of your systems.
+I will show one exploit in a simply Java based server application that can be used to do mostly everything with your whole system.'
+categories: [Java, OpenJDK]
+origin: https://dev.karakun.com
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+In this post, I will show a possible exploit of a small Java based enterprise application. The bugs that I use for the exploit are already fixed since 2017 and new versions of the libraries are available for more than a year. I do not want to blame any library or developer with this blog post. My main goal is to show you how important it is to know the dependencies of your application and the importance of having an up-to-date version of your dependencies. By updating to the latest releases you will always benefit from security fixes and avoid being attackable by exploits that were made available to the public.
+
+
+
+## Creating a small server application
+
+To give you an example of a security issue and an exploit that will use this issue to do really bad things I will create a minimalistic server application in Java. The application will handle some data items and will provide an HTTP endpoint so that a client can receive the current item set and mutate the data.
+
+To create such an application you can choose between several Java based frameworks like Spring (Boot) or JakartaEE. In this specific example, I decided to use one of the smallest frameworks that I know for such a use case. By using [spark](http://sparkjava.com) I can easily define a small HTTP server in just 1 Java class. To make life easier I will add [jackson](https://github.com/FasterXML/jackson) and [xalan](https://xalan.apache.org) as additional dependencies to provide automatic JSON-Object-Mapping for my application. Since I decided to use Maven for this example the `pom.xml` file might look like this:
+
+```xml
+ com.karakun.dev
+ exploit
+ 1.0-SNAPSHOT
+
+
+
+ com.sparkjava
+ spark-core
+ 2.7.2
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.8.8
+
+
+ xalan
+ xalan
+ 2.7.2
+
+
+
```
+
+As you can see in the maven definition our application will only need 3 dependencies. Having a deeper look you realize that we already depend on **23** libraries as the 3 dependencies defined in the pom file depend on several other libraries. All these dependencies are transitive dependencies of our application and will be added to the classpath. The following graph shows all libraries our application depends on based on the above pom:
+
+
+
+Most dependencies in the graph are transitive dependencies from spark. Even if this library is one of the smallest HTTP server libs available it already brings a lot of things with it. In our example this is much more than we need since we do not want to add security, use websockets or program against the servlet API. This should not be any blame against spark. I just want to show you that your applications often depend on many more things than you might know. ;)
+
+## Let's start coding
+
+The first thing that we want to define is a plain POJO. I decided to call it "Product" and defined it as a small Java bean with some properties/fields. As you can see in the following definition of the class there is absolutely no magic in this code. I even do not define `toString()`, `equals()`, or `hashcode()` (which could be done but does not change anything in the sample). This "Product" data type will be the only data that our application can handle. Here is the complete code of the `Product` class:
+
+```javapublic class Product {
+
+ private String name;
+
+ private Object data;
+
+ public Product() {
+ }
+
+ public Product(final String name, final Object data) {
+ this.name = name;
+ this.data = data;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public void setData(final Object data) {
+ this.data = data;
+ }
+}
```
+
+In our application, we want to manage the above products. Instead of using a database and maybe JPA (as most of us would do for real applications) I have chosen the easiest way to manage such data: a `List`. By defining and managing collections in our application we can easily hold a list of products in memory and work with them at runtime. Since several clients might access our sever I decided to use a `CopyOnWriteArrayList` as a concrete list type in my application. Thus, we won't end in any `ConcurrentModificationException`. The following code snippet shows how a collection with some initial data can be created:
+
+```javafinal List database = new CopyOnWriteArrayList<>();
+database.add(new Product("car", randomData()));
+database.add(new Product("boat", randomData()));
+database.add(new Product("plane", randomData()));
```
+
+The `randomData()` method used in this snippet creates some random metadata for the `Product` instances. You will see the code of this method later. For our example, these few lines of code are really everything we need as a small in-memory data store. By using a list we can easily add new products to our "database" or return the complete content.
+
+In the next step, we will use spark to provide HTTP/rest endpoints for exactly this functionality. We want to define an endpoint that can be reached by a `GET` request to return all our products and a second endpoint that can be reached by a `POST` request. The POST endpoint will add a new product as defined in the body of the HTTP request to our database.
+
+
+
+The following code snippet shows in a simplified way how this can be achieved by using spark:
+
+```java//Configure HTTP server
+Spark.port(8888);
+
+//Define endpoints
+Spark.get("/products", (request, response) -> serializer.writeValueAsString(database));
+Spark.post("/products", (request, response) -> database.add(deserializer.readValue(request.body(), Product.class)));
```
+
+For sure the post lambda needs null checks and exception handling. Plus, the `serializer` and `deserializer` objects that are used in the snippet are instances of the `ObjectMapper` class from jackson. These objects will be used to transform the JSON of the HTTP requests and responses to Java objects. Let's put the database and server code together in a single Java class. As you can see in the following snippet you can easily create such simple servers with only 50 lines of code:
+
+```javapublic class MyServer {
+
+ private static final List database = new CopyOnWriteArrayList<>();
+
+ private static final ObjectMapper deserializer = new ObjectMapper().enableDefaultTyping();
+ private static final ObjectMapper serializer = new ObjectMapper();
+
+ public static void main(String[] args) {
+
+ //Adding some basic data
+ database.add(new Product("car", randomData()));
+ database.add(new Product("boat", randomData()));
+ database.add(new Product("plane", randomData()));
+
+ //Configure HTTP server
+ Spark.port(8888);
+
+ //Define endpoints
+ Spark.get("/products", (request, response) -> {
+ return serializer.writeValueAsString(database);
+ });
+
+ Spark.post("/products", (request, response) -> {
+ try {
+ final Product product = deserializer.readValue(request.body(), Product.class);
+ Optional.ofNullable(product).ifPresent(p -> database.add(p));
+ return "THANKS";
+ } catch (final Exception e) {
+ return "ERROR";
+ }
+ });
+ }
+
+ private static Map randomData() {
+ final String[] colors = {"yellow", "red", "green"};
+ final Map data = new HashMap<>();
+ data.put("cost", new Random().nextInt(100_000) + "");
+ data.put("color", colors[new Random().nextInt(colors.length)]);
+ return data;
+ }
+}
```
+
+At this point, we can start our server and call the defined endpoints. To do such calls you can use any tool that provides the functionality to execute HTTP requests. I use [PAW](https://paw.cloud) on my Mac but you can use any other tool like [curl](https://curl.haxx.se) or [postman](https://www.getpostman.com) for example. Also, all major browsers offer plugins or extensions to trigger HTTP requests.
+
+The following snippet shows the raw content of a GET request to receive the product list from the server
+
+```javaGET /products HTTP/1.1
+Host: localhost:8888
+Connection: close
+User-Agent: Paw/3.1.7 (Macintosh; OS X/10.14.2) GCDHTTPRequest
```
+
+When doing the request you will receive a response that contains the product list in JSON format as you can see in the following screenshot of Paw:
+
+
+
+Once you added a new product by doing a `POST` HTTP request you see the new product in this JSON list when doing a new `GET` request. For posting a new product the body of your HTTP requests needs to look like this:
+
+```json{
+ "name":"jetpack",
+ "data":["java.util.HashMap",{"cost":"200_000","color":"yellow"}]
+}
```
+
+Thanks to the jackson and xalan dependency our server application will automatically create a new `Product` instance from the given JSON definition.
+
+## Let's hack
+
+Based on the current state of our application and the information we have about its implementation and endpoints we could consider our application as bulletproof that cannot be hacked in any way. Reviewing the following points might support this opinion:
+
+* The application can only be accessed by 2 endpoints
+* The endpoints are well defined and based on the HTTP standard
+* Internally exception handling is added to the endpoints
+* Internally the endpoints only have access to the data list
+* The application is very small and therefore we understand the complete code
+* We only use well-known dependencies
+* All dependencies are open source
+
+With all this in mind, you might be shocked when I tell you that I can get access to the native file system by only doing 1 HTTP request against this application. And: the file system is only one example. I showed the very same sample at a JUG session and created a request against the application that changed the wallpaper of my operation system. While this is not really dangerous it had a nice effect on the audience to visualize that I can really do more or less everything on the system that hosts the given application.
+
+
+
+All this can be easily achieved by using a simple exploit. Everything I need to do is a `POST` request against the endpoint that our application offers to add a new `Product` instance. Instead of just sending a JSON based description of a product (which I want to add), the body of my HTTP request looks like this:
+
+```json{
+ "name": "bomb",
+ "data": ["org.apache.xalan.xsltc.trax.TemplatesImpl",
+ {
+ "transletBytecodes" : [ "yv66vgAAADQAy........ABAHoAAwB7AHwAew==" ],
+ "transletName": "oops!",
+ "outputProperties": {}
+ }
+ ]
+}
```
+
+The content of the `transletBytecodes` property is much longer than shown in this snippet. But since you cannot really read the content it doesn't make sense to show it completely. Much more interesting is the general workflow that I used to create this HTTP body and how it will be handled in our server application.
+
+The content of the `transletBytecodes` property is a base64 encoded byte array. This byte array is the byte representation of a compiled Java class. To create the base 64 string I wrote a java class compiled it and simply converted the content of the class file to base64.
+
+
+
+If you want to try this on your own just compile a Java class and use any converter to create a base64 based string out of the content of the class file. You can even create such tool by yourself with some lines of Java code:
+
+```javapublic class Encoder {
+
+ public static void main(String[] args) throws Exception {
+ byte[] classBytes = Files.readAllBytes(new File("target/classes/com/karakun/dev/Bomb.class").toPath());
+ byte[] encodedBytes = Base64.getEncoder().encode(classBytes);
+ System.out.println(new String(encodedBytes));
+ }
+}
```
+
+The given code directly prints the base64 encoded string as the output of the program to your terminal. If you want to do this with a class that you can use for the exploit you need to extend a specific class that is defined by xalan. Simply add `org.apache.xalan.xsltc.runtime.AbstractTranslet` class. The 2 abstract methods can be implemented with an empty body they are not used for the exploit. The really interesting part is the constructor of your class. Here you can easily add some custom code like I did in the following sample:
+
+```javapublic class Bomb extends org.apache.xalan.xsltc.runtime.AbstractTranslet {
+
+ public Bomb() {
+ super.transletVersion = CURRENT_TRANSLET_VERSION;
+
+ //Now we can do evil stuff
+ System.out.println("BOOOOOOOOM!");
+ }
+
+ @Override
+ public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
+ // empty
+ }
+
+ @Override
+ public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
+ // empty
+ }
+}
```
+
+If you transform such a class to a base64 string as described above and send it to your server application the constructor of your custom class will be called on the server. With the given example the server would print "BOOOOOOOOM!" as output in the terminal. Before we have a look at the internals and how this is even possible think about the evil potential of this security issue. Instead of just printing a funny string we could write an algorithm that does horrible things on your system as you can see in the following code snippet:
+
+```javapublic Bomb() {
+ super.transletVersion = CURRENT_TRANSLET_VERSION;
+
+ //the byte content of a native tool as base64
+ String snifferBinaryStream = "yv66vgAAADQAy........ABAHoAAwB7AHwAew"
+
+ //Let's create an executable on the local machine
+ File executable = copyToExe(snifferBinaryStream);
+
+ //Let's start our native executable
+ run(executable);
+}
```
+
+## Some background to the vulnerability
+
+The exploit that I used in the sample is a security issue that occurred in several versions of the jackson-databind library (All versions before 2.6.7.1, 2.7.9.1 and 2.8.9 are affected). The issue was reported in 2017 and is fixed in new releases of the library. Internally the problem is defined like this: `jackson-databind` will perform code execution by sending maliciously crafted input to the readValue method of the `ObjectMapper`.
+
+You can find more information about the vulnerability [here](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7525)
+
+## Conclusion
+
+This small example shows that even common and popular libraries can have security issues which can be used for exploits. Sometimes such bugs (and the exploits) can be harmless but the given sample shows how such exploits could kill your complete system. We as developers need to know about such problems in the libraries our systems depend on and try to get rid of them. The following thoughts can help us not to end in creating insecure applications or get hacked:
+
+* The most important step is to know the internal dependencies and remove frameworks and libraries that you don't really need.
+* You should keep all your dependencies up-to-date.
+* All security issues are captured in [databases](http://cve.mitre.org) and tools can help us to check our applications and their dependencies against these databases.
+
+I plan to write an article in the near future about helpful tools that will notify you automatically about possible security issues in your software stack.
diff --git a/content/posts/2020-02-15-back-to-the-future.md b/content/posts/2020-02-15-back-to-the-future.md
index d670b713..cb6a63be 100644
--- a/content/posts/2020-02-15-back-to-the-future.md
+++ b/content/posts/2020-02-15-back-to-the-future.md
@@ -1,142 +1,136 @@
----
-outdated: true
-showInBlog: false
-title: 'Back to the future - with Java'
-date: "2020-02-15"
-author: hendrik
-excerpt: "Each year several Java applications might show wrong date information for the days around New
- Year's Eve. This post gives an overview about the problem and describes how you can easily avoid such
- bugs"
-categories: [Java]
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-Since Java 8 we have a new date & time API as part of Java. The API is really good and offers a lot of functionality and flexibility. Based on this it’s much easier to handle date and time information in Java. But even with this new API, several use cases are still quite complex. When talking about problems with date and time information normally timezones are mentioned directly. In this post, I will show you that even the basic usage of date information can create problems. So we will forget all the timezone problems for now and have a look at a really easy use case: We want to print the year of a date. Maybe even this task can end in some trouble…
-
-Let's have a look at a simple code snippet:
-
-{{< highlight java >}}
-final LocalDate myDate = LocalDate.of(2015, 11, 30);
-final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.YYYY");
-final String formattedDate = formatter.format(myDate);
-System.out.println("The date is " + formattedDate);
-{{< / highlight >}}
-
-Even if you have not used the API that often it's quite easy to understand that the code will print `The date is 30.11.2015` to the console. Based on this experience we can create a method like this:
-
-{{< highlight java >}}
-/**
-* Prints the given date in the format that is normally used in Europe.
-* The format is described as
-* [day of month (2 digits)].[month of year (2 digits)].[year (4 digits)]
-*
-* @param date the date
-*/
-public static void printDate(final LocalDate date) {}
- final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.YYYY");
- final String formattedDate = formatter.format(myDate);
- System.out.println("The date is " + formattedDate);
-}
-{{< / highlight >}}
-
-What if I tell you that this code already contains a common problem, that I've seen in several projects within the last years? To understand that problem we should call the method with a set of
-different dates:
-
-* `LocalDate.of(2015, 11, 30)` results in `The date is 30.11.2015`
-* `LocalDate.of(1992, 4, 12)` results in `The date is 12.04.1992`
-* `LocalDate.of(2008, 12, 28)` results in `The date is 28.12.2008`
-* `LocalDate.of(2021, 1, 1)` results in `The date is 01.01.2020`
-
-If you realized the mismatch and you are not aware of the problem you might ask yourself what the hell is happening here. While the first 3 example looks good the output of the last example contains a wrong year. You can easily try this on your own if you do not believe me ;)
-
-
-
-## It's not a bug, it's a feature
-
-To be true the described behavior is not a bug in the JDK, it's a feature that a lot of people are not aware of. So let's have a look at why the given output is correct and what we need to do to get our wanted behavior.
-
-The problem with our code is hidden in the usage of the `DateTimeFormatter`. To receive our date as a formatted string we use the pattern `dd.MM.YYYY`. Maybe you already asked yourself why the `d` in the pattern is written lowercase while the `M` and `Y` are written uppercase. Let's have a look at the [JavaDoc](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html) of the `DateTimeFormatter` class and the definition of the pattern for formatting and parsing.
-In the doc, you can find a table with a description of each supported letter in such a pattern. The following table contains only the letters that are interested in our use case:
-
-| letter | meaning | examples |
-| ------ | --------------- | -------- |
-| d | day-of-month | 10 |
-| D | day-of-year | 189 |
-| m | minute-of-hour | 30 |
-| M | month-of-year | 7; 07 |
-| y | year-of-era | 2004; 04 |
-| Y | week-based-year | 1996; 96 |
-| u | year | 2004; 04 |
-
-As you can see for all the letters that we used in the example the uppercase and lowercase variants have a different meaning. When having a look at the definition for day and month we can easily say that we have chosen the right pattern to format the string. It becomes more interesting when having a look at the year definition. As you can see the table contains 3 different letters (`y`, `Y`, and `u`) that can be used to define the format of a year in the pattern.
-
-### Finding the problem
-
-In our example, we used `YYYY` to define the year. Let's have a look at the definition of the parser letter `Y`. As you can see in the table it is defined as **'week-based-year'**. While the examples in the table looks fine this definition is the cause of our problem:
-
-The **'week-based-year'** type is defined by the 'ISO week date' that is part of ISO 8601. A detailed definition of this standard can be found at [wikipedia](https://en.wikipedia.org/wiki/ISO_week_date). The standard defines that a year has 52 or 53 full weeks. That is 364 or 371 days instead of the usual 365 or 366 days. In the definition weeks always start with Monday and the first week of a year is the week that contains the first Thursday of the year.
-
-By using this definition it can happen that the first days of a year are not part of the first week of the year but the last week of the previous year. Next to this the last days of December could be part of the first week of the next year. Here are some examples:
-
-* **December 29, 2014 (Monday)** is defined as part of the first week of the year 2015 since the Thursday of this week is the first Thursday in 2015 (1 January 2015). Based on this the `YYYY` pattern would result in 2015 for that date.
-* **January 1, 2015 (Thursday)** is defined as part of the first week of the year 2015 since the Thursday of this week is the first Thursday in 2015. Based on this the `YYYY` pattern would result in 2015 for that date.
-* **January 1, 2016 (Friday)** is defined as part of the last week of the year 2015 since the Thursday of this week is in 2015 (December 31, 2015). Based on this the `YYYY` pattern would result in 2015 for that date.
-
-Maybe you have noticed in the samples that both dates '1 January 2015' and '1 January 2016' will result in the same string by using the `dd.MM.YYYY` pattern ;)
-
-For most people, this ISO standard is not usable for their regular work. But as you have seen in the examples this can end in critical bugs in our software.
-
-Since we found the problem and understood the 'ISO week date' we can say that this is normally not the solution that we want to use in our software. The `DateTimeFormatter` class supports 2 other letters (`y` and `u`) to format year information. Let's have a look at these 2 options.
-
-### Working with eras
-
-It might look like it won't make any difference if you use `y` or `u` as a letter for years. As long as the date is within the current era everything is fine. The Gregorian Calendar uses the "Common Era" notation. Here the 2 eras **"Common Era" (CE)** and **"Before the Common Era" (BCE)** are used. We are currently in the "Common Era" that started with year 0. An end of the "Common Era" is not defined. This definition is an alternative to Dionysian “Before Christ” (BC) and “Anno Domini” (AD) definition that is numerically equivalent but uses a different (non-religious based) wording.
-
-
-
-When formatting a year by using the `DateTimeFormatter` class you can add the era to your custom pattern. The era is defined by the letter `G` as you can find out in the JavaDoc of `DateTimeFormatter`. The following table gives an overview how years will be formatted based on the 2 different types:
-
-| year (as number) | pattern 'uuuu' | pattern 'yyyy' | pattern 'yyyy G' |
-| ---------------- | -------------- | -------------- | ---------------- |
-| 2019 | 2019 | 2019 | 2019 AD |
-| 3 | 0003 | 0003 | 0003 AD |
-| 0 | 0000 | 0001 | 0001 BC |
-| -1 | -0001 | 0002 | 0002 BC |
-| -10 | -0010 | 0011 | 0011 BC |
-| -2019 | -2019 | 2020 | 2020 BC |
-
-From my point of view, both pattern have their downsides. When using the `yyyy` pattern without adding information of the era you might get an output that will be interpreted wrong by a user. Imagine you have a mathematical bug in your software and calculate the year '-2019' as the final year of any contract. I would assume that it will be better to see '-2019' on screen/paper and recognize the error instead of '2020'.
-
-Another interesting point is that the result might be longer as the letter count in the `uuuu` pattern. As you can see in the table negative year numbers will have a `-` as a prefix when using the `uuuu` pattern. Based on this you can not trust the string length of a formatted date when using the `u` to format years.
-
-#### Other eras in Java
-
-Java supports different calendar systems next to the Gregorian Calendar. You can find a good example when having a look at the `JapaneseChronology` class that defines the 'Japanese Imperial calendar system' in Java. While I have absolutely no knowledge about that calendar system you can find out that is has several eras that are defined by the `JapaneseEra` class. This class contains several constants that define the eras of the calendar system:
-
-| name | meaning |
-| ------ | ------------------------------------------ |
-| MEIJI | The 'Meiji' era (1868-01-01 - 1912-07-29) |
-| TAISHO | The 'Taisho' era (1912-07-30 - 1926-12-24) |
-| SHOWA | The 'Showa' era (1926-12-25 - 1989-01-07) |
-| HEISEI | The 'Heisei' era (1989-01-08 - current) |
-
-When using the 'Japanese Imperial calendar system' Java offers some additional classes to define time information. The following code creates a date based on the calendar and prints it based on different format pattern strings:
-
-{{< highlight java >}}
-final JapaneseDate japaneseDate = JapaneseDate.of(JapaneseEra.MEIJI, 7, 3, 17);
-
-final String format1 = DateTimeFormatter.ofPattern("dd.MM.uuuu").format(japaneseDate);
-final String format2 = DateTimeFormatter.ofPattern("dd.MM.yyyy").format(japaneseDate);
-final String format3 = DateTimeFormatter.ofPattern("dd.MM.yyyy G").format(japaneseDate);
-
-System.out.println(format1); // prints '17.03.1874'
-System.out.println(format2); // prints '17.03.0007'
-System.out.println(format3); // prints '17.03.0007 Meiji'
-{{< / highlight >}}
-
-In this sample the usage between the two pattern `yyyy` and `uuuu` ends in a totally different result.
-
-## Conclusion
-
-Working with date and time information is always a complex topic. Normally people say that coding will become complex when timezone functionality is added. In the given examples we do not concern timezones at all and already found a lot of complex topics. All these topics can end in horrible bugs in business applications.
-
-For the initial problem, we can easily say that the `dd.MM.YYYY` pattern should never be used. If you want to use `dd.MM.yyyy` or `dd.MM.uuuu` in your application depends on your needs and how you want to visualize negative year information. Just saying that your application will never need to handle negative years is maybe not the best answer since we all just developers that create bugs from time to time ;)
+---
+outdated: true
+showInBlog: false
+title: 'Back to the future - with Java'
+date: "2020-02-15"
+author: hendrik
+excerpt: "Each year several Java applications might show wrong date information for the days around New
+ Year's Eve. This post gives an overview about the problem and describes how you can easily avoid such
+ bugs"
+categories: [Java]
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+Since Java 8 we have a new date & time API as part of Java. The API is really good and offers a lot of functionality and flexibility. Based on this it’s much easier to handle date and time information in Java. But even with this new API, several use cases are still quite complex. When talking about problems with date and time information normally timezones are mentioned directly. In this post, I will show you that even the basic usage of date information can create problems. So we will forget all the timezone problems for now and have a look at a really easy use case: We want to print the year of a date. Maybe even this task can end in some trouble…
+
+Let's have a look at a simple code snippet:
+
+```javafinal LocalDate myDate = LocalDate.of(2015, 11, 30);
+final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.YYYY");
+final String formattedDate = formatter.format(myDate);
+System.out.println("The date is " + formattedDate);
```
+
+Even if you have not used the API that often it's quite easy to understand that the code will print `The date is 30.11.2015` to the console. Based on this experience we can create a method like this:
+
+```java/**
+* Prints the given date in the format that is normally used in Europe.
+* The format is described as
+* [day of month (2 digits)].[month of year (2 digits)].[year (4 digits)]
+*
+* @param date the date
+*/
+public static void printDate(final LocalDate date) {}
+ final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.YYYY");
+ final String formattedDate = formatter.format(myDate);
+ System.out.println("The date is " + formattedDate);
+}
```
+
+What if I tell you that this code already contains a common problem, that I've seen in several projects within the last years? To understand that problem we should call the method with a set of
+different dates:
+
+* `LocalDate.of(2015, 11, 30)` results in `The date is 30.11.2015`
+* `LocalDate.of(1992, 4, 12)` results in `The date is 12.04.1992`
+* `LocalDate.of(2008, 12, 28)` results in `The date is 28.12.2008`
+* `LocalDate.of(2021, 1, 1)` results in `The date is 01.01.2020`
+
+If you realized the mismatch and you are not aware of the problem you might ask yourself what the hell is happening here. While the first 3 example looks good the output of the last example contains a wrong year. You can easily try this on your own if you do not believe me ;)
+
+
+
+## It's not a bug, it's a feature
+
+To be true the described behavior is not a bug in the JDK, it's a feature that a lot of people are not aware of. So let's have a look at why the given output is correct and what we need to do to get our wanted behavior.
+
+The problem with our code is hidden in the usage of the `DateTimeFormatter`. To receive our date as a formatted string we use the pattern `dd.MM.YYYY`. Maybe you already asked yourself why the `d` in the pattern is written lowercase while the `M` and `Y` are written uppercase. Let's have a look at the [JavaDoc](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html) of the `DateTimeFormatter` class and the definition of the pattern for formatting and parsing.
+In the doc, you can find a table with a description of each supported letter in such a pattern. The following table contains only the letters that are interested in our use case:
+
+| letter | meaning | examples |
+| ------ | --------------- | -------- |
+| d | day-of-month | 10 |
+| D | day-of-year | 189 |
+| m | minute-of-hour | 30 |
+| M | month-of-year | 7; 07 |
+| y | year-of-era | 2004; 04 |
+| Y | week-based-year | 1996; 96 |
+| u | year | 2004; 04 |
+
+As you can see for all the letters that we used in the example the uppercase and lowercase variants have a different meaning. When having a look at the definition for day and month we can easily say that we have chosen the right pattern to format the string. It becomes more interesting when having a look at the year definition. As you can see the table contains 3 different letters (`y`, `Y`, and `u`) that can be used to define the format of a year in the pattern.
+
+### Finding the problem
+
+In our example, we used `YYYY` to define the year. Let's have a look at the definition of the parser letter `Y`. As you can see in the table it is defined as **'week-based-year'**. While the examples in the table looks fine this definition is the cause of our problem:
+
+The **'week-based-year'** type is defined by the 'ISO week date' that is part of ISO 8601. A detailed definition of this standard can be found at [wikipedia](https://en.wikipedia.org/wiki/ISO_week_date). The standard defines that a year has 52 or 53 full weeks. That is 364 or 371 days instead of the usual 365 or 366 days. In the definition weeks always start with Monday and the first week of a year is the week that contains the first Thursday of the year.
+
+By using this definition it can happen that the first days of a year are not part of the first week of the year but the last week of the previous year. Next to this the last days of December could be part of the first week of the next year. Here are some examples:
+
+* **December 29, 2014 (Monday)** is defined as part of the first week of the year 2015 since the Thursday of this week is the first Thursday in 2015 (1 January 2015). Based on this the `YYYY` pattern would result in 2015 for that date.
+* **January 1, 2015 (Thursday)** is defined as part of the first week of the year 2015 since the Thursday of this week is the first Thursday in 2015. Based on this the `YYYY` pattern would result in 2015 for that date.
+* **January 1, 2016 (Friday)** is defined as part of the last week of the year 2015 since the Thursday of this week is in 2015 (December 31, 2015). Based on this the `YYYY` pattern would result in 2015 for that date.
+
+Maybe you have noticed in the samples that both dates '1 January 2015' and '1 January 2016' will result in the same string by using the `dd.MM.YYYY` pattern ;)
+
+For most people, this ISO standard is not usable for their regular work. But as you have seen in the examples this can end in critical bugs in our software.
+
+Since we found the problem and understood the 'ISO week date' we can say that this is normally not the solution that we want to use in our software. The `DateTimeFormatter` class supports 2 other letters (`y` and `u`) to format year information. Let's have a look at these 2 options.
+
+### Working with eras
+
+It might look like it won't make any difference if you use `y` or `u` as a letter for years. As long as the date is within the current era everything is fine. The Gregorian Calendar uses the "Common Era" notation. Here the 2 eras **"Common Era" (CE)** and **"Before the Common Era" (BCE)** are used. We are currently in the "Common Era" that started with year 0. An end of the "Common Era" is not defined. This definition is an alternative to Dionysian “Before Christ” (BC) and “Anno Domini” (AD) definition that is numerically equivalent but uses a different (non-religious based) wording.
+
+
+
+When formatting a year by using the `DateTimeFormatter` class you can add the era to your custom pattern. The era is defined by the letter `G` as you can find out in the JavaDoc of `DateTimeFormatter`. The following table gives an overview how years will be formatted based on the 2 different types:
+
+| year (as number) | pattern 'uuuu' | pattern 'yyyy' | pattern 'yyyy G' |
+| ---------------- | -------------- | -------------- | ---------------- |
+| 2019 | 2019 | 2019 | 2019 AD |
+| 3 | 0003 | 0003 | 0003 AD |
+| 0 | 0000 | 0001 | 0001 BC |
+| -1 | -0001 | 0002 | 0002 BC |
+| -10 | -0010 | 0011 | 0011 BC |
+| -2019 | -2019 | 2020 | 2020 BC |
+
+From my point of view, both pattern have their downsides. When using the `yyyy` pattern without adding information of the era you might get an output that will be interpreted wrong by a user. Imagine you have a mathematical bug in your software and calculate the year '-2019' as the final year of any contract. I would assume that it will be better to see '-2019' on screen/paper and recognize the error instead of '2020'.
+
+Another interesting point is that the result might be longer as the letter count in the `uuuu` pattern. As you can see in the table negative year numbers will have a `-` as a prefix when using the `uuuu` pattern. Based on this you can not trust the string length of a formatted date when using the `u` to format years.
+
+#### Other eras in Java
+
+Java supports different calendar systems next to the Gregorian Calendar. You can find a good example when having a look at the `JapaneseChronology` class that defines the 'Japanese Imperial calendar system' in Java. While I have absolutely no knowledge about that calendar system you can find out that is has several eras that are defined by the `JapaneseEra` class. This class contains several constants that define the eras of the calendar system:
+
+| name | meaning |
+| ------ | ------------------------------------------ |
+| MEIJI | The 'Meiji' era (1868-01-01 - 1912-07-29) |
+| TAISHO | The 'Taisho' era (1912-07-30 - 1926-12-24) |
+| SHOWA | The 'Showa' era (1926-12-25 - 1989-01-07) |
+| HEISEI | The 'Heisei' era (1989-01-08 - current) |
+
+When using the 'Japanese Imperial calendar system' Java offers some additional classes to define time information. The following code creates a date based on the calendar and prints it based on different format pattern strings:
+
+```javafinal JapaneseDate japaneseDate = JapaneseDate.of(JapaneseEra.MEIJI, 7, 3, 17);
+
+final String format1 = DateTimeFormatter.ofPattern("dd.MM.uuuu").format(japaneseDate);
+final String format2 = DateTimeFormatter.ofPattern("dd.MM.yyyy").format(japaneseDate);
+final String format3 = DateTimeFormatter.ofPattern("dd.MM.yyyy G").format(japaneseDate);
+
+System.out.println(format1); // prints '17.03.1874'
+System.out.println(format2); // prints '17.03.0007'
+System.out.println(format3); // prints '17.03.0007 Meiji'
```
+
+In this sample the usage between the two pattern `yyyy` and `uuuu` ends in a totally different result.
+
+## Conclusion
+
+Working with date and time information is always a complex topic. Normally people say that coding will become complex when timezone functionality is added. In the given examples we do not concern timezones at all and already found a lot of complex topics. All these topics can end in horrible bugs in business applications.
+
+For the initial problem, we can easily say that the `dd.MM.YYYY` pattern should never be used. If you want to use `dd.MM.yyyy` or `dd.MM.uuuu` in your application depends on your needs and how you want to visualize negative year information. Just saying that your application will never need to handle negative years is maybe not the best answer since we all just developers that create bugs from time to time ;)
diff --git a/content/posts/2020-02-21-adopt-tests.md b/content/posts/2020-02-21-adopt-tests.md
index 7992a426..85f73f8d 100644
--- a/content/posts/2020-02-21-adopt-tests.md
+++ b/content/posts/2020-02-21-adopt-tests.md
@@ -1,78 +1,76 @@
----
-outdated: true
-showInBlog: false
-title: 'How AdoptOpenJDK provides enterprise ready OpenJDK builds'
-date: "2020-02-21"
-author: hendrik
-excerpt: 'With the new licence of the Oracle JDK a lot of companies need to switch to a new JDK vendor.
-With AdoptOpenJDK we have a community based alternative that provides free LTS JDK builds. In this post
-I will have a deeper look at the infrastructure of the AdoptOpenJDK and how each build is tested to offer
-production ready quality.'
-categories: [Java, AdoptOpenJDK]
-preview_image: "/posts/preview-images/software-development-green.svg"
----
-
-While in theory, everybody can build it's own JDK based on the OpenJDK sources you normally don't want to do that. For several years people downloaded JDK builds from Oracle but based on the [new Licence for Oracle JDKs]({{< ref "/posts/2018-06-25-java-releases" >}}) this isn't that easy anymore. If you need an up-to-date Oracle JDK for production you need to buy commercial support from Oracle since last year.
-
-A lot of Linux users do not care about that problem since they used OpenJDK builds that were downloaded from an APT repository, for example. On Linux distributions like ubuntu you only need the following command to add a ready-to-use JDK installation to your system:
-
-{{< highlight shell >}}
-sudo apt-get install openjdk
-{{< / highlight >}}
-
-While this sounds like a really easy solution there are several points that you normally can not answer based on this approach:
-
-* You do not know who has built this JDK binary
-* You do not know if these binaries were built on the latest OpenJDK sources/tag
-* You do not know if and how these binaries were tested.
-
-While you can find answers to some of the questions it is not a trivial task for a regular user. Especially the last question can normally not be answered.
-
-## AdoptOpenJDK for the rescue
-
-With [AdoptOpenJDK](https://adoptopenjdk.net) an open source project exists that has the main goal to solve all the mentioned problems by providing open, free, and well tested builds of the OpenJDK. Since last year I'm part of the [AdoptOpenJDK technical steering committee (TSC)](https://github.com/AdoptOpenJDK/TSC#the-tsc). I'm really happy to be part of the team and with way over **150.000.000 downloads** I can say that the project is a great success and brings a really important benefit to the Java community. With AdoptOpenJDK binaries you have a really good alternative next to downloading (and paying for) Oracle Java. If you have more questions about AdoptOpenOpenJDK just ping me or ask us directly in the [AdoptOpenJDK Slack](https://adoptopenjdk.slack.com/).
-
-
-
-In this article, I will give an overview of the test infrastructure of AdoptOpenJDK and describe the different types of tests that will be executed for each release. All this ends in a well tested distribution that is ready to use for the enterprise.
-
-## Guide to the test jobs at AdoptOpenJDK
-
-For all nightly and release builds, test jobs are running as part of the [AdoptOpenJDK continuous delivery pipelines]((ci.adoptopenjdk.net)). For the test step of a build, all tests are grouped by its type. Currently, the tests of AdoptOpenJDK are split into 6 different groups/types. When running the test phase on our CI servers the defined groups will be executed in parallel. All these tests are defined in the open source test framework [**AQA** (AdoptOpenJDK Quality Assurance)](https://blog.adoptopenjdk.net/2019/07/the-first-drop-introducing-adoptopenjdk-quality-assurance-aqa-v1-0) that is provided by AdoptOpenJDK and can be found [here](https://github.com/AdoptOpenJDK/openjdk-tests). The following image shows the simplified pipeline of the AdoptOpenJDK builds and all the different test groups that are part of the test step in each build:
-
-
-
-Additional information about the test concept and the integration in the delivery pipeline can be found [at this blog post](https://blog.adoptopenjdk.net/2017/12/testing-java-help-count-ways).
-
-### Test groups
-
-As already mentioned all tests of AdoptOpenJDK are grouped based on its type in 6 different groups. The following table gives a first overview of the different test types:
-
- | name | Type | Description |
- | ---------- | ----------------------------- | ----------------------------------------------------- |
- | openjdk | OpenJDK regression tests | Tests from OpenJDK |
- | system | System and load tests | Tests from the AdoptOpenJDK/openjdk-systemtest repo |
- | external | 3rd party application tests | Test suites from a variety of applications, along with microprofile TCKs, run in Docker containers |
- | perf | Performance benchmark suites | Performance benchmark tests (both full suites and microbenches) from different open-source projects such as Acme-Air and AdoptOpenJDK/bumblebench |
- | functional | Unit and functional tests | Functional tests not originating from the openjdk regression suite, that include locale/language tests and a subset of implementation agnostic tests from the openj9 project. |
- | jck | Compliance tests | TCK tests (under the OpenJDK Community TCK License Agreement), in compliance with the license agreement. While this test material is currently not run at the AdoptOpenJDK project (see the [support statement](https://adoptopenjdk.net/support.html#jck) for details), those with their own OCTLA agreements may use the AdoptOpenJDK test automation infrastructure to execute their TCK test material in their own private Jenkins servers. |
-
-As you can see next to the OpenJDK tests we added a lot of additional tests. The OpenJDK regression tests are a great start to test a JDK, but eventually, you may want to be able to test the performance of your code, and whether some 3rd party applications still work. Here all the other test types come in play. This does not only add performance tests and additional general unit tests. Next to those, the test framework contains test suites from several big players from the Java ecosystem to directly check the accurate functionality of important frameworks with the AdoptOpenJDK builds. AQA for example executes tests from [11+ popular Java applications](https://github.com/AdoptOpenJDK/openjdk-tests/tree/master/external) including all tests from [Apache Tomcat](http://tomcat.apache.org) project and all TCKs (Test Compatibility Kit) of the [Eclipse MicroProfile](https://microprofile.io) on the popular frameworks available (OpenLiberty, Payara, Tomee, and Thorntail).
-
-### Bundling all tests with AQA
-
-While this first looks like an impressive mix of several tests that will be executed individually for each build the underlying AQA platform does much more. Since we do not want to run test suites one after each other and end in several different test reports AQA provides a thin platform. This platform provides thin wrappers around the different test modules and assembles all in a single huge test suite.
-
-By using AQA, new tests or complete suites of tests can easily be added to the project and since AQA is open source any other project can easily adopt it. To be true some JDK vendors already use AQA today to test the builds of their JDK distributions. Some of them even integrate the Java TCK in AQA. While AdoptOpenJDK currently does not run the Java TCK and has [no agreement with Oracle](https://adoptopenjdk.net/quality.html#jck), AQA already provides everything to simply integrate the TCK for those who wish to include it and have an OCLTA license for those closed test materials.
-
-As you can see every AdoptOpenJDK build runs through a ‘we test the hell out of it’ job ;) And the project won’t stop here. More and more tests will be added to make AQA the perfect test suite for any JDK build. In general, you can define the benefits of AQA like this:
-
-* better, more flexible tests, with the ability to apply certain types of testing to different builds
-* a common way to easily add, edit, group, include, exclude and execute tests on AdoptOpenJDK builds
-* the latitude to use a variety of tests that use many different test frameworks
-* test results to have a common look & feel for easier viewing and comparison
-* easily run all types of tests via make targets in various CI environments
-
-## Guide to running the tests yourself
-
-Thanks to AQA you can even run all the tests by yourself on your own system and test any OpenJDK distribution. As already mentioned several other companies that provide OpenJDK distributions already use AQA to get better test coverage and quality for their commercial OpenJDK distributions. For more details on how to run the same tests as AdoptOpenJDK on your laptop or in your build farm, please consult the [official user guide](https://github.com/AdoptOpenJDK/openjdk-tests/blob/master/doc/userGuide.md).
+---
+outdated: true
+showInBlog: false
+title: 'How AdoptOpenJDK provides enterprise ready OpenJDK builds'
+date: "2020-02-21"
+author: hendrik
+excerpt: 'With the new licence of the Oracle JDK a lot of companies need to switch to a new JDK vendor.
+With AdoptOpenJDK we have a community based alternative that provides free LTS JDK builds. In this post
+I will have a deeper look at the infrastructure of the AdoptOpenJDK and how each build is tested to offer
+production ready quality.'
+categories: [Java, AdoptOpenJDK]
+preview_image: "/posts/preview-images/software-development-green.svg"
+---
+
+While in theory, everybody can build it's own JDK based on the OpenJDK sources you normally don't want to do that. For several years people downloaded JDK builds from Oracle but based on the [new Licence for Oracle JDKs](/posts/2018-06-25-java-releases) this isn't that easy anymore. If you need an up-to-date Oracle JDK for production you need to buy commercial support from Oracle since last year.
+
+A lot of Linux users do not care about that problem since they used OpenJDK builds that were downloaded from an APT repository, for example. On Linux distributions like ubuntu you only need the following command to add a ready-to-use JDK installation to your system:
+
+```shellsudo apt-get install openjdk
```
+
+While this sounds like a really easy solution there are several points that you normally can not answer based on this approach:
+
+* You do not know who has built this JDK binary
+* You do not know if these binaries were built on the latest OpenJDK sources/tag
+* You do not know if and how these binaries were tested.
+
+While you can find answers to some of the questions it is not a trivial task for a regular user. Especially the last question can normally not be answered.
+
+## AdoptOpenJDK for the rescue
+
+With [AdoptOpenJDK](https://adoptopenjdk.net) an open source project exists that has the main goal to solve all the mentioned problems by providing open, free, and well tested builds of the OpenJDK. Since last year I'm part of the [AdoptOpenJDK technical steering committee (TSC)](https://github.com/AdoptOpenJDK/TSC#the-tsc). I'm really happy to be part of the team and with way over **150.000.000 downloads** I can say that the project is a great success and brings a really important benefit to the Java community. With AdoptOpenJDK binaries you have a really good alternative next to downloading (and paying for) Oracle Java. If you have more questions about AdoptOpenOpenJDK just ping me or ask us directly in the [AdoptOpenJDK Slack](https://adoptopenjdk.slack.com/).
+
+
+
+In this article, I will give an overview of the test infrastructure of AdoptOpenJDK and describe the different types of tests that will be executed for each release. All this ends in a well tested distribution that is ready to use for the enterprise.
+
+## Guide to the test jobs at AdoptOpenJDK
+
+For all nightly and release builds, test jobs are running as part of the [AdoptOpenJDK continuous delivery pipelines]((ci.adoptopenjdk.net)). For the test step of a build, all tests are grouped by its type. Currently, the tests of AdoptOpenJDK are split into 6 different groups/types. When running the test phase on our CI servers the defined groups will be executed in parallel. All these tests are defined in the open source test framework [**AQA** (AdoptOpenJDK Quality Assurance)](https://blog.adoptopenjdk.net/2019/07/the-first-drop-introducing-adoptopenjdk-quality-assurance-aqa-v1-0) that is provided by AdoptOpenJDK and can be found [here](https://github.com/AdoptOpenJDK/openjdk-tests). The following image shows the simplified pipeline of the AdoptOpenJDK builds and all the different test groups that are part of the test step in each build:
+
+
+
+Additional information about the test concept and the integration in the delivery pipeline can be found [at this blog post](https://blog.adoptopenjdk.net/2017/12/testing-java-help-count-ways).
+
+### Test groups
+
+As already mentioned all tests of AdoptOpenJDK are grouped based on its type in 6 different groups. The following table gives a first overview of the different test types:
+
+ | name | Type | Description |
+ | ---------- | ----------------------------- | ----------------------------------------------------- |
+ | openjdk | OpenJDK regression tests | Tests from OpenJDK |
+ | system | System and load tests | Tests from the AdoptOpenJDK/openjdk-systemtest repo |
+ | external | 3rd party application tests | Test suites from a variety of applications, along with microprofile TCKs, run in Docker containers |
+ | perf | Performance benchmark suites | Performance benchmark tests (both full suites and microbenches) from different open-source projects such as Acme-Air and AdoptOpenJDK/bumblebench |
+ | functional | Unit and functional tests | Functional tests not originating from the openjdk regression suite, that include locale/language tests and a subset of implementation agnostic tests from the openj9 project. |
+ | jck | Compliance tests | TCK tests (under the OpenJDK Community TCK License Agreement), in compliance with the license agreement. While this test material is currently not run at the AdoptOpenJDK project (see the [support statement](https://adoptopenjdk.net/support.html#jck) for details), those with their own OCTLA agreements may use the AdoptOpenJDK test automation infrastructure to execute their TCK test material in their own private Jenkins servers. |
+
+As you can see next to the OpenJDK tests we added a lot of additional tests. The OpenJDK regression tests are a great start to test a JDK, but eventually, you may want to be able to test the performance of your code, and whether some 3rd party applications still work. Here all the other test types come in play. This does not only add performance tests and additional general unit tests. Next to those, the test framework contains test suites from several big players from the Java ecosystem to directly check the accurate functionality of important frameworks with the AdoptOpenJDK builds. AQA for example executes tests from [11+ popular Java applications](https://github.com/AdoptOpenJDK/openjdk-tests/tree/master/external) including all tests from [Apache Tomcat](http://tomcat.apache.org) project and all TCKs (Test Compatibility Kit) of the [Eclipse MicroProfile](https://microprofile.io) on the popular frameworks available (OpenLiberty, Payara, Tomee, and Thorntail).
+
+### Bundling all tests with AQA
+
+While this first looks like an impressive mix of several tests that will be executed individually for each build the underlying AQA platform does much more. Since we do not want to run test suites one after each other and end in several different test reports AQA provides a thin platform. This platform provides thin wrappers around the different test modules and assembles all in a single huge test suite.
+
+By using AQA, new tests or complete suites of tests can easily be added to the project and since AQA is open source any other project can easily adopt it. To be true some JDK vendors already use AQA today to test the builds of their JDK distributions. Some of them even integrate the Java TCK in AQA. While AdoptOpenJDK currently does not run the Java TCK and has [no agreement with Oracle](https://adoptopenjdk.net/quality.html#jck), AQA already provides everything to simply integrate the TCK for those who wish to include it and have an OCLTA license for those closed test materials.
+
+As you can see every AdoptOpenJDK build runs through a ‘we test the hell out of it’ job ;) And the project won’t stop here. More and more tests will be added to make AQA the perfect test suite for any JDK build. In general, you can define the benefits of AQA like this:
+
+* better, more flexible tests, with the ability to apply certain types of testing to different builds
+* a common way to easily add, edit, group, include, exclude and execute tests on AdoptOpenJDK builds
+* the latitude to use a variety of tests that use many different test frameworks
+* test results to have a common look & feel for easier viewing and comparison
+* easily run all types of tests via make targets in various CI environments
+
+## Guide to running the tests yourself
+
+Thanks to AQA you can even run all the tests by yourself on your own system and test any OpenJDK distribution. As already mentioned several other companies that provide OpenJDK distributions already use AQA to get better test coverage and quality for their commercial OpenJDK distributions. For more details on how to run the same tests as AdoptOpenJDK on your laptop or in your build farm, please consult the [official user guide](https://github.com/AdoptOpenJDK/openjdk-tests/blob/master/doc/userGuide.md).
diff --git a/content/posts/2020-07-14-adopt-roadshow.md b/content/posts/2020-07-14-adopt-roadshow.md
index a2362a6a..7a8f6c04 100644
--- a/content/posts/2020-07-14-adopt-roadshow.md
+++ b/content/posts/2020-07-14-adopt-roadshow.md
@@ -12,7 +12,7 @@ preview_image: "/posts/preview-images/software-development-green.svg"
AdoptOpenJDK is doing a virtual roadshow of the Java User Groups.
We plan to reach as many groups as possible but we will also live stream the event on YouTube.
-{{< centered-image src="/posts/2020-07-14-adopt-roadshow/adopt-logo.png" width="50%" alt=">AdoptOpenJDK logo">}}
+
## Abstract of the session
AdoptOpenJDK is the leading provider of OpenJDK™ binaries.
diff --git a/content/posts/2023-02-07-logging-in-java-and-other-languages.md b/content/posts/2023-02-07-logging-in-java-and-other-languages.md
index 7c348a2a..a55bcf78 100644
--- a/content/posts/2023-02-07-logging-in-java-and-other-languages.md
+++ b/content/posts/2023-02-07-logging-in-java-and-other-languages.md
@@ -54,47 +54,42 @@ Care must be taken not to log information in a loop.
Even though user inputs are considered external inputs, one should not log every keystroke directly.
The following example shows an excerpt from a problematic log history where exactly this happened:
-{{< highlight log >}}
-08:34:23 User mutates id field with new value 'J'
+```log08:34:23 User mutates id field with new value 'J'
08:34:23 User mutates id field with new value 'JA'
08:34:23 User mutates id field with new value 'JAV'
08:34:23 User mutates id field with new value 'JAVA'
-{{< / highlight >}}
+```
One can easily imagine how difficult it becomes to extract important information from a log file with such entries.
The same applies to log messages that contain too much information.
Even if we know a user's birthday, we don't need to include this information in our log messages:
-{{< highlight log >}}
-08:34:23 User 'Max' with birthday '01/01/1970' \
+```log08:34:23 User 'Max' with birthday '01/01/1970' \
mutates id field with new value 'JAVA'
-{{< / highlight >}}
+```
While the username in the message can certainly be interesting for later analysis to relate this message to other log entries, the birthdate is rather distracting and makes reading the messages more complicated for the human eye.
A third important point to always keep in mind when creating log messages is data sensitivity.
While we have always seen the change of an ID in the log in the previous messages, the following message should never appear in a log file:
-{{< highlight log >}}
-08:34:23 User 'Max' mutates password with new value '12#Agj!j7
-{{< / highlight >}}
+```log08:34:23 User 'Max' mutates password with new value '12#Agj!j7
+```
In this case, logging would represent a real security vulnerability of the application.
Sensitive data such as the user's password should, of course, never be visible in log messages.
Based on the previous insights, the following log messages appear sensible and well-structured:
-{{< highlight log >}}
-08:34:23 User 'Max' mutates id field with new value 'JAVA'
+```log08:34:23 User 'Max' mutates id field with new value 'JAVA'
08:34:23 User 'Max' mutates password
-{{< / highlight >}}
+```
In addition to these tips, one should always ensure that the source code of an application is not so cluttered with log calls that the source code becomes unreadable and difficult to understand.
The following snippet from a Java program shows what happens when logging calls are overdone:
-{{< highlight java >}}
-LOG.log("We start the transaction");
+```javaLOG.log("We start the transaction");
manager.beginTransaction();
LOG.log("DB query will be executed");
LOG.log("DB query: select * from users");
@@ -105,16 +100,15 @@ LOG.log("DB query executed in " + (now() - start) + " ms");
LOG.log("Found " + users.size() + " entities");
manager.endTransaction();
LOG.log("Transaction done");
-{{< / highlight >}}
+```
Here, the code and its exact function are hardly recognizable.
Without the logging calls, we can understand it at a single glance:
-{{< highlight java >}}
-manager.beginTransaction();
+```javamanager.beginTransaction();
users = manager.query("select * from users");
manager.endTransaction();
-{{< / highlight >}}
+```
However, one should not completely omit logging, and perhaps this is exactly a place where one would like to see a lot of information in the logs.
In this case, logging calls must be cleverly integrated into the structure and API of the application.
@@ -124,8 +118,7 @@ This way, the business logic is cleaned of logging calls, and we still get all t
If it is not possible to place logging directly in the API for various reasons, complexity related to logging can also be relatively easily "hidden" in reusable lambdas or methods.
The following example shows a generic function that executes a query within a transaction and continues to provide all necessary information as log messages:
-{{< highlight java >}}
-final Function queryInTransaction = query -> {
+```javafinal Function queryInTransaction = query -> {
LOG.log("We start the transaction");
manager.beginTransaction();
LOG.log("DB query: " + query);
@@ -137,35 +130,33 @@ final Function queryInTransaction = query -> {
LOG.log("Transaction done");
return result;
}
-{{< / highlight >}}
+```
This allows us to call our operations in a readable form with maximum logging in the business logic:
-{{< highlight java >}}
-LOG.log("Loading all users from database");
+```javaLOG.log("Loading all users from database");
users = queryInTransaction("select * from users");
-{{< / highlight >}}
+```
Anyone who has ever worked with logging frameworks will certainly miss the logging level as an important and central element in the previous examples.
We will take a closer look at this to conclude.
Although different loggers do not always define the same levels, they all have the same functionality: on a one-dimensional scale, the level indicates how important the message is in the context of all messages.
-{{< centered-image src="/posts/2023-02-07-logging-in-java-and-other-languages/logging-level-scale.jpg" width="100%" showCaption="true" alt="The scale shows the logging levels.">}}
+
As shown in the example image, let's assume we can use three different levels in our logging (note: depending on the specific logging framework, there are several more).
At the `ERROR` level, we want to log all faulty behavior of the application, while we use the `INFO` level for general information about the application's process and status.
With the `DEBUG` level, we log detailed information that is only important in exceptional cases.
Java source code that uses the different levels in logging could look like this:
-{{< highlight java >}}
-try {
+```javatry {
LOG.info("Loading all users from database");
users = query("select * from users");
LOG.debug("Found " + users.size() + " users in db");
} catch (Exception e) {
LOG.error("Error while loading all users");
}
-{{< / highlight >}}
+```
At runtime, the logger's level can be configured to filter which messages should actually end up in the log.
Typically, messages at the `DEBUG` level are filtered out and only included in the log during error analysis or similar scenarios.
diff --git a/content/posts/2023-02-28-java-backwards-compatibility.md b/content/posts/2023-02-28-java-backwards-compatibility.md
index ac9e55d5..1c5d6874 100644
--- a/content/posts/2023-02-28-java-backwards-compatibility.md
+++ b/content/posts/2023-02-28-java-backwards-compatibility.md
@@ -25,7 +25,7 @@ The JCL includes all classes of the Java API that we work with every day, such a
But it also contains more exotic classes like `sun.misc.Unsafe`.
Together with the Java Virtual Machine (JVM) and various tools like the Java compiler (javac), the JCL defines the JDK for JavaSE that developers use daily.
-{{< centered-image src="/posts/2023-02-28-java-backwards-compatibility/java-structure.jpg" width="100%" showCaption="false" alt="Java Structure">}}
+
The private API of the JCL is on the classpath but should never be used directly by applications.
Internal changes in the OpenJDK are often implemented in this area, which could lead to potential changes in the interfaces of the private API.
@@ -39,7 +39,7 @@ However, this changed with Java 9 and the introduction of the module system.
The module system allows hiding APIs from the outside world, making them usable only within their own module.
This enabled the complete hiding of Java's private APIs.
-{{< centered-image src="/posts/2023-02-28-java-backwards-compatibility/java-modules.jpg" width="100%" showCaption="false" alt="Java Modules">}}
+
Since many programs and libraries used these private APIs, this change in Java 9 would have led to immense refactoring.
Therefore, the OpenJDK decided that the private APIs from Java 9 to Java 15 could still be used, with only a warning issued when software accesses private APIs.
@@ -60,10 +60,9 @@ For example, with Java 10, the Java language was extended with the use of `var`
This allows omitting the explicit type declaration for a variable when the compiler can infer it.
Here's an example:
-{{< highlight java >}}
-var list = new ArrayList(); // infers ArrayList
+```javavar list = new ArrayList(); // infers ArrayList
var stream = list.stream(); // infers Stream
-{{< / highlight >}}
+```
The introduction of `var` into the Java language had some implications.
Although `var` was not added as a keyword to the Java syntax, allowing it to still be used as a variable name, its status in the Java language is defined as a "Reserved Type Name" (see [JEP 286](https://openjdk.org/jeps/286)).
@@ -100,7 +99,7 @@ Here, all differences in the Java Class Library between two Java versions can be
Since not only versions with Long-term Support (LTS) are listed but all major releases since Java 1.0, you can start adapting your software even before a new LTS version of Java is released.
In addition to changes, the tool also shows all classes, functions, and other elements that have been annotated with `@Deprecated`.
-{{< centered-image src="/posts/2023-02-28-java-backwards-compatibility/java-new-apis.jpg" width="100%" showCaption="false" alt="New APIs in Java 17">}}
+
## What Does This Mean for Developers?
diff --git a/content/posts/2023-03-14-java-release-train.md b/content/posts/2023-03-14-java-release-train.md
index 9ba05006..ec3ca717 100644
--- a/content/posts/2023-03-14-java-release-train.md
+++ b/content/posts/2023-03-14-java-release-train.md
@@ -22,7 +22,7 @@ The following diagram shows the release date and lifecycle of Java 6, 7, and 8.
The lifecycle of the versions is defined by the availability of free security updates for the respective version.
Once there are no more free updates for a version, its lifecycle ends in the diagram.
-{{< centered-image src="/posts/2023-03-14-java-release-train/lifecycle.jpg" width="100%" showCaption="false" alt="Java Lifecycle">}}
+
In the diagram, you can see different points.
It is important to note that there is always a period during which at least two releases with security updates are supported.
@@ -60,11 +60,10 @@ Such APIs are in a special incubator package and are only moved to their correct
The preview status can be used to make new language features of the Java platform available in advance.
Such features must be activated via a command-line parameter:
-{{< highlight bash >}}
-$ javac HelloWorld.java
+```bash$ javac HelloWorld.java
$ javac --release 14 --enable-preview HelloWorld.java
$ java --enable-preview HelloWorld
-{{< / highlight >}}
+```
## Long-Term Support and Critical Patch Updates
@@ -85,7 +84,7 @@ Consequently, Java 21 will be the next LTS release in September 2023.
Based on these definitions, the release graph of Java versions since Java 9 looks as follows:
-{{< centered-image src="/posts/2023-03-14-java-release-train/releases.jpg" width="100%" showCaption="false" alt="Java Releases">}}
+
Since all work is done in OpenJDK, the release date of individual Java distributions may vary slightly.
Once the release is published in OpenJDK, the work to create the distributions like Eclipse Temurin, Oracle JDK, or Azul Zulu begins.
diff --git a/content/posts/2023-04-18-detect-null-errors-with-static-analysis.md b/content/posts/2023-04-18-detect-null-errors-with-static-analysis.md
index 290938bc..75f3175a 100644
--- a/content/posts/2023-04-18-detect-null-errors-with-static-analysis.md
+++ b/content/posts/2023-04-18-detect-null-errors-with-static-analysis.md
@@ -1,110 +1,102 @@
----
-outdated: false
-showInBlog: true
-title: "Detecting NullPointerExceptions with Static Code Analysis"
-date: 2023-04-18
-author: hendrik
-excerpt: "NullPointerExceptions are one of the most common sources of errors in Java. However, these errors can be significantly minimized through static code analysis. This post gives an overview of annotations can be used to handle 'null' in Java in a better way."
-categories: [Java]
-origin: https://www.heise.de/blog/Programmiersprache-Java-Null-Fehler-mit-statischer-Analyse-aufspueren-7351944.html
-preview_image: "/posts/preview-images/java-yellow.svg"
----
-
-New projects bring new challenges and new knowledge with them.
-[In my current project](https://github.com/hashgraph/hedera-services), I recently created a definition for handling null checks during static code analysis.
-For many on the project, it was important that parameters are not only checked at runtime, for example through `Objects.requireNonNull(...)`, but also directly during compilation.
-Therefore, we decided to also rely on static code analysis here to verify the handling of `null`.
-
-## Static Code Analysis
-
-Before we dive into the various annotation and checker libraries available for Java, let's briefly explain what static code analysis is.
-During compilation, the program code is checked by a tooling.
-The currently most popular tool in Java is probably SpotBugs, which can be integrated into builds with Maven or Gradle, and its results can also be automatically published on platforms like SonarCloud.
-With static code analysis, you can find problems such as buffer overflows, infinite loops, or "out of bounds" errors.
-A simple example is division by zero.
-If such a case occurs in the code, the analysis can provide a warning or, depending on the configuration, terminate the entire build with an error.
-In our project, we have such a check in GitHub Actions, which displays the results directly in [SonarCloud](https://sonarcloud.io/project/overview?id=com.hedera.hashgraph%3Ahedera-services) and a Pull Request.
-
-## Proper Handling of `null`
-
-One problem when programming with Java is certainly the handling of `null` values.
-While I personally clearly believe that `null` has its justification, even though Tony Hoare, the inventor of the `null` reference in programming, now refers to it as a "billion-dollar mistake".
-
-However, in Java, you cannot natively define whether a parameter is allowed to be `null`.
-This has been attempted to be solved through various means in the class library.
-Examples include `java.util.Optional`, `Objects.requireNonNull(...)`, or [JSR305](https://jcp.org/en/jsr/detail?id=305).
-
-An illustrative example of a programming language that has native support for null references is Kotlin.
-It explicitly distinguishes between nullable references and non-null references.
-The latter is the default, and a variable with such a reference can never be assigned null.
-If you need a variable that can include null, you must work with a nullable reference.
-This is indicated by the `?` character.
-The following code includes a Kotlin example for both references:
-
-{{< highlight java >}}
-var a: String = "abc" // Regular initialization means
- // non-null by default
-a = null // compilation error
-
-var b: String? = "abc" // can be set to null
-b = null // ok
-{{< / highlight >}}
-
-Since there is no such native support in Java, attempts are made to integrate it as best as possible through static code analysis.
-In general, two annotations are needed, one (`@Nullable`) defining that a value or variable can be null, and the other annotation defining that a value or variable must never be null (`@NonNull`).
-
-To understand this, let's look at a code example that defines a method and adds the information via annotation that the return value of the method can never be `null`:
-
-{{< highlight java >}}
-@NonNull String getName() {
- if(isUnique()) {
- return „Item „ + getId();
- } else {
- return null;
- }
-}
-{{< / highlight >}}
-
-As you can see in the implementation of the method, it is possible for it to return `null`.
-This would be a case where the static code analysis would show a violation.
-If desired, you can configure tools like IntelliJ to display such problems directly.
-
-The following code, which uses the `@Nullable` annotation, leads to a warning in the analysis:
-
-{{< highlight java >}}
-void check(@Nullable String value) {
- Objects.hash(value.toLowerCase());
-}
-{{< / highlight >}}
-
-In this example, the `@Nullable` annotation defines for the variable `value` that it can have the value `null`.
-However, the fact that the code directly accesses the variable potentially leads to a `NullPointerException` at runtime.
-This would also be evaluated by the static code analysis and reported as a problem.
-
-## Integrating Static Code Analysis into Your Project
-
-If you want to integrate such static code analysis into your own project, you need to meet a few simple prerequisites.
-First, you need to choose one or more analysis tools.
-Here, I recommend [SpotBugs](https://spotbugs.github.io/), which is the successor to FindBugs.
-The tool can be started either via the command line or integrated into a Gradle or Maven build.
-To analyze the problems found, you can either view them in the SpotBugs' own Swing client or, for example, as an HTML-based overview as part of a generated Maven site using the Maven `site` goal.
-You can configure the tool to upload the results, for example, to Sonar or SonarCloud.
-
-If you want to use `@Nullable` and `@NonNull` annotations in your project, you need a library that provides the annotation.
-Your own project only needs to depend on the library at compile time.
-Unfortunately, there is a plethora of libraries that provide annotations here as well.
-Examining the individual libraries based on their advantages and disadvantages will be the subject of its own post.
-Therefore, I initially recommend SpotBugs Annotations as a dependency, which you can find under the following Maven coordinates:
-
-{{< highlight xml >}}
-
- com.github.spotbugs
- spotbugs-annotations
- 4.7.3
-
-{{< / highlight >}}
-
-The abundance of tools and libraries unfortunately does not make it easy to find the perfect and future-oriented combination.
-When I delved deeper into the topic, I was shocked that much in this area is still not defined by standards or generally used best practices.
-While there have been various approaches such as [JSR305](https://jcp.org/en/jsr/detail?id=305), these have always run aground at some point and are now used in a wild mix.
+---
+outdated: false
+showInBlog: true
+title: "Detecting NullPointerExceptions with Static Code Analysis"
+date: 2023-04-18
+author: hendrik
+excerpt: "NullPointerExceptions are one of the most common sources of errors in Java. However, these errors can be significantly minimized through static code analysis. This post gives an overview of annotations can be used to handle 'null' in Java in a better way."
+categories: [Java]
+origin: https://www.heise.de/blog/Programmiersprache-Java-Null-Fehler-mit-statischer-Analyse-aufspueren-7351944.html
+preview_image: "/posts/preview-images/java-yellow.svg"
+---
+
+New projects bring new challenges and new knowledge with them.
+[In my current project](https://github.com/hashgraph/hedera-services), I recently created a definition for handling null checks during static code analysis.
+For many on the project, it was important that parameters are not only checked at runtime, for example through `Objects.requireNonNull(...)`, but also directly during compilation.
+Therefore, we decided to also rely on static code analysis here to verify the handling of `null`.
+
+## Static Code Analysis
+
+Before we dive into the various annotation and checker libraries available for Java, let's briefly explain what static code analysis is.
+During compilation, the program code is checked by a tooling.
+The currently most popular tool in Java is probably SpotBugs, which can be integrated into builds with Maven or Gradle, and its results can also be automatically published on platforms like SonarCloud.
+With static code analysis, you can find problems such as buffer overflows, infinite loops, or "out of bounds" errors.
+A simple example is division by zero.
+If such a case occurs in the code, the analysis can provide a warning or, depending on the configuration, terminate the entire build with an error.
+In our project, we have such a check in GitHub Actions, which displays the results directly in [SonarCloud](https://sonarcloud.io/project/overview?id=com.hedera.hashgraph%3Ahedera-services) and a Pull Request.
+
+## Proper Handling of `null`
+
+One problem when programming with Java is certainly the handling of `null` values.
+While I personally clearly believe that `null` has its justification, even though Tony Hoare, the inventor of the `null` reference in programming, now refers to it as a "billion-dollar mistake".
+
+However, in Java, you cannot natively define whether a parameter is allowed to be `null`.
+This has been attempted to be solved through various means in the class library.
+Examples include `java.util.Optional`, `Objects.requireNonNull(...)`, or [JSR305](https://jcp.org/en/jsr/detail?id=305).
+
+An illustrative example of a programming language that has native support for null references is Kotlin.
+It explicitly distinguishes between nullable references and non-null references.
+The latter is the default, and a variable with such a reference can never be assigned null.
+If you need a variable that can include null, you must work with a nullable reference.
+This is indicated by the `?` character.
+The following code includes a Kotlin example for both references:
+
+```javavar a: String = "abc" // Regular initialization means
+ // non-null by default
+a = null // compilation error
+
+var b: String? = "abc" // can be set to null
+b = null // ok
```
+
+Since there is no such native support in Java, attempts are made to integrate it as best as possible through static code analysis.
+In general, two annotations are needed, one (`@Nullable`) defining that a value or variable can be null, and the other annotation defining that a value or variable must never be null (`@NonNull`).
+
+To understand this, let's look at a code example that defines a method and adds the information via annotation that the return value of the method can never be `null`:
+
+```java@NonNull String getName() {
+ if(isUnique()) {
+ return „Item „ + getId();
+ } else {
+ return null;
+ }
+}
```
+
+As you can see in the implementation of the method, it is possible for it to return `null`.
+This would be a case where the static code analysis would show a violation.
+If desired, you can configure tools like IntelliJ to display such problems directly.
+
+The following code, which uses the `@Nullable` annotation, leads to a warning in the analysis:
+
+```javavoid check(@Nullable String value) {
+ Objects.hash(value.toLowerCase());
+}
```
+
+In this example, the `@Nullable` annotation defines for the variable `value` that it can have the value `null`.
+However, the fact that the code directly accesses the variable potentially leads to a `NullPointerException` at runtime.
+This would also be evaluated by the static code analysis and reported as a problem.
+
+## Integrating Static Code Analysis into Your Project
+
+If you want to integrate such static code analysis into your own project, you need to meet a few simple prerequisites.
+First, you need to choose one or more analysis tools.
+Here, I recommend [SpotBugs](https://spotbugs.github.io/), which is the successor to FindBugs.
+The tool can be started either via the command line or integrated into a Gradle or Maven build.
+To analyze the problems found, you can either view them in the SpotBugs' own Swing client or, for example, as an HTML-based overview as part of a generated Maven site using the Maven `site` goal.
+You can configure the tool to upload the results, for example, to Sonar or SonarCloud.
+
+If you want to use `@Nullable` and `@NonNull` annotations in your project, you need a library that provides the annotation.
+Your own project only needs to depend on the library at compile time.
+Unfortunately, there is a plethora of libraries that provide annotations here as well.
+Examining the individual libraries based on their advantages and disadvantages will be the subject of its own post.
+Therefore, I initially recommend SpotBugs Annotations as a dependency, which you can find under the following Maven coordinates:
+
+```xml
+ com.github.spotbugs
+ spotbugs-annotations
+ 4.7.3
+
```
+
+The abundance of tools and libraries unfortunately does not make it easy to find the perfect and future-oriented combination.
+When I delved deeper into the topic, I was shocked that much in this area is still not defined by standards or generally used best practices.
+While there have been various approaches such as [JSR305](https://jcp.org/en/jsr/detail?id=305), these have always run aground at some point and are now used in a wild mix.
Therefore, I will also dedicate a separate post to this problem in the near future.
\ No newline at end of file
diff --git a/content/posts/2023-05-09-java-module-system.md b/content/posts/2023-05-09-java-module-system.md
index 2012d534..a10c7983 100644
--- a/content/posts/2023-05-09-java-module-system.md
+++ b/content/posts/2023-05-09-java-module-system.md
@@ -1,68 +1,66 @@
----
-outdated: false
-showInBlog: true
-title: "Java's Module System: Help, My Dependencies Are Not Java Modules!"
-date: 2023-05-09
-author: hendrik
-excerpt: "With Java, you can now modularize applications quite well, but you also have to consider dependencies. When these are not Java modules, it gets interesting. In this post you can learn more about the Java module system and how it can be used in your projects."
-categories: [Java]
-origin: https://www.heise.de/blog/Javas-Modulsystem-Hilfe-meine-Abhaengigkeiten-sind-keine-Java-Module-7536607.html
-preview_image: "/posts/preview-images/java-2-green.svg"
----
-
-In a [previous post](https://open-elements.com/posts/2024/01/11/software-development-minimal-support-for-the-java-module-system/), I wrote about minimal support for the Java Module System (Java Platform Module System, JPMS) and how you can help achieve it.
-However, it can always happen that libraries do not support the Java module system, and it is also not foreseeable that they will be available as "automatic modules" in the future.
-
-If you want to migrate your own code to JPMS and depend on such libraries, you sometimes have to resort to tricks.
-In this post, I would like to address precisely such dependencies and see how you can deal with them.
-
-## Gradle Plugin as a Remedy
-
-Although I feel more at home with Maven, I recently worked on migrating a large Gradle project to Java modules.
-Since the project is open source, it can be easily [viewed on GitHub](https://github.com/hashgraph/hedera-services).
-At the beginning of the migration, this project had a multitude of dependencies that did not support the Java module system.
-For some, we were able to achieve a sustainable solution by creating direct pull requests (PRs) at the respective projects to add an `Automatic-Module-Name`.
-I have already described in the [previous post on this topic](https://open-elements.com/posts/2024/01/11/software-development-minimal-support-for-the-java-module-system/) how you can easily achieve this using a Maven or Gradle plugin.
-An example of such a PR can be found [here](https://github.com/offbynull/portmapper/pull/48).
-
-However, there are also dependencies for which you cannot simply create such a PR or where the PR is not accepted.
-Perhaps you also have a dependency whose further development has been discontinued.
-In all these cases, a different implementation is needed.
-Basically, you have to take care of creating Java modules from the dependencies yourself.
-There are different ways to do this.
-For example, you can manually add an `Automatic-Module-Name` entry to the manifest of the JAR and then host the modified version in an internal Maven repository.
-For the mentioned Gradle project, we fell back on the "extra-java-module-info" plugin by Jendrik Johannes.
-This [open-source plugin](https://github.com/gradlex-org/extra-java-module-info) allows you to add an `Automatic-Module-Name` entry to dependencies at build time.
-Specifically, the plugin is used as in the following example, where for each `automaticModule(...)` call, the Gradle identifier of the dependency is passed as the first parameter and the module name to be used as the second parameter:
-
-{{< highlight java >}}
-plugins {
- id("org.gradlex.extra-java-module-info")
-}
-
-extraJavaModuleInfo {
- failOnMissingModuleInfo.set(true)
-
- automaticModule("io.prometheus:simpleclient",
- "io.prometheus.simpleclient")
- automaticModule("io.prometheus:simpleclient_common",
- "io.prometheus.simpleclient_common")
- automaticModule("io.prometheus:simpleclient_httpserver",
- "io.prometheus.simpleclient.httpserver")
-}
-{{< / highlight >}}
-
-Together with the author of the plugin, we were even able to significantly extend it in a very productive exchange.
-In addition to automatic modules, the plugin has always been able to create modules with a `module-info.java`.
-However, you had to manually define things like exports.
-Thanks to new functionalities, you can now define a module so that its complete packages are exported ([see further info](https://github.com/gradlex-org/extra-java-module-info/issues/38)).
-This has the great advantage that you do not have to work with automatic modules, which bring some peculiarities with them, since, among other things, all automatic modules are added to the "required" dependencies of a module as soon as an automatic module is specified as "required" in the `module-info.java` (see [Java spec](https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#jls-7.7.1)).
-Once again, a big thank you to Jendrik Johannes as the maintainer of the library.
-Our collaboration has, in my opinion, extremely well demonstrated the advantages of open source.
-For anyone who wants to go deeper into this topic, Jendrik has hosted several videos on this and other topics around Gradle for free [on YouTube](https://www.youtube.com/@jjohannes).
-
-## One Problem Remains
-
-However, one last major problem cannot be solved even with the implementations presented here: As soon as a JAR violates the package split constraints of the Java module system, it cannot be added to the module path.
-In this case, much more far-reaching steps must be taken.
+---
+outdated: false
+showInBlog: true
+title: "Java's Module System: Help, My Dependencies Are Not Java Modules!"
+date: 2023-05-09
+author: hendrik
+excerpt: "With Java, you can now modularize applications quite well, but you also have to consider dependencies. When these are not Java modules, it gets interesting. In this post you can learn more about the Java module system and how it can be used in your projects."
+categories: [Java]
+origin: https://www.heise.de/blog/Javas-Modulsystem-Hilfe-meine-Abhaengigkeiten-sind-keine-Java-Module-7536607.html
+preview_image: "/posts/preview-images/java-2-green.svg"
+---
+
+In a [previous post](https://open-elements.com/posts/2024/01/11/software-development-minimal-support-for-the-java-module-system/), I wrote about minimal support for the Java Module System (Java Platform Module System, JPMS) and how you can help achieve it.
+However, it can always happen that libraries do not support the Java module system, and it is also not foreseeable that they will be available as "automatic modules" in the future.
+
+If you want to migrate your own code to JPMS and depend on such libraries, you sometimes have to resort to tricks.
+In this post, I would like to address precisely such dependencies and see how you can deal with them.
+
+## Gradle Plugin as a Remedy
+
+Although I feel more at home with Maven, I recently worked on migrating a large Gradle project to Java modules.
+Since the project is open source, it can be easily [viewed on GitHub](https://github.com/hashgraph/hedera-services).
+At the beginning of the migration, this project had a multitude of dependencies that did not support the Java module system.
+For some, we were able to achieve a sustainable solution by creating direct pull requests (PRs) at the respective projects to add an `Automatic-Module-Name`.
+I have already described in the [previous post on this topic](https://open-elements.com/posts/2024/01/11/software-development-minimal-support-for-the-java-module-system/) how you can easily achieve this using a Maven or Gradle plugin.
+An example of such a PR can be found [here](https://github.com/offbynull/portmapper/pull/48).
+
+However, there are also dependencies for which you cannot simply create such a PR or where the PR is not accepted.
+Perhaps you also have a dependency whose further development has been discontinued.
+In all these cases, a different implementation is needed.
+Basically, you have to take care of creating Java modules from the dependencies yourself.
+There are different ways to do this.
+For example, you can manually add an `Automatic-Module-Name` entry to the manifest of the JAR and then host the modified version in an internal Maven repository.
+For the mentioned Gradle project, we fell back on the "extra-java-module-info" plugin by Jendrik Johannes.
+This [open-source plugin](https://github.com/gradlex-org/extra-java-module-info) allows you to add an `Automatic-Module-Name` entry to dependencies at build time.
+Specifically, the plugin is used as in the following example, where for each `automaticModule(...)` call, the Gradle identifier of the dependency is passed as the first parameter and the module name to be used as the second parameter:
+
+```javaplugins {
+ id("org.gradlex.extra-java-module-info")
+}
+
+extraJavaModuleInfo {
+ failOnMissingModuleInfo.set(true)
+
+ automaticModule("io.prometheus:simpleclient",
+ "io.prometheus.simpleclient")
+ automaticModule("io.prometheus:simpleclient_common",
+ "io.prometheus.simpleclient_common")
+ automaticModule("io.prometheus:simpleclient_httpserver",
+ "io.prometheus.simpleclient.httpserver")
+}
```
+
+Together with the author of the plugin, we were even able to significantly extend it in a very productive exchange.
+In addition to automatic modules, the plugin has always been able to create modules with a `module-info.java`.
+However, you had to manually define things like exports.
+Thanks to new functionalities, you can now define a module so that its complete packages are exported ([see further info](https://github.com/gradlex-org/extra-java-module-info/issues/38)).
+This has the great advantage that you do not have to work with automatic modules, which bring some peculiarities with them, since, among other things, all automatic modules are added to the "required" dependencies of a module as soon as an automatic module is specified as "required" in the `module-info.java` (see [Java spec](https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#jls-7.7.1)).
+Once again, a big thank you to Jendrik Johannes as the maintainer of the library.
+Our collaboration has, in my opinion, extremely well demonstrated the advantages of open source.
+For anyone who wants to go deeper into this topic, Jendrik has hosted several videos on this and other topics around Gradle for free [on YouTube](https://www.youtube.com/@jjohannes).
+
+## One Problem Remains
+
+However, one last major problem cannot be solved even with the implementations presented here: As soon as a JAR violates the package split constraints of the Java module system, it cannot be added to the module path.
+In this case, much more far-reaching steps must be taken.
However, I will address this point in a future post.
\ No newline at end of file
diff --git a/content/posts/2023-06-22-logging-facades-for-java.md b/content/posts/2023-06-22-logging-facades-for-java.md
index 8fee0461..2296619e 100644
--- a/content/posts/2023-06-22-logging-facades-for-java.md
+++ b/content/posts/2023-06-22-logging-facades-for-java.md
@@ -16,8 +16,7 @@ Problems often arise in this area between different logging frameworks, and cons
To better understand the issue, I'll start with a very simple example, almost the "Hello World" of logging.
The following code shows a minimal Java application that simply logs a message:
-{{< highlight java >}}
-public class HelloLogging {
+```javapublic class HelloLogging {
private static final Logger LOG = Logger.getLogger("HelloLogging");
@@ -25,12 +24,12 @@ public class HelloLogging {
LOG.info("Hello World");
}
}
-{{< / highlight >}}
+```
Even in this trivial application, logging can be configured through the features of the logging framework, in this example `java.util.Logging` (JUL), and output to a file or the console (shell).
The following diagram shows the structure and configuration of logging in a schematic layout.
-{{< centered-image src="/posts/2023-06-22-logging-facades-for-java/structure-logging.jpg" width="100%" showCaption="false" alt="Logging Structure">}}
+
## A Realistic Scenario
@@ -40,14 +39,14 @@ Since the developers of these libraries also want to output information about it
However, these libraries do not use `java.util.Logging`, but rather other logging libraries.
As you can see in the following diagram, we assume that [Log4J2](https://logging.apache.org/log4j/2.x/) and [Logback](https://github.com/qos-ch/logback) are in use.
-{{< centered-image src="/posts/2023-06-22-logging-facades-for-java/application-logging.jpg" width="100%" showCaption="false" alt="Log4J2 and Logback Structure">}}
+
Now we have the problem that the logging of our application is handled by three different logging frameworks.
Although Log4J and Logback also offer enough configuration options, since the logging frameworks do not synchronize with each other, it would be a really dumb idea to have all frameworks write to the same file.
It can happen that several of the frameworks write to the same line, resulting in an unreadable jumble of randomly strung together text snippets or even deadlocks.
Another idea is to have each framework log to its own file, as indicated in the following diagram.
-{{< centered-image src="/posts/2023-06-22-logging-facades-for-java/extended-application-logging.jpg" width="100%" showCaption="false" alt="File Per Framework Structure">}}
+
This setup causes the loggings to act completely independently of each other and not get in each other's way.
This results in clean logging, but it is distributed across multiple files that you have to synchronize manually or with the help of tools.
@@ -63,8 +62,7 @@ SLF4J provides a logging API that comes as a single dependency without transitiv
The API can be used in this case to generate concrete log calls in the code.
The following code shows a "Hello World" logging example:
-{{< highlight java >}}
-import org.slf4j.Logger;
+```javaimport org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloLogging {
@@ -76,7 +74,7 @@ public class HelloLogging {
logger.info("Hello World!");
}
}
-{{< / highlight >}}
+```
Looking at this code alone, one might wonder what advantages SLF4J offers over classic Java logging.
One of the most important points is that `org.slf4j.Logger` is an interface.
@@ -91,7 +89,7 @@ Such bindings are not needed at compile time and can therefore be specified as a
Since SLF4J internally uses the Java SPI, no code needs to be adapted to use the concrete logging implementation.
We can now use this feature for our sample application:
-{{< centered-image src="/posts/2023-06-22-logging-facades-for-java/example-application-logging.jpg" width="100%" showCaption="false" alt="Example Application Structure">}}
+
In the diagram, Log4J2 is used as the logging implementation, and by adding a suitable binding, all log messages created via the `org.slf4j.Logger` logger are automatically forwarded to Log4J2.
Since in this example our "Database lib" dependency apparently also uses Log4J2, the messages from different internal and external modules are thus handled directly via Log4J2.
@@ -104,18 +102,17 @@ There are completely different implementation approaches for such adapters depen
While SLF4J offers some of these adapters, they are also sometimes provided directly by the logging frameworks.
For Log4J2, for example, the following dependency must be added if you want to forward messages from Log4J2 to SLF4J:
-{{< highlight xml >}}
-org.apache.logging.log4j
+```xmlorg.apache.logging.log4jlog4j-to-slf4j
-{{< / highlight >}}
+```
By adding this dependency, which you should preferably only add to the runtime classpath, a logging flow is created as shown in the following diagram:
-{{< centered-image src="/posts/2023-06-22-logging-facades-for-java/history-logging.jpg" width="100%" showCaption="false" alt="Logging History">}}
+
SLF4J provides a good overview of the integration through bindings and adapters for various logging libraries [on their website](https://www.slf4j.org/legacy.html).
If we now look at our sample application based on these findings, we can achieve our goal by adding an adapter for Logback.
As shown in the following diagram, all log messages of the entire system are routed via Log4J2, and we thus have the advantage that we only have to document one central location.
-{{< centered-image src="/posts/2023-06-22-logging-facades-for-java/central-logging.jpg" width="100%" showCaption="false" alt="Central Logging">}}
\ No newline at end of file
+
\ No newline at end of file
diff --git a/content/posts/2023-08-03-distributions-and-support-without-oracle.md b/content/posts/2023-08-03-distributions-and-support-without-oracle.md
index 3f0df665..718f0a35 100644
--- a/content/posts/2023-08-03-distributions-and-support-without-oracle.md
+++ b/content/posts/2023-08-03-distributions-and-support-without-oracle.md
@@ -31,7 +31,7 @@ With [over 200 million downloads](https://dash.adoptium.net/), no other Java dis
This is [underscored by a recent Gartner report](https://www.gartner.com/en/documents/4540799), which predicts that by 2026, over 80% of all Java applications will not run on an Oracle distribution.
Eclipse Temurin will likely take the largest share of this market.
-{{< centered-image src="/posts/2023-08-03-distributions-and-support-without-oracle/distributions.jpg" width="100%" showCaption="false" alt="Distributions Java">}}
+
## Java Support
@@ -50,7 +50,7 @@ Therefore, now might be the right time to look at alternative Java support offer
Organizations like Azul and the Eclipse Adoptium working group have responded to these events.
Mike Milinkovich, the Executive Director of the [Eclipse Foundation](https://www.eclipse.org/), commented on the situation on X / Twitter:
-{{< centered-image src="/posts/2023-08-03-distributions-and-support-without-oracle/tweet.jpg" width="100%" showCaption="true" alt="(Picture: Twitter / X)">}}
+
But beyond this comment, Adoptium has also taken action and set up a page for [commercial support for Eclipse Temurin](https://adoptium.net/temurin/commercial-support/).
On this page, support for Eclipse Temurin is offered by three industry experts: Red Hat, IBM, and Open Elements.
diff --git a/content/posts/2024-01-11-java-module-system.md b/content/posts/2024-01-11-java-module-system.md
index bdc6a865..ee5fe86d 100644
--- a/content/posts/2024-01-11-java-module-system.md
+++ b/content/posts/2024-01-11-java-module-system.md
@@ -1,70 +1,66 @@
----
-outdated: false
-showInBlog: true
-title: "Minimal Support for the Java Module System"
-date: 2024-01-11
-author: hendrik
-excerpt: "The Java Module System remains an underutilized feature in the development of applications and libraries, despite its often straightforward entry point. Anyway, more and more libraries provide support for the module system. Based on that it might make sense to learn how you can add support to your project."
-categories: [Java]
-origin: https://www.heise.de/blog/Softwareentwicklung-Minimale-Unterstuetzung-fuer-das-Java-Modulsystem-7434695.html
-preview_image: "/posts/preview-images/java-blue.svg"
----
-
-Over the past few years, there have been many differing opinions about the Java Module System.
-While many developers are positive about the standardized way to define modules, there are also critical voices pointing out missing features, such as version support.
-However, I do not intend to delve into this debate here.
-Personally, I see many advantages in the module system and understand why framework and library developers would (want to) use it.
-
-One major drawback is that a (transitive) dependency that is not adapted to the Java Module System may not fit the definitions and constraints of the module system and thus cannot be added to the module path.
-The Java Module System automatically creates a module for each JAR it finds on the module path.
-This can lead to some issues, which can often be resolved with minor adjustments in a library.
-
-In several posts, I will take a closer look at these problems and suggest possible solutions.
-This post focuses on the use and definition of automatic modules.
-
-## Implementing Modules as Automatic Modules
-
-A key definition of the module system is that each module requires a unique name.
-There is a distinction between explicitly declared modules, which have a `module-info.java`, and automatic modules, which are implicitly declared.
-More information can be found in the [Java SE Spec](https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#jls-7.7.1).
-If you do not want to leverage the benefits of the module system by using a `module-info.java` in your project, it is sufficient to define your library as an automatic module.
-
-The only requirement is that the module has a unique name.
-Although Java can extract a name from the JAR file name if necessary, this is not recommended.
-Defining a name for an automatic module is very simple.
-You only need to define the `Automatic-Module-Name` property in the `MANIFEST.MF` of the JAR.
-If you use Maven or Gradle as your build tool, you can even automate this process with a plugin.
-
-As shown in the following example, you only need to configure the maven-jar-plugin for a Maven build:
-
-{{< highlight xml >}}
-
- org.apache.maven.plugins
- maven-jar-plugin
- 3.3.0
-
-
-
- com.example.lib
-
-
-
-
-{{< / highlight >}}
-
-In Gradle, you can achieve this by using the Java Library Plugin, which should be part of every Java build.
-Detailed documentation for using Gradle can be found [here](https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_modular_auto), while the following code shows a simple integration into a project:
-
-{{< highlight java >}}
-tasks.jar {
- manifest {
- attributes("Automatic-Module-Name" to "com.example.lib")
- }
-}
-{{< / highlight >}}
-
-## Next Steps
-
-Since these changes are very simple, they are also ideal for offering as a pull request for open-source libraries.
-[In one example](https://github.com/offbynull/portmapper/pull/48), I added a PR to define an `Automatic-Module-Name` to an open-source Java library.
+---
+outdated: false
+showInBlog: true
+title: "Minimal Support for the Java Module System"
+date: 2024-01-11
+author: hendrik
+excerpt: "The Java Module System remains an underutilized feature in the development of applications and libraries, despite its often straightforward entry point. Anyway, more and more libraries provide support for the module system. Based on that it might make sense to learn how you can add support to your project."
+categories: [Java]
+origin: https://www.heise.de/blog/Softwareentwicklung-Minimale-Unterstuetzung-fuer-das-Java-Modulsystem-7434695.html
+preview_image: "/posts/preview-images/java-blue.svg"
+---
+
+Over the past few years, there have been many differing opinions about the Java Module System.
+While many developers are positive about the standardized way to define modules, there are also critical voices pointing out missing features, such as version support.
+However, I do not intend to delve into this debate here.
+Personally, I see many advantages in the module system and understand why framework and library developers would (want to) use it.
+
+One major drawback is that a (transitive) dependency that is not adapted to the Java Module System may not fit the definitions and constraints of the module system and thus cannot be added to the module path.
+The Java Module System automatically creates a module for each JAR it finds on the module path.
+This can lead to some issues, which can often be resolved with minor adjustments in a library.
+
+In several posts, I will take a closer look at these problems and suggest possible solutions.
+This post focuses on the use and definition of automatic modules.
+
+## Implementing Modules as Automatic Modules
+
+A key definition of the module system is that each module requires a unique name.
+There is a distinction between explicitly declared modules, which have a `module-info.java`, and automatic modules, which are implicitly declared.
+More information can be found in the [Java SE Spec](https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#jls-7.7.1).
+If you do not want to leverage the benefits of the module system by using a `module-info.java` in your project, it is sufficient to define your library as an automatic module.
+
+The only requirement is that the module has a unique name.
+Although Java can extract a name from the JAR file name if necessary, this is not recommended.
+Defining a name for an automatic module is very simple.
+You only need to define the `Automatic-Module-Name` property in the `MANIFEST.MF` of the JAR.
+If you use Maven or Gradle as your build tool, you can even automate this process with a plugin.
+
+As shown in the following example, you only need to configure the maven-jar-plugin for a Maven build:
+
+```xml
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.3.0
+
+
+
+ com.example.lib
+
+
+
+
```
+
+In Gradle, you can achieve this by using the Java Library Plugin, which should be part of every Java build.
+Detailed documentation for using Gradle can be found [here](https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_modular_auto), while the following code shows a simple integration into a project:
+
+```javatasks.jar {
+ manifest {
+ attributes("Automatic-Module-Name" to "com.example.lib")
+ }
+}
```
+
+## Next Steps
+
+Since these changes are very simple, they are also ideal for offering as a pull request for open-source libraries.
+[In one example](https://github.com/offbynull/portmapper/pull/48), I added a PR to define an `Automatic-Module-Name` to an open-source Java library.
Perhaps an open-source developer is reading this and will create a "Good First Issue" for such a change to their libraries, which could be implemented by newcomers during events like [Hacktoberfest](https://hacktoberfest.com/).
\ No newline at end of file
diff --git a/content/posts/2024-01-18-performance-of-java-logging.md b/content/posts/2024-01-18-performance-of-java-logging.md
index 73c47f28..c4e9e9a8 100644
--- a/content/posts/2024-01-18-performance-of-java-logging.md
+++ b/content/posts/2024-01-18-performance-of-java-logging.md
@@ -22,15 +22,14 @@ Among other things, you can set whether the code should run several times for a
These and other parameters can be easily defined in JMH using annotations, similar to JUnit.
A simple example of a benchmark looks like this:
-{{< highlight java >}}
-@Benchmark
+```java@Benchmark
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 4, time = 4)
@Measurement(iterations = 4, time = 4)
public void runSingleSimpleLog() {
logger.log("Hello World");
}
-{{< / highlight >}}
+```
The example performs four warm-up runs, followed by four measurement runs.
Each run lasts four seconds, and the measurement result shows how many operations per second could be performed.
@@ -59,7 +58,7 @@ On the other hand, however, they also brought to light a few insights that are c
The following is an overview of measurement results for simple logging of a "Hello World" message:
-{{< centered-image src="/posts/2024-01-18-performance-of-java-logging/measure-logging.jpg" width="100%" showCaption="false" alt="Measurement Results">}}
+
## The Problem with the Console
@@ -74,13 +73,13 @@ Another big difference can be seen when looking at the measurement values for sy
Here it immediately becomes clear that asynchronous logging is significantly faster.
The following tables show the measurement values of asynchronous logging compared to synchronous logging:
-{{< centered-image src="/posts/2024-01-18-performance-of-java-logging/measure-comparision-logging.jpg" width="100%" showCaption="false" alt="Measurement Comparision">}}
+
The clearly higher performance is due to the fact that the write operation of the asynchronous loggers does not block.
The Log4J2 and Chronicle Logger loggers use different libraries internally, but both are based on a "lock-free inter-thread communication library".
While [LMAX Disruptor](https://github.com/LMAX-Exchange/disruptor) has to be added as a library for Log4J, which internally enables asynchronous logging via ring buffers, the Chronicle Logger is directly based on the [Chronicle Queue library](https://github.com/OpenHFT/Chronicle-Queue).
-{{< centered-image src="/posts/2024-01-18-performance-of-java-logging/synchronous-asynchronous-logging.jpg" width="100%" showCaption="false" alt="Synchronous-Asynchronous Logging">}}
+
A concrete description of the internally used libraries and how they enable asynchronous communication or writing to the file system can be found in the documentation.
@@ -92,7 +91,7 @@ As a reason, I suspect that the used Chronicle Queue manages the binary data for
However, this still needs to be further investigated.
The following table shows an overview of the variance:
-{{< centered-image src="/posts/2024-01-18-performance-of-java-logging/variance-logging-performance.jpg" width="100%" showCaption="false" alt="Overview Variance">}}
+
## Conclusion
@@ -101,4 +100,3 @@ While console logging is certainly very convenient during development, you might
It also shows that the use of asynchronous loggers can make sense if the performance of the system is really critical.
Of course, this comes with higher complexity and additional transitive dependencies.
Ultimately, each project must still decide for itself which logger is most sensible.
-However, with the figures mentioned here, you now have another basis for determining this.
\ No newline at end of file
diff --git a/content/posts/2024-01-20-open-elements-2023.de.md b/content/posts/2024-01-20-open-elements-2023.de.md
index a4b91016..6b7585bc 100644
--- a/content/posts/2024-01-20-open-elements-2023.de.md
+++ b/content/posts/2024-01-20-open-elements-2023.de.md
@@ -20,7 +20,7 @@ nicht nur für die internen Stakeholder, sondern auch für die Welt außerhalb g
In diesem Zusammenhang legte Open Elements den Grundstein für zukunftsweisende Innovation und Wachstum in den kommenden
Jahren.
-{{< centered-image src="/posts/2023-01-20-open-elements-2023/oss-meets-java.png" width="75%" alt="Open Elements als Bindeglied von OSS und Java">}}
+
## Die Erfolge in der Eclipse Foundation
@@ -36,7 +36,7 @@ engagiert, sondern auch bedeutende Beiträge zu Projekten der Eclipse Adoptium A
Diese Beiträge ermöglichten es, dass Open Elements neben namhaften Unternehmen wie IBM, RedHat und Azul ebenfalls
kommerziellen Support für die Produkte der Adoptium Arbeitsgruppe anbieten kann.
-{{< centered-image src="/posts/2023-01-20-open-elements-2023/adoptium-members.png" width="60%" showCaption="true" alt="Mitglieder der Adoptium Arbeitsgruppe">}}
+
Ein weiterer Meilenstein für Open Elements war die Rolle als einer der Sponsoren der internationalen
[Eclipse Con 2023](https://www.eclipsecon.org/2023) Konferenz, was das Engagement des Unternehmens in der
@@ -57,7 +57,7 @@ Dies wurde auch dadurch unterstrichen, dass Hendrik Ebbers zur
[Mercedes-Benz FOSS Con](https://opensource.mercedes-benz.com/news/recap-foss-convention-2023/) eingeladen wurde,
um die Arbeit der Eclipse Foundation im Java-Sektor zu präsentieren.
-{{< centered-image src="/posts/2023-01-20-open-elements-2023/mercedes-foss.png" width="80%" showCaption="true" alt="Fotos der Mercedes-Benz FOSS Con">}}
+
Diese Erfolge von Open Elements und Hendrik Ebbers in der Eclipse Foundation zeigen deutlich, wie das Unternehmen und
seine führenden Köpfe das immer wichtiger werdende Thema Open Source Software mitgestalten und prägen.
@@ -79,7 +79,7 @@ Darüber hinaus hat Open Elements bedeutende Beiträge zu weiteren prominenten O
darunter [web3j](https://github.com/hyperledger/web3j),
[Eclipse AQAvit](https://projects.eclipse.org/projects/adoptium.aqavit) und dem [OpenJDK](https://github.com/openjdk/jmh).
-{{< centered-image src="/posts/2023-01-20-open-elements-2023/contributions.png" width="80%" showCaption="true" alt="Open Elements tätigte über 1800 Beiträge zu Open Source Projekten in 2023">}}
+
Diese Contributions unterstreichen das tiefgreifende **Engagement von Open Elements in der Java-Community** und seine
Hingabe an die Förderung und Verbesserung von Open-Source-Technologien. Durch diese Aktivitäten stärkt Open Elements
@@ -111,14 +111,14 @@ Veranstaltung von Mercedes Benz, die sich auf freie und Open-Source-Software kon
Dies war eine hervorragende Gelegenheit, Hedera weiteren Entscheidungsträgern und Influencern in der Technologiebranche
vorzustellen.
-{{< centered-image src="/posts/2023-01-20-open-elements-2023/jug-bonn.png" width="80%" showCaption="true" alt="Foto des Vortrags auf der JUG Bonn">}}
+
## Beitrag für Bildung und Gesellschaft
Im letzten Jahr hat Open Elements einen signifikanten Beitrag zur Bildung und Gesellschaft geleistet, indem es Wissen,
Ressourcen und Engagement in verschiedenen Bereichen bereitstellte.
- **Bildung:** Seit dem Wintersemester 2023
- [unterrichtet Hendrik Ebbers an der OTH Regensburg das Modul „Distribution Ledger Technology und Digital Trust“]({{< relref "dlt-lecture" >}}).
+ [unterrichtet Hendrik Ebbers an der OTH Regensburg das Modul „Distribution Ledger Technology und Digital Trust“](/dlt-lecture).
Dieses Engagement in der akademischen Welt unterstreicht das Bestreben von Open Elements, zukünftige Generationen
von Entwicklern und Technologieexperten auszubilden und zu inspirieren.
- **Weitere Konferenzen & Meetups:** Open Elements hat sich als einer der Sponsoren der Java User Group Dortmund
@@ -151,4 +151,4 @@ verschiedenen Organisationen unterstrich Open Elements seine führende Rolle in
Das Unternehmen demonstrierte sein Engagement für Nachhaltigkeit und soziale Verantwortung durch Sponsoring und
umweltfreundliche Initiativen.
-{{< centered-image src="/posts/2023-01-20-open-elements-2023/duke-os.png" width="50%" alt="Illustration des Java Maskottchens mit dem Open Source Logo">}}
+
diff --git a/content/posts/2024-07-09-open-source-java.de.md b/content/posts/2024-07-09-open-source-java.de.md
index 6a053b5d..25ac727c 100644
--- a/content/posts/2024-07-09-open-source-java.de.md
+++ b/content/posts/2024-07-09-open-source-java.de.md
@@ -28,7 +28,7 @@ Sie war in den letzten 20 Jahren quasi durchgängig in der Top 3 der populärste
Neben der Programmiersprache bezieht sich der Begriff Java aber auch auf die Laufzeitumgebung, in der Java Programme
ausgeführt werden können: der Java Virtual Machine (JVM).
-{{< centered-image src="/posts/2024-07-09-open-source-java/toibe-de.png" width="100%" showCaption="true" alt="Diagramm zur Verbreitung von Java basierend auf Toibe">}}
+
Diese besondere Kombination aus Programmiersprache und Laufzeitumgebung ermöglicht es, dass Java Anwendungen auf jeder
Maschine, auf der eine JVM installiert ist, ausgeführt werden. Hierdurch entstand auch einer der Leitsprüche von
@@ -36,7 +36,7 @@ Java: ""Write Once, Run Anywhere" (WORA)”.
Sowohl die Bestandteile der Programmiersprache als auch der Quelltext der JVM von Java sind im OpenJDK zu finden,
welches die Open Source Quellen von Java beinhaltet.
-{{< centered-image src="/posts/2024-07-09-open-source-java/wora-de.png" width="100%" showCaption="true" alt="Schematischer Stack einer Java Anwendung">}}
+
## Was bedeutet Open Source?
Open Source lässt sich heute **in den meisten Bereichen unseres digitalen Alltags** wiederfinden und wird dabei häufig
@@ -47,7 +47,7 @@ Das gleiche gilt für den Safari bzw. Chrome Browser. Beide basieren zum größt
Aber nicht nur im Privaten begegnen uns Open-Source-Anwendungen immer mehr – auch die deutliche Mehrheit aller deutschen
Unternehmen setzt Open-Source-Software ein.
-{{< centered-image src="/posts/2024-07-09-open-source-java/os-logo.png" width="80%" showCaption="true" alt="Die offiziellen Logos zum erkennen von Open Source (Software)">}}
+
**Open Source ist ein starker Treiber von Innovation.**
@@ -60,7 +60,7 @@ Jedoch gibt es heute Workflows die es projektexternen Personen erlauben, einen B
leisten. Dies wirkt sich positiv auf die Diversität in OSS aus, da hierdurch jede Person an Open Source mitarbeiten kann.
Die größte Plattform für Open Source Software, auf der auch die Quellen des OpenJDK – also Java – zu finden sind, ist GitHub.
-{{< centered-image src="/posts/2024-07-09-open-source-java/pr-de.png" width="80%" showCaption="true" alt="Pull Request Workflow, um als externer Entwickler an OSS mitzuarbeiten">}}
+
### Wo wird Open Source grundsätzlich genutzt?
@@ -81,7 +81,7 @@ YouTube, Netflix, PayPal oder eBay sind alle auf einer Open Source Basis aufgeba
Der wohl offensichtlichste Vorteil von Open Source Software ist die kostenfreie Verwendung.
Weitere Vorteile die vor allem von Unternehmen als sehr positiv wahrgenommen werden, sind in folgendem Diagramm zu finden:
-{{< centered-image src="/posts/2024-07-09-open-source-java/diagramm-benefits-de.png" width="80%" showCaption="true" alt="Ergebnis der Umfrage, welchen Mehrwert Firmen in OSS sehen">}}
+
OSS bringt allerdings noch weitaus mehr positive Aspekte mit sich:
@@ -121,7 +121,7 @@ zum OpenJDK beitragen. Das OpenJDK ist als Projekt [bei GitHub zu finden](https:
Auf dem folgenden Bild ist dargestellt, welche Firmen Änderungen zu Java 19 beigetragen haben
(also Änderungen, die zwischen der Veröffentlichung von Java 18 und 19 hinzugefügt wurden).
-{{< centered-image src="/posts/2024-07-09-open-source-java/openjdk-contributions.png" width="100%" alt="Verteilung der Beiträge von verschiedenen Firmen zum OpenJDK">}}
+
Der OpenJDK-Quelltext lässt sich in drei Teile teilen:
@@ -142,7 +142,7 @@ Anbieter (Oracle, Microsoft, RedHat) herunterladen.
Die bei weitem **meistgenutzte Distribution ist hierbei Eclipse Temurin**, welche von der Eclipse Foundation
als **“anwenderneutrale” Distribution** zur Verfügung gestellt wird.
-{{< centered-image src="/posts/2024-07-09-open-source-java/distributions.png" width="100%" showCaption="true" alt="Verschiedene Java Distributionen basieren alle auf dem OpenJDK">}}
+
Viele der verfügbaren Laufzeitumgebungen werden heute durch das **Java Test Compatibility Kit (TCK)** auf ihre
**Kompatibilität zum offiziellen JavaSE Standard** hin überprüft.
@@ -173,7 +173,7 @@ In Unternehmen gibt es selten die erforderlichen Ressourcen, um diese Herausford
Da Open Source Software wie Java mittlerweile aber häufig zur **kritischen Infrastruktur von Unternehmen** gehört,
braucht es externen Support.
-{{< centered-image src="/illustrations/support-care-logos/support-care-logo.svg" width="100%" alt="Eclipse Temurin Support & Care Logo">}}
+
Support & Care by Open Elements unterstützt Unternehmen bei dieser wichtigen Aufgabe.
Wir helfen bei der Instandhaltung und Wartung der Java Laufzeitumgebung.
diff --git a/content/posts/2024-07-22-gaming-web3.md b/content/posts/2024-07-22-gaming-web3.md
index 61750245..0bbeb211 100644
--- a/content/posts/2024-07-22-gaming-web3.md
+++ b/content/posts/2024-07-22-gaming-web3.md
@@ -16,7 +16,7 @@ of the game and used in other games, this reality is still nowhere to be found.
In this article, I want to take a closer look at **non-fungible tokens (NFTs)** and their **usability for video games**
and consider what further standardizations are needed to realize the promise of game-independent assets.
-{{< centered-image src="/posts/2024-07-22-gaming-web3/tokens.png" width="100%" showCaption="true" alt="Assets of games can be defined as unique NFTs">}}
+
Most of the games that rely on Web3 technologies today use NFTs to represent in-game assets and “store them on a blockchain”.
The promise here is that these **NFTs belong to the players** and not to the game, meaning they cannot be “taken away”
@@ -37,7 +37,7 @@ The argument that no publisher would ever do this is not entirely correct.
After all, especially in the area of micropayments and loot boxes, we have seen too many things in recent years that
supposedly no publisher would ever do.
-{{< centered-image src="/posts/2024-07-22-gaming-web3/spoon.png" width="100%" showCaption="true" alt="The real asset content of an NFT can change">}}
+
In addition to managing game assets such as items or skins, many of these points also apply to digital currencies used
in computer games today.
@@ -49,7 +49,7 @@ spans their games.
Another advantage is that surplus coins could easily be **exchanged back into real currency** (fiat currency) via an
exchange like [Coinbase](https://www.coinbase.com/).
-{{< centered-image src="/posts/2024-07-22-gaming-web3/exchange.png" width="100%" showCaption="true" alt="Today no game tokens are exchangeable">}}
+
Based on these points, the use of NFTs for managing game assets and their ownership can be broken down into the
following advantages and disadvantages:
@@ -102,7 +102,7 @@ Once the graphic is no longer actively used in the game, the NFT can be unlocked
[ERC-6982](https://eips.ethereum.org/EIPS/eip-6982) already defines events for locking NFTs.
However, for games, this should be extended further.
-{{< centered-image src="/posts/2024-07-22-gaming-web3/tokemon.png" width="100%" showCaption="true" alt="Gaming cards defined as lockable tokens">}}
+
#### NFT metadata
@@ -131,8 +131,7 @@ this draft into a sensible, sustainable, and secure standard for NFTs in compute
The interfaces shown here are based on [ERC-721 (NFT standard)](https://eips.ethereum.org/EIPS/eip-721)
and [ERC-165 (Standard Interface Detection)](https://eips.ethereum.org/EIPS/eip-165):
-{{< highlight java >}}
-interface GameTokens {
+```javainterface GameTokens {
// returns the total amount of tokens for a game
function totalSupply(address game) returns (uint256);
@@ -199,7 +198,7 @@ interface GameToken {
// returns all tags of the token
function getTags() returns (string[]);
}
-{{< / highlight >}}
+```
Feedback on the design of the interface and its functions is always welcome.
@@ -252,7 +251,7 @@ the [Linux Foundation](https://www.linuxfoundation.org/), you can find many exam
implemented and established sensibly, transparently, and on equal footing.
Therefore, I propose a similar concept for a working group to define and manage an independent and interoperable NFT.
-{{< centered-image src="/posts/2024-07-22-gaming-web3/open_game_standards_alliance.svg" width="100%" showCaption="true" alt="An open and transparent alliance of the gaming industry is needed">}}
+
## Next Steps
diff --git a/content/posts/2025-01-03-dco-signing.md b/content/posts/2025-01-03-dco-signing.md
index 53ea2272..0f9ed3ec 100644
--- a/content/posts/2025-01-03-dco-signing.md
+++ b/content/posts/2025-01-03-dco-signing.md
@@ -22,8 +22,7 @@ Since Open Source Software (OSS) are becoming more and more important, the DCO l
The idea of the DCO is simple: Every contributor must sign the DCO before contributing to an Open Source project.
The full text of the DCO, as hosted at https://developercertificate.org is as follows:
-{{< highlight bash >}}
-By making a contribution to this project, I certify that:
+```bashBy making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
@@ -46,7 +45,7 @@ By making a contribution to this project, I certify that:
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
-{{< / highlight >}}
+```
As you can see the text of the DCO reads as a legal statement.
Since a legal statement normally need to be signed, there must be a way to sign the DCO for a contribution to an OSS.
@@ -58,8 +57,7 @@ Next to that the integration in the workflow of git, and GitHub must be very eas
Therefore, the DCO is even mentioned in [the man page (the documentation) of git](https://git-scm.com/docs/git-commit). By calling `git help commit` you can see the following information:
-{{< highlight bash >}}
--s, --signoff, --no-signoff
+```bash-s, --signoff, --no-signoff
Add a Signed-off-by trailer by the committer at the end of the commit log message.
The meaning of a signoff depends on the project to which you’re committing.
For example, it may certify that the committer has the rights to submit the work under the project’s license or agrees
@@ -69,17 +67,16 @@ Consult the documentation or leadership of the project to which you’re contrib
used in that project.
The --no-signoff option can be used to countermand an earlier --signoff option on the command line.
-{{< / highlight >}}
+```
As you can see a developer only needs to add the `-s` or `--signoff` option to the `git commit` command to sign the DCO.
You can easily try this at home by creating a new git repository and adding a new file to it:
-{{< highlight bash >}}
-$ git commit -m "DCO post started" -s
+```bash$ git commit -m "DCO post started" -s
[dco-post d2b4530] DCO post started
1 file changed, 72 insertions(+)
create mode 100644 content/posts/2025-01-03-validating-dco-signing.md
-{{< / highlight >}}
+```
I just did exactly that to commit the current state of this post to the git repository.
As you can see adding the `-s` option to the `git commit` command does not change the output, asks for a signature, or anything else.
@@ -91,8 +88,7 @@ It does not even need the author to read the DCO.
You can see that the DCO is signed by looking at the commit message.
The `Signed-off-by` line is added to the commit message:
-{{< highlight bash >}}
-$ git log -1
+```bash$ git log -1
commit d2b45309f4a002dd637e7a83fb524d0be0549853 (HEAD -> dco-post)
Author: Hendrik Ebbers
Date: Thu Jan 2 16:39:43 2025 +0100
@@ -100,7 +96,7 @@ Date: Thu Jan 2 16:39:43 2025 +0100
DCO post started
Signed-off-by: Hendrik Ebbers
-{{< / highlight >}}
+```
The complete signing process is now done.
It does exactly what you see in the commit message: It adds a single `Signed-off-by` line to the commit message.
@@ -118,14 +114,14 @@ One of the most popular tools is the [DCO Check GitHub App](https://github.com/a
The app checks every pull request for the `Signed-off-by` line.
If a pull request does not contain the `Signed-off-by` line, the PR checks will fail and the PR cannot be merged.
-{{< centered-image src="/posts/2025-01-03-dco-signing/dco-github-pr-check.png" width="100%" showCaption="true" alt="Sample of a PR with an failed DCO check">}}
+
While the app is in general a good idea to ensure that every future contribution is signed, it has some drawbacks.
If the check fails, the PR cannot be merged in first place but a committer of the repository can "fix" that:
If you look at the details of the failed check, you can see a help text that explains how to fix the missing DCO signing.
While that is great and even enabled developers that are not familiar with the DCO to sign it, the details page also contains a button to "set DCO to pass".
-{{< centered-image src="/posts/2025-01-03-dco-signing/dco-github-set-pass.png" width="100%" showCaption="true" alt="Sample of a PR with an failed DCO check">}}
+
When I saw and pressed this button for the first time, I was assuming that I would sign the DCO for all commits in the PR.
But that is not the case.
@@ -144,11 +140,10 @@ When we looked at the `git log` output before, we saw that the `Signed-off-by` l
The committer has not been mentioned so far.
You can see the committer and the author of a commit by using the `git show` command:
-{{< highlight bash >}}
-$ git show --pretty=format:"Author: %an <%ae>%nCommitter: %cn <%ce>" -s
+```bash$ git show --pretty=format:"Author: %an <%ae>%nCommitter: %cn <%ce>" -s
Author: Hendrik Ebbers
Committer: Hendrik Ebbers