Beyond PrettyFaces - Einführung in Rewrite

Preview:

DESCRIPTION

W-JAX 2013 talk on Rewrite

Citation preview

Christian Kaltepoth | ingenit GmbH & Co. KG

Beyond PrettyFacesEinführung in Rewrite

URL-Rewriting

Wikipedia

A rewrite engine is software [...] that modifies a web URL's appearance.

This modification is called URL rewriting.

http://en.wikipedia.org/wiki/Rewrite_engine

Beispiel

http://www.onlineshop.de/b/ref=sa_menu_desk3?ie=UTF8&node=2193272340

http://www.onlineshop.de/elektronik

Sprechende RESTful URLs

http://www.javaserverfaces.org/news

http://jax.de/wjax2013/sessions

https://github.com/ocpsoft/rewrite/issues/87

http://stackoverflow.com/questions/tagged/jsf

Wozu das Ganze?

Vorteile

• Adressierbare Informationen– Wo bin ich hier?– "Vertrauen"

• Reload und Bookmarks• Einfache HTML Links

– Lose Kopplung

• Technologieneutralität

SEO

• Keywords in URL• Optimierung des Rankings

http://www.amazon.com/JavaServer-Faces-2-0-Complete-

Reference/dp/0071625097

PrettyFaces• JSF URL-Rewriting De-facto-Standard • RESTful URLs• Page Actions• Einfache Rewrite Engine• Dynamic Views• Integration mit JSF Navigation

Warum Rewrite?

API Abhängigkeiten

Servlet-spezifisch

JSF-spezifisch

Pre

ttyF

aces

Einschränkungen

• Mapping nur via Request Path• Eingeschränkte Konfiguration via XML• Annotation API „verbesserungswürdig“• Konvertierung nur eingeschränkt

möglich• Nicht besonders erweiterbar

Der Neuanfang

Was ist Rewrite?

Key Features

• Servlet basiertes Rewriting auf Basis einer Rule-Engine

• Framework Integration– JSF, CDI, Spring, Shiro, etc.

• Konfiguration: Java DSL + Annotations• Fokus auf Erweiterbarkeit• Open Source (Apache 2.0)

Begriffe

• Configuration:– Sortierte Liste

von Rules

• Rule:– Conditions– Operations– Priority

Rewriting Types

Inbound

Outbound

Inbound

GET /faces/home.xhtml HTTP/1.1Host: www.acme.comConnection: keep-alive[....]

Outbound

<a href="/faces/home.xhtml"> Getting started</a>

Java DSL

Warum?

• Typensichere Konfiguration• Code Assist durch IDE• Geführte Konfiguration• Erweiterbar• „Plain Java“

Java DSL

public class RewriteConfig extends HttpConfigurationProvider {

@Override public Configuration getConfiguration(ServletContext ctx) {

// Konfiguration „bauen“

}

@Override public int priority() { return 10; }

}

ConfigurationBuilder

return ConfigurationBuilder.begin() // Variante 1 .addRule() .when( /* condition */ ) .perform( /* operation */ ) // Variante 2 .addRule( /* rule */ )

;

Initial Redirect

http://www.acme.com/

http://www.acme.com/faces/home.xhtml

Redirect

Beispiel: Initial Redirect

.addRule()

.when( Direction.isInbound().and(Path.matches("/"))).perform( Redirect.permanent("/faces/home.xhtml"))

Der erste Rewrite

http://www.acme.com/faces/home.xhtml

http://www.acme.com/home

Der erste Rewrite

.addRule()

.when(Direction.isInbound().and( Path.matches("/home"))).perform(Forward.to("/faces/home.xhtml"))

.addRule()

.when(Direction.isOutbound().and( Path.matches("/faces/home.xhtml"))).perform(Substitute.with("/home"))

Einfacher: Joins

.addRule( Join.path("/home") .to("/faces/home.xhtml") )

Parameter

/faces/products.xhtml?category=books

/products/books

JSF 2.0 View Parameter

<f:metadata> <f:viewParam name="category" value="#{productListPage.category}" /></f:metadata>

@Named@RequestScopedpublic class ProductListPage {

private String category;

}

Join mit Parametern

.addRule( Join.path("/products/{category}") .to("/faces/products.xhtml"))

Demo

Annotations?

Einfacher Join

@Named@RequestScoped@Join(path = "/home", to = "/faces/home.xhtml")public class HomePage {

/* your code */

}

Parameter

/faces/products.xhtml?category=books

/products/books

Mit View-Parametern@Named@RequestScoped@Join(path = "/products/{category}", to = "/faces/products.xhtml")public class ProductListPage {

// <f:viewParam name=“category“ ...> private String category;

/* ... */

}

