martes, 8 de agosto de 2017

JEE & JSF 3rd Part: Accessing property files (I DON'T LIKE THIS POST. I FIND IT TOO ARTIFICIOUS. ONLY FOR LEARNING PURPOSES)

0. Introduction

Although this is a "very academical" post, I don't like it as it is too verbose and difficult to understand. So I prefer using this approach to use properties.

To show formatted text Hilite is used



Getting a property from a property file is rather simple in Java. But it is a very resource consuming practice to create a Properties class every time a property is read (and accessing a file).

So a good choice is to use a singleton instance.

To achieve this post, the help of these post have been greatly appreciated:
  1. Baeldung, Mykong. (For accessing property files)
  2. Ivo Woltring, Piotr Nowicki (For singletons)

A Singleton is very similar to an application scoped bean, so the second approach will be used. the use of Weld is very important as a context and dependency manager container.

The steps of this tutorial are:

  1. Create an Eclipse Maven project as the one created in the last post, or use it. 
  2. Create an Interface to define an annotation of Property.
  3. Create the Producer (but Ivo and Piotr have distinguished the data type of property)
  4. Creating the property files (application.properties)
  5. Using in an example
Let's begin with the second step.

1. Creation of the Property Annotation (Interface)

Our code is:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.ximodante.utils.property;

import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;


/**
 * Represents an property key to be injected
 */
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Property {
    @Nonbinding String value() default "";
    @Nonbinding boolean required() default true;
}

Brief explanations:
@Retention (RUNTIME) for accessing during Runtime
@target indicates in which part of the code can be used
@Nonbinding: "If a member has this qualifier, it will not be used during type-safe resolution and its value will have no meaning". This is what says, Ken Finnegan


2. The Producer class

Ivor and Piotr have made a "fine" producer, analyzing the property type. I cannot improve this class So a copy-paste is made, but some modifications are made:

  1. @ApplicationScoped annotation for making it quite similar to a singleton.
  2. Some additional System.out.println sentences to see whether the property file is accessed and to evaluate how many times the property file is opened
  3. An additional class Config is accessed to know where is the property file. The file is in "config/application.properties" in the src/main/resources folder
  4. Should implement Serializable or else Weld complaints


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package org.ximodante.utils.property;

import java.io.FileInputStream;
import java.io.IOException;

import java.io.Serializable;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;


import org.ximodante.jsf.config.Config;

@ApplicationScoped
public class PropertyProducer implements Serializable{
 
 private static final long serialVersionUID = 1L;
 
 private Properties properties;
 
  
    @Property
    @Produces
    public String produceString(final InjectionPoint ip) {
        return this.properties.getProperty(getKey(ip));
    }
    
    @Property
    @Produces
    public int produceInt(final InjectionPoint ip) {
        return Integer.valueOf(this.properties.getProperty(getKey(ip)));
    }
    
    @Property
    @Produces
    public boolean produceBoolean(final InjectionPoint ip) {
        return Boolean.valueOf(this.properties.getProperty(getKey(ip)));
    }
    
    private String getKey(final InjectionPoint ip) {
        return (ip.getAnnotated()
                  .isAnnotationPresent(Property.class) && 
                !ip.getAnnotated()
                   .getAnnotation(Property.class)
                   .value().isEmpty()) ? ip.getAnnotated()
                                           .getAnnotation(Property.class)
                                           .value() 
                                       : ip.getMember()
                                           .getName();
    }
    
    @PostConstruct
    public void init() {
        this.properties = new Properties();
        
        String path = Thread.currentThread().getContextClassLoader().getResource("").getPath() + Config.getPropertyFile();
        System.out.println("PROPERTIES.PATH=" + path);
        
        try {
            //this.properties.load(stream);
         this.properties.load(new FileInputStream(path));
        } catch (final IOException e) {
            throw new RuntimeException("XXXXXXXX: Configuration could not be loaded!");
        }
    }

}


3. The application.properties file

Our file  in "config/application.properties" in the src/main/resources folder is



1
2
3
4
webEnvironment=true
comment=This is a test commennt
kk=Other property
greet.first=Good Morning!

To localize the path of the file the Config class is used.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package org.ximodante.jsf.config;


import lombok.Getter;

public class Config {
 @Getter
 private static final String PropertyFile="config/application.properties";
 
}


4. Using in a bean.

The source code for a simple bean is



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package org.ximodante.utils.property;

import java.io.Serializable;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;

import lombok.Getter;

@Named
@ViewScoped
public class TestPropertyBean implements Serializable{
 private static final long serialVersionUID = 1L;
 
 // the name of the attribute (greet1= does NOT match 
 // the property name ("greet.fist")
 @Inject
 @Property("greet.first")
 @Getter
 private String greet1;
 
 // the name of the attribute (comment) DOES match 
 // the property name so no attribute is passed to 
 // the annotation @Property
 @Inject
 @Property
 @Getter
 private String comment;
 
}

To make this easier a xhtml file is supplied (beanprop.xhtml) in webapp folder



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:p="http://primefaces.org/ui">  
    <h:head>  
    </h:head>  
      
    <h:body>  
       <h:form>  
           <p:panel header="Keyboard Demo">    
               <p:keyboard value="#{testPropertyBean.comment}"/>  
               <p:keyboard value="#{testPropertyBean.greet1}"/>  
             </p:panel>
             <p:commandButton value="Submit"/>
       </h:form>
    </h:body>  
</html>


Let's run the project as a server application and point to http://localhost:8080/JSFv02/beanprop.jsf in the browser where:

- JSFv02 is the name of our project
beanprop.jsf references to the beanprop.xhtml file in the webapp folder

Here is the result









No hay comentarios:

Publicar un comentario

JEE & JSF16th Part: Creating an abstraction view layer to JSF components and Forms (5/5). Frequent problems

1. ERROR #1: Using a bean that does not exists In the previos entry we used this facelet file: 1 2 3 4 5 6 7 8 9 10 11 1...