DeltaSpike – CDI extensions of the world, unite! – CDI



DeltaSpike – CDI extensions of the world, unite! – CDI

1 0


devconf2014


On Github rsmeral / devconf2014

DeltaSpike

CDI extensions of the world, unite!

DevConf 2014

Us

Ron Šmeral@rsmeralSeam QE at RH | Seam, Weld, DeltaSpike
Matouš Jobánek@MatousJobanekWFK QE at RH | beer, mountains

CDI

CDI

Contexts and Dependency Injection

Weld, OWB, CanDI

Type-safe resolution, Scopes

public class UserController {

    @Inject @User
    public Repository repo;
@SessionScoped @User
class UserRepo implements Repository {

...
class Repositories {

    @Produces @SessionScoped @User
    public Repository getUserRepo() {

CDI

Interceptors

public class Account {
...
    @Audited
    public void changePassword(Credentials c) {

...
@Interceptor @Audited
public class AuditInterceptor {
    
    @AroundInvoke
    public logOperation() {
...

CDI

Events

public void updatePasswordExpiryDate(@Observes @Changed Credentials) {
...
@Inject @Changed Event<Credentials> changeEvent;

public changePassword(Credentials c) {
    ...
    changeEvent.fire(c);

CDI extensions

SPI for integration with other technologiesSeam, Spring, GWT, ...

Custom scopes@PageScope, @BusinessProcessScope

Provide beans, augment existing beans

Catch system events for deployment phasesbefore/after deployment, per bean, per injection point

Existing extensions

Integrations with other frameworks

PicketLink, RestEasy, Agorava, …

Frameworks

zk, SoftwareMill, …

Seam 3, MyFaces CODI

Unite

DeltaSpike

Core
Data
JPA
BeanVal
Partial Bean
Scheduler
Test Control
Servlet
JSF
Security
spacer
spacer

What?

CDI extension framework

Why?

Unite efforts

Who?

Apache committersSeam developersother CDI ext. authors

When?

now: 0.6-SNAPSHOTsoon: 1.0

Frameworks

JBoss Seam 3

Solder
Config
Catch
Security
Social
Mail
Transaction
Render
Cron
Reports
Remoting
Rest
JMS
Persistence
Validation
Servlet
Wicket
Drools
jBPM
Faces
nothing
Spring
JCR

MyFaces CODI

Core
JSF
BV
JPA
Message

Other

cdi-query

Frameworks

JBoss Seam 3

Solder
Config
Catch
Security
Social
Mail
Transaction
Render
Cron
Reports
Remoting
Rest
JMS
Persistence
Validation
Servlet
Wicket
Drools
jBPM
Faces
nothing
Spring
JCR

MyFaces CODI

Core
JSF
BV
JPA
Message

Other

cdi-query

■ DeltaSpike & ■ friends

JBoss Seam 3

Core
Aries
Core
Security
Agorava
Mail
JPA
Render
Scheduler
Reports
Remoting
RestEasy
JMS 2.0
JTA 1.1
beanval
Servlet
Wicket
Drools
jBPM
JSF
Test-Control
PartialBean
Spring
ModeShape
spacer

MyFaces CODI

Core
JSF
beanval
JPA
Core

Other

Data

DeltaSpike

Core
Data
JPA
BeanVal
Partial Bean
Scheduler
Test Control
Servlet
JSF
Security
Agorava
PicketLink

DeltaSpike

Core
Data
JPA
BeanVal
Partial Bean
Scheduler
Test Control
Servlet
JSF
Security
Agorava
PicketLink

DeltaSpike

Core

Features for extension authors and users

Exceptions as events


...
try {
    doSomethingNasty();
} catch(TooNastyException ex) {
    logger.log("something nasty happened");
}
@Inject
private Event<ExceptionToCatchEvent> exEvt;
...
try {
    doSomethingNasty();
} catch(TooNastyException ex) {
    exEvt.fire(new ExceptionToCatchEvent(ex));
}







@ExceptionHandler
public class LoggingHandler {
    void logException(@BeforeHandles ExceptionEvent<Exception> evt) {
@ExceptionHandler
public class NastinessHandler {
    void spank(@Handles ExceptionEvent<TooNastyException> evt) {

DeltaSpike

Core

Type-safe messages

@MessageBundle
public interface AppMessages {

    @MessageTemplate("Hello, %s!")
    String hello(String name);

    @MessageTemplate("{greeting}")
    String greet(String greeting, String name);
AppMessages.properties
greeting=%s, %s!
Usage
@Inject AppMessages msg;
...
msg.greet("Hello", "DevConf");
msg.hello("World");

DeltaSpike

Core

ProjectStage, conditional bean exclusion

@Exclude(exceptIfProjectStage=IntegrationTest.class)
public class TestUserRepository { ...

Resource loading

@Inject
@ExternalResource("schedule.xml")
private InputStream inputStream;

@Inject
@ExternalResource("api-keys.properties")
private Properties apiKeys;

DeltaSpike

BeanVal

CDI in bean validators

class RegistrationAction {


    String chosenName;
    
    void register() {
        ...
    }
}
class RegistrationAction {

    @NotTaken
    String chosenName;
    
    void register() {
        ...
    }
}




    




class UserNameValidator implements ConstraintValidator<NotTaken, String> {

    @Inject
    UserRepository userRepo;

    boolean isValid(String s, ConstraintValidatorContext cvc) {
        return userRepo.findByName(s) == null;
    }
}

DeltaSpike

Data
public class PersonRepository {

    private Connection conn;

    private static final String BY_ID = "SELECT * FROM Person WHERE id = ?";
    private static final String BY_NAME = "SELECT * FROM Person WHERE firstName LIKE ? AND lastName LIKE ?'";
    private static final String STORE = "INSERT INTO Person(firstName,lastName,birthDate) VALUES(?,?,?)";
    private static final String UPDATE = "UPDATE Person SET firstName = ?, lastName = ?, birthDate = ?";
    private static final String REMOVE = "DELETE FROM Person WHERE id = ?";
    
    private PreparedStatement findByIdStmt;
    private PreparedStatement findByNameStmt;
    private PreparedStatement storeStmt;
    private PreparedStatement updateStmt;
    private PreparedStatement removeStmt;

    public PersonRepository() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost/people", "user", "pass");
            findByIdStmt = conn.prepareStatement(BY_ID);
            findByNameStmt = conn.prepareStatement(BY_NAME);
            storeStmt = conn.prepareStatement(STORE);
            updateStmt = conn.prepareStatement(UPDATE);
            removeStmt = conn.prepareStatement(REMOVE);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(PersonRepository.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException ex) {
            Logger.getLogger(PersonRepository.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public Person find(Long id) {
        try {
            findByIdStmt.setLong(1, id);
            ResultSet rs = findByIdStmt.executeQuery();
            if (rs.next()) {
                String firstName = rs.getString("firstName");
                String lastName = rs.getString("lastName");
                Date birthDate = new Date(rs.getDate("birthDate").getTime());
                return new Person(firstName, lastName, birthDate);
            }
        } catch (SQLException ex) {
            Logger.getLogger(PersonRepository.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public List<Person> findByName(String first, String last) {
        try {
            findByNameStmt.setString(1, "%" + first + "%");
            findByNameStmt.setString(1, "%" + last + "%");
            ResultSet rs = findByNameStmt.executeQuery();
            List<Person> people = new ArrayList<Person>();
            while (rs.next()) {
                Long id = rs.getLong("id");
                String firstName = rs.getString("firstName");
                String lastName = rs.getString("lastName");
                Date birthDate = new Date(rs.getDate("birthDate").getTime());
                people.add(new Person(id, firstName, lastName, birthDate));
            }
            return people;
        } catch (SQLException ex) {
            Logger.getLogger(PersonRepository.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public Long store(Person p) {
        try {
            storeStmt.setString(1, p.getFirstName());
            storeStmt.setString(2, p.getLastName());
            storeStmt.setDate(3, new java.sql.Date(p.getBirthDate().getTime()));
            storeStmt.executeUpdate();
            return storeStmt.getGeneratedKeys().getLong(1);
        } catch (SQLException ex) {
            Logger.getLogger(PersonRepository.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public void update(Person p) {
        try {
            updateStmt.setString(1, p.getFirstName());
            updateStmt.setString(2, p.getLastName());
            updateStmt.setDate(3, new java.sql.Date(p.getBirthDate().getTime()));
            updateStmt.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(PersonRepository.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void remove(Person p) {
        try {
            removeStmt.setLong(1, p.getId());
            removeStmt.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(PersonRepository.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
@Stateful
@ConversationScoped
public class PersonRepository {
   
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    public void persist(Person p) {
        em.persist(p);
        em.flush();
    }

    public void remove(Person p) {
        em.remove(p);
        em.flush();
    }

    public List<Person> getAllPeople() {
        return em.createQuery("SELECT p FROM Person p").getResultList();
    }

    public List<Person> findByName(String name) {
        return em.createQuery("SELECT p From Person p WHERE p.name LIKE :name")
                 .setParameter("name", name).getResultList();
    }
}
@Repository
public interface PersonRepository 
extends EntityRepository<Person, Long> {}

DeltaSpike

Data

Data repositories made simple

Method name DSL

List<Person> findByNameLikeAndAgeBetweenAndGender(
    String name, int minAge, int maxAge, Gender gender);

Query as annotation

@Query("SELECT p from Person p where p.birthDate = ?1")
Person findByBirthDate(Date d);

DeltaSpike

Data

Auditing API

Criteria API support

Query Delegate – custom DSL

DTO mapping

Pagination

...

DeltaSpike

Partial Bean

Single dynamic implementation for bean interfaces

public interface PersonQueryService {

    @QueryMethod("select p from Person p order by p.name")
    public List<Person> findAllSortedByName();
    ...
@PartialBeanBinding
@Target(TYPE)
@Retention(RUNTIME)
@interface QueryService {}

@QueryService
public interface PersonQueryService {

    @QueryMethod("select p from Person p order by p.name")
    public List<Person> findAllSortedByName();
    ...






@QueryService
public class QueryServicePartialBean implements InvocationHandler {
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String query = method.getAnnotation(QueryMethod.class);
        ...

DeltaSpike

Core
Data
JPA
BeanVal
Partial Bean
Scheduler
Test Control
Servlet
JSF
Security
PicketLink
Agorava

DeltaSpike

JSF

Type-safe view-configs

@Folder
public interface Pages {

    @View(name = "home")
    class Index implements ViewConfig { }

    @Folder
    interface Admin extends ViewConfig {

        @View
        class Index implements Admin { }
    }
}
/pages/ /pages/home.xhtml /pages/admin/ /pages/admin/index.xhtml

DeltaSpike

JSF

Navigation

@Model
public interface Pages extends ViewConfig {


    class Home implements Pages { }

    class Index implements Pages { }
}
@Model
public interface Pages extends ViewConfig {


    class Home implements Pages { }

    class Index implements Pages {


        public Class<? extends ViewConfig> actionMethod() {

                return Pages.Home.class;
        }
    }
}
@Model
public interface Pages extends ViewConfig {


    class Home implements Pages { }

    class Index implements Pages {

        @NavigationParameter(key = "param", value = "#{myBean.property}")
        public Class<? extends ViewConfig> actionMethod() {

                return Pages.Home.class;
        }
    }
}
@Model
public interface Pages extends ViewConfig {

    @View(viewParams = INCLUDE)
    class Home implements Pages { }

    class Index implements Pages {

        @NavigationParameter(key = "param", value = "#{myBean.property}")
        public Class<? extends ViewConfig> actionMethod() {

                return Pages.Home.class;
        }
    }
}

DeltaSpike

Security

Securing method invocation

@SecurityBindingType
@Retention(value = RUNTIME)
@Target({TYPE, METHOD})
@Documented
@SecurityBindingType
public @interface CustomSecurityBinding {
}

DeltaSpike

Security
@CustomSecurityBinding
public void doSomething(Thing thing) {

    thing.doSomething();
}
@CustomSecurityBinding
public void doSomething(Thing thing) {

    thing.doSomething();
}
@CustomSecurityBinding
public void doSomething(Thing thing) {

    thing.doSomething();
}
@Secures
@CustomSecurityBinding
public boolean doSecCheck(InvocationContext invCont, @LoggedIn User user)
    throws Exception {

    return user.isLoggedIn(); // perform security check
}

DeltaSpike

Security

Securing access to Java classes

@Secured(Class<? extends AccessDecisionVoter>)
public interface AccessDecisionVoter extends Serializable {

    Set<SecurityViolation> checkPermission(AccessDecisionVoterContext context);
}
@Secured(CustomAccessDecisionVoter.class)
public class SecuredBean {

    //...
}

DeltaSpike

Security
+
JSF

Integration with JSF module

public interface Pages extends ViewConfig {

    class Index implements Pages { }


    interface Admin extends Pages {

                class Manage implements Admin { }

                class Home implements Admin { }
    }
}
@Secured(EmployeeAccessDecisionVoter.class)
public interface Pages extends ViewConfig {

    class Index implements Pages { }

    
    interface Admin extends Pages {

                class Manage implements Admin { }

                class Home implements Admin { }
    }
}
@Secured(EmployeeAccessDecisionVoter.class)
public interface Pages extends ViewConfig {

    class Index implements Pages { }

    @Secured(AdminAccessDecisionVoter.class)    
    interface Admin extends Pages {

                class Manage implements Admin { }

                class Home implements Admin { }
    }
}

Seam Security

DeltaSpike Security
PicketLink

PicketLink

Application Security Framework for Java EE applications

Provided features:

authenticating users

authorizing access

managing of users, groups, roles,..

plus much more...

Integrates DeltaSpike Security

The simplest solution for Seam / DeltaSpike based apps

Agorava

What?

CDI extension frameworkOriginally Seam Social

Why?

To deal with Social Mediabased on OAuth

Who?

Antoine Sabot-Durandother CDI ext. authors

When?

version: 0.7.0Nov 20, 2013

Agorava – What is on the menu?

A generic API to deal with OAuth 1.0a and 2.0 services

Specific API for Twitter, Facebook and LinkedIn

API to retrieve basic user information from a Social Service

SPI to extend Agorava with new modules for new services

Agorava – How?

1. Declare your OAuth application on the Social Media web site

2. Get OAuth app keys

3. Produce it with a CDI producer:

@ApplicationScoped
@Produces
@Twitter
@OAuthApplication(params = {@Param(name = PREFIX, value = "twitter")})
public OAuthAppSettings twitterSettings;

agorava.properties :

twitter.apiKey = your_key
twitter.apiSecret = your_secret_key

Agorava

OAuth authorization

@Inject
OAuthLifeCycleService lifeCycleService;

String authURL = lifeCycelService.startDanceFor(Twitter.class, "/icallback.jsf");

Agorava

Wanna work with user's info?

@Inject
@Twitter
TwitterUserService userService;

public void handleUserInfo() {

        userService.getProfileId();
        userService.getScreenName();
        //...
}

Agorava

Send tweet?

@Inject
@Twitter
TwitterTimelineService tl;

public Tweet sendTweet(String msg) {

        return tl.updateStatus(msg);
}

Your tweets

Loading tweets...

Demo at https://github.com/rsmeral/devconf2014-demo

How can I contribute?

Thank you