Ohne View-Parameter@Named@RequestScoped@Join(path = "/products/{category}", to = "/faces/products.xhtml")public class ProductListPage {

@Parameter private String category;

/* ... */ }

Validierung@Named@RequestScoped@Join(path = "/products/{category}", to = "/faces/products.xhtml")public class ProductListPage {

@Parameter @Matches("[a-zA-Z\\-]+") private String category;

/* ... */ }

JSF Validators@Named@RequestScoped@Join(path = "/products/{category}", to = "/faces/products.xhtml")public class ProductListPage {

@Parameter @Validate(with = CategoryValidator.class) private String category;

/* ... */ }

Request Actions

Request Actions@Named@RequestScoped@Join(path = "/home", to = "/faces/home.xhtml")public class HomePage {

@RequestAction public void init() { /* your code */ }

}

Ignore Postbacks@Named@RequestScoped@Join(path = "/home", to = "/faces/home.xhtml")public class HomePage {

@RequestAction @IgnorePostback public void init() { /* your code */ }

}

Deferral@Named@ViewScoped@Join(path = "/home", to = "/faces/home.xhtml")public class HomePage {

@RequestAction @Deferred public void init() { /* your code */ }

}

Deferral@Named@ViewScoped@Join(path = "/home", to = "/faces/home.xhtml")public class HomePage {

@RequestAction @Deferred(before = Phase.RENDER_RESPONSE) public void init() { /* your code */ }

}

Navigation

Navigation

<h:link outcome="/products.xhtml"> <f:param name="category" value="books"/> Bücher</h:link>

<a href="/products/books"> Bücher </a>

Navigation

public class SomePage {

public String actionMethod() {

/* do something */

return "/products.xhtml?category=books" + "&faces-redirect=true";

}

}

Navigation

public class SomePage {

public Navigate actionMethod() {

/* do something */

return Navigate.to(ProductListPage.class) .with("category", "books");

}

}

Was kann Rewrite noch?

Content Delivery Networks(CDN)

JSF Resources

<h:outputScript name="jquery.js" />

<script type="text/javascript" src="/faces/javax.faces.resource/jquery.js" />

<script type="text/javascript" src="http://dh8sm43.cloudfront.net/jquery.js" />

Erzeugt

Gewünscht

CDN URL Relocation

.addRule( CDN.relocate("/faces/javax.faces.resource/jquery.js") .to("http://dh8sm43.cloudfront.net/jquery.js"))

ResourceTransformation

HTTP Response

RewriteTransformation

Pipeline

Usecases

• Minification – JavaScript, CSS

• Compression – GZIP, Deflate

• Rendering – SASS, SCSS, Markdown, Textile, ...

• Custom Processing

JavaScript Minify

.addRule()

.when( Direction.isInbound().and(Path.matches( "/faces/javax.faces.resource/{*}.js"))).perform( Transform.with(Minify.js()))

Rendering

Beispiel: Sass$blue: #3bbfce;$margin: 16px;

.content-navigation { border-color: $blue; color: darken($blue, 9%);}

.border { padding: $margin / 2; margin: $margin / 2; border-color: $blue;}

.content-navigation { border-color: #3bbfce; color: #2b9eab;}

.border { padding: 8px; margin: 8px; border-color: #3bbfce;}

Beispiel: Sass

.addRule()

.when( Direction.isInbound().and( Path.matches("/styles/{*}.sass"))).perform( Response.setContentType("text/css").and( Transform.with(Sass.compiler())))

Precompile with Maven

<plugin> <groupId>org.jasig.maven</groupId> <artifactId>sass-maven-plugin</artifactId> <version>1.1.1</version> <executions> <execution> <phase>prepare-package</phase> <goals> <goal>update-stylesheets</goal> </goals> </execution> </executions></plugin>

Transform on demand.addRule().when( Direction.isInbound() .and(Path.matches("/styles/{name}.css")) .and(Resource.exists("/styles/{name}.scss")) .and(Not.any( Resource.exists("/styles/{name}.css")))).perform( Forward.to("/styles/{name}.scss") .and(Response.setContentType("text/css")) .and(Transform.with(Sass.compiler())))

Wie migriere ich meine PrettyFaces Anwendung?

Rewrite PrettyFaces Module

<dependency> <groupId>org.ocpsoft.rewrite</groupId> <artifactId>rewrite-config-prettyfaces</artifactId> <version>2.0.8.Final</version></dependency>

• Drop-In Replacement für PrettyFaces• „Sanfte“ Migration

Thank you!

http://ocpsoft.org/rewrite/

Christian Kaltepothchristian@kaltepoth.de @chkal