├── .gitignore ├── .travis.yml ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── risucci │ └── quickstart │ ├── context │ ├── QuickstartSecurityWebApplicationInitializer.java │ ├── QuickstartWebApplicationInitializer.java │ ├── adapter │ │ ├── WebApplicationConfigurerAdapter.java │ │ └── WebApplicationSecurityConfigurerAdapter.java │ ├── configuration │ │ ├── Database.java │ │ └── Jpa.java │ └── event │ │ └── ApplicationLoaderListener.java │ ├── jsf │ ├── bean │ │ ├── CountryBean.java │ │ └── LocaleManager.java │ ├── model │ │ └── Country.java │ └── util │ │ ├── FacesMessageSeverity.java │ │ └── FacesUtils.java │ └── repository │ └── CountryRepository.java ├── resources ├── com │ └── risucci │ │ └── quickstart │ │ ├── ascii_table.txt │ │ ├── i18n_en.properties │ │ ├── i18n_es.properties │ │ └── i18n_pt.properties └── datasource.properties └── webapp ├── WEB-INF ├── faces-config.xml ├── templates │ ├── main-with-nav.xhtml │ ├── main.xhtml │ └── nav.xhtml └── web.xml ├── index.html ├── protected ├── index.xhtml └── manage │ ├── country-edit.xhtml │ └── country-list.xhtml ├── public └── login.xhtml └── resources └── css └── login.css /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | bin 3 | .classpath 4 | .settings 5 | .project 6 | faces-config.pageflow 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://travis-ci.org/michelrisucci/spring-jsf-jpa-quickstart) [](https://github.com/michelrisucci/spring-jsf-jpa-quickstart/releases/tag/2.0.1.GA) 2 | 3 | Spring + JSF + JPA Quickstart 4 | ============================= 5 | 6 | - Version 2.0.1.GA 7 | 8 | - What it is: a quickstart project containing initial structure to: 9 | - ZERO CONFIGURATIONS to run the project! Checkout and run! 10 | - Web Application Security Access: 11 | - Username: **`admin`** 12 | - Password: **`123456`** 13 | - Spring Context 4.3 as Context Provider; 14 | - Spring Security 4.1 as Web Security Provider; 15 | - Jetty 9.3 as Webserver; 16 | - Pure JavaServer Faces 2.2 (no Primefaces required); 17 | - Built-in H2, PostgreSQL and MySQL Server connection for JDBC/JPA (extensible to ANY database - add specific JDBC drivers to POM if needed); 18 | - Oracle; 19 | - PostgreSQL; 20 | - Microsoft SQL Server; 21 | - Informix; 22 | - H2; 23 | - Derby; 24 | - and many more... 25 | - Hibernate 5 as JPA 2.1 provider; 26 | - Full-featured CRUD operations over an entity; 27 | - CRUD filtering features using Spring Data QBE; 28 | - Internationalization; 29 | - Faces bean utilities using FacesUtils class static methods; 30 | - Twitter Bootstrap 3.3 templating; 31 | 32 | - To run: 33 | - Checkout using Git or SVN; 34 | - Run using Maven 3 `mvn clean jetty:run`; 35 | 36 | - Customize database (optional): 37 | - Create a database over your preferred SGBD; 38 | - Add the desired JAR to POM, if needed: built-in H2, PostgreSQL and MySQL drivers; 39 | - Configure database connection settings over `src/main/resources/datasource.properties`; 40 | 41 | What's new 42 | ============================= 43 | 44 | - Version 2.0.1.GA 45 | - Fixed datasource properties location. 46 | 47 | - Version 2.0.0.GA 48 | - Pure JavaServer Faces 2.2 (no Primefaces required); 49 | - Spring Security 4.1 as Web Security Provider; 50 | - Hibernate 5 as JPA 2.1 provider; 51 | - Twitter Bootstrap 3.3 templating; 52 | 53 | - Version 1.4.0.GA 54 | - Added H2 JAR dependency for built-in support to H2 database; 55 | - Set H2 as default database (no configurations needed to run the project); 56 | 57 | - Version 1.3.1.GA 58 | - Fixed a bug in the edition form that, in some circumstances, was keeping outdated validation data: added attribute resetValues="true" to the insertion and edition action buttons; 59 | 60 | - Version 1.3.0.GA 61 | - Added a full-featured CRUD operations example: possibility to READ over a table, CREATE, EDIT and DELETE entries; 62 | - Changed default entity from "Code" to "Country", with properties: 63 | - Name (text); 64 | - Acronym (text); 65 | - Population (numeric); 66 | - Added a Spring application context listener that automatically adds mock data to database; 67 | - Moved internal page CSS to an external file at the `resources` folder; 68 | - Updated dependencies versions; 69 | 70 | - Version 1.2.2.GA 71 | - Fixed JPA Transaction Manager bean name to conventional "transactionManager"; 72 | 73 | - Version 1.2.1.GA 74 | - Added PostgreSQL 9.x JDBC 4.1 driver; 75 | - Project encoding strictly defined as UTF-8; 76 | - Updated Primefaces version to 5.1; 77 | 78 | - Version 1.2.0.GA 79 | - Full support component injection (@Inject and @Autowired) by extending the new utility class InjectionAwareBean Spring context's `SpringBeanAutowiringSupport` utility class; 80 | 81 | - Version 1.1.2.GA 82 | - Changed `index.xhtml` to show a `p:datatable` with mock objects; 83 | - Changed default Primefaces Aristo theme to Bootstrap; 84 | 85 | - Version 1.1.0.GA 86 | - Internationalization; 87 | - Bean utilities (class FacesUtils); 88 | - BUG: Spring does not fully support CDI, then @Named could not be used to define JSF Managed Beans; 89 | 90 | - Version 1.0.4.GA 91 | - Built-in MySQL Server connection for JDBC/JPA (extensible to ANY database - add specific JDBC drivers to POM if needed); 92 | - Oracle; 93 | - PostgreSQL; 94 | - Microsoft SQL Server; 95 | - Informix; 96 | - H2; 97 | - Derby; 98 | - and many more... 99 | - Hibernate 4.x as JPA 2.1 provider (switchable to EclipseLink if convenient - see web.xml); 100 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.risucci 6 | spring-jsf-jpa-quickstart 7 | 2.0.1.GA 8 | war 9 | 10 | 11 | UTF-8 12 | 13 | 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 3.5.1 21 | 22 | 1.7 23 | 1.7 24 | 25 | 26 | 27 | 28 | 29 | org.eclipse.jetty 30 | jetty-maven-plugin 31 | 9.3.11.v20160721 32 | 33 | 34 | /jsf 35 | 36 | 0 37 | 38 | target/classes/ 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.springframework 49 | spring-framework-bom 50 | 4.3.2.RELEASE 51 | pom 52 | import 53 | 54 | 55 | 56 | org.springframework.security 57 | spring-security-bom 58 | 4.1.3.RELEASE 59 | pom 60 | import 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | javax.servlet 69 | javax.servlet-api 70 | 3.1.0 71 | provided 72 | 73 | 74 | 75 | 76 | org.apache.commons 77 | commons-dbcp2 78 | 2.1.1 79 | 80 | 81 | 82 | 83 | com.h2database 84 | h2 85 | 1.4.192 86 | 87 | 88 | 89 | org.postgresql 90 | postgresql 91 | 9.4.1209.jre7 92 | 93 | 94 | 95 | mysql 96 | mysql-connector-java 97 | 5.1.39 98 | 99 | 100 | 101 | 102 | org.hibernate 103 | hibernate-core 104 | 5.2.2.Final 105 | 106 | 107 | 108 | 109 | org.springframework 110 | spring-webmvc 111 | 112 | 113 | org.springframework 114 | spring-orm 115 | 116 | 117 | org.springframework 118 | spring-tx 119 | 120 | 121 | org.springframework.data 122 | spring-data-jpa 123 | 1.10.2.RELEASE 124 | 125 | 126 | org.springframework.security 127 | spring-security-web 128 | 129 | 130 | org.springframework.security 131 | spring-security-config 132 | 133 | 134 | 135 | 136 | com.sun.faces 137 | jsf-api 138 | 2.2.13 139 | 140 | 141 | com.sun.faces 142 | jsf-impl 143 | 2.2.13 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/context/QuickstartSecurityWebApplicationInitializer.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.context; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.core.annotation.Order; 5 | import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; 6 | 7 | @Configuration 8 | @Order(2) 9 | public class QuickstartSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { 10 | 11 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/context/QuickstartWebApplicationInitializer.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.context; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.annotation.Order; 6 | import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; 7 | 8 | import com.risucci.quickstart.context.adapter.WebApplicationConfigurerAdapter; 9 | import com.risucci.quickstart.context.adapter.WebApplicationSecurityConfigurerAdapter; 10 | 11 | 12 | @Configuration 13 | @ComponentScan(basePackages = { "com.risucci.quickstart" }) 14 | @Order(1) 15 | public class QuickstartWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 16 | 17 | @Override 18 | protected Class>[] getRootConfigClasses() { 19 | return new Class>[] { QuickstartWebApplicationInitializer.class }; 20 | } 21 | 22 | /** 23 | * {@link WebApplicationConfigurerAdapter} and 24 | * {@link WebApplicationSecurityConfigurerAdapter} already being scanned. 25 | */ 26 | @Override 27 | protected Class>[] getServletConfigClasses() { 28 | return new Class>[] {}; 29 | } 30 | 31 | @Override 32 | protected String[] getServletMappings() { 33 | return new String[] { "/rest/*" }; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/context/adapter/WebApplicationConfigurerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.context.adapter; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; 5 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 7 | 8 | @Configuration 9 | @EnableWebMvc 10 | public class WebApplicationConfigurerAdapter extends WebMvcConfigurerAdapter { 11 | 12 | @Override 13 | public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 14 | configurer.enable(); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/context/adapter/WebApplicationSecurityConfigurerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.context.adapter; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 8 | 9 | @Configuration 10 | @EnableWebSecurity(debug = false) 11 | public class WebApplicationSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 12 | 13 | @Override 14 | protected void configure(HttpSecurity http) throws Exception { 15 | 16 | // Security policy: login page. 17 | http.formLogin() // 18 | .loginPage("/public/login.xhtml") // 19 | .loginProcessingUrl("/public/login.xhtml") // 20 | .defaultSuccessUrl("/protected/index.xhtml") // 21 | .failureUrl("/public/login.xhtml?source=loginError") // 22 | .permitAll(); 23 | 24 | // Security policy: public available paths 25 | http.authorizeRequests() // 26 | .antMatchers("/").permitAll() // 27 | .antMatchers("/index.html").permitAll() // 28 | .antMatchers("/public/**", "/resources/**", "/javax.faces.resource/**").permitAll(); 29 | 30 | // Security policy: protecting all remaining paths. 31 | http.authorizeRequests() // 32 | .anyRequest().authenticated(); 33 | 34 | // Logout handling. 35 | http.logout() // 36 | .logoutUrl("/logout") // 37 | .logoutSuccessUrl("/public/login.xhtml?source=logout") // 38 | .permitAll(); 39 | 40 | /* 41 | * Security policy: disabling CSRF protection. We must use it, but for 42 | * now, I prefer to disable it to prevent more configuration overloads. 43 | */ 44 | http.csrf().disable(); 45 | } 46 | 47 | @Override 48 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 49 | auth.inMemoryAuthentication() // 50 | .withUser("admin") // 51 | .password("123456") // 52 | .roles("ADMIN"); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/context/configuration/Database.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.context.configuration; 2 | 3 | import java.util.Properties; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import org.apache.commons.dbcp2.BasicDataSourceFactory; 8 | import org.apache.commons.logging.Log; 9 | import org.apache.commons.logging.LogFactory; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | import org.springframework.core.io.Resource; 14 | import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; 15 | import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor; 16 | import org.springframework.transaction.annotation.EnableTransactionManagement; 17 | 18 | @Configuration 19 | @EnableTransactionManagement 20 | public class Database { 21 | 22 | private static final String DATASOURCE = "classpath:datasource.properties"; 23 | private static final Log log = LogFactory.getLog(Database.class); 24 | 25 | @Bean 26 | public DataSource dataSource(@Value(DATASOURCE) Resource ds) throws Exception { 27 | log.info("Loading DataSource."); 28 | Properties properties = new Properties(); 29 | properties.load(ds.getInputStream()); 30 | return BasicDataSourceFactory.createDataSource(properties); 31 | } 32 | 33 | @Bean 34 | public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() { 35 | log.info("Loading PersistenceExceptionTranslationPostProcessor."); 36 | return new PersistenceExceptionTranslationPostProcessor(); 37 | } 38 | 39 | @Bean 40 | public PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() { 41 | log.info("Loading PersistenceAnnotationBeanPostProcessor."); 42 | return new PersistenceAnnotationBeanPostProcessor(); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/context/configuration/Jpa.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.context.configuration; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import javax.persistence.EntityManagerFactory; 7 | import javax.persistence.SharedCacheMode; 8 | import javax.sql.DataSource; 9 | 10 | import org.apache.commons.logging.Log; 11 | import org.apache.commons.logging.LogFactory; 12 | import org.hibernate.dialect.H2Dialect; 13 | import org.springframework.beans.factory.annotation.Autowire; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.beans.factory.annotation.Value; 16 | import org.springframework.context.annotation.Bean; 17 | import org.springframework.context.annotation.ComponentScan; 18 | import org.springframework.context.annotation.Configuration; 19 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 20 | import org.springframework.orm.jpa.JpaTransactionManager; 21 | import org.springframework.orm.jpa.JpaVendorAdapter; 22 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 23 | import org.springframework.orm.jpa.vendor.Database; 24 | import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; 25 | import org.springframework.transaction.PlatformTransactionManager; 26 | 27 | import com.risucci.quickstart.context.QuickstartWebApplicationInitializer; 28 | 29 | @Configuration 30 | @EnableJpaRepositories(basePackages = "com.risucci.quickstart") 31 | public class Jpa { 32 | 33 | private static final Log log = LogFactory.getLog(Jpa.class); 34 | 35 | @Bean 36 | @Autowired 37 | public LocalContainerEntityManagerFactoryBean entityManagerFactory( // 38 | DataSource dataSource, // 39 | JpaVendorAdapter jpaVendorAdapter, // 40 | @Value("#{packagesToScan}") String[] packagesToScan, // 41 | @Value("#{sharedCacheMode}") SharedCacheMode sharedCacheMode, // 42 | @Value("#{jpaPropertiesMap}") Map jpaPropertiesMap) { 43 | 44 | log.info("Loading JPA EntityManagerFactory."); 45 | LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean(); 46 | bean.setDataSource(dataSource); 47 | bean.setJpaVendorAdapter(jpaVendorAdapter); 48 | bean.setPackagesToScan(packagesToScan); 49 | bean.setSharedCacheMode(sharedCacheMode); 50 | bean.setJpaPropertyMap(jpaPropertiesMap); 51 | bean.afterPropertiesSet(); 52 | return bean; 53 | } 54 | 55 | /** 56 | * {@link JpaTransactionManager} also supports direct DataSource access 57 | * within a transaction (i.e. plain JDBC code working with the same 58 | * DataSource). This allows for mixing services which access JPA and 59 | * services which use plain JDBC (without being aware of JPA)! Application 60 | * code needs to stick to the same simple Connection lookup pattern as with 61 | * DataSourceTransactionManager (i.e. 62 | * DataSourceUtils.getConnection(javax.sql.DataSource) or going through a 63 | * TransactionAwareDataSourceProxy). Note that this requires a 64 | * vendor-specific JpaDialect to be configured 65 | * 66 | * @param entityManagerFactory 67 | * @return 68 | */ 69 | @Bean 70 | @Autowired 71 | public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { 72 | log.info("Loading JPA Transaction Management."); 73 | return new JpaTransactionManager(entityManagerFactory); 74 | } 75 | 76 | /* 77 | * DEFINITIONS 78 | */ 79 | 80 | @Bean(autowire = Autowire.BY_NAME) 81 | public String[] packagesToScan() { 82 | return QuickstartWebApplicationInitializer.class.getAnnotation(ComponentScan.class).basePackages(); 83 | } 84 | 85 | @Bean(autowire = Autowire.BY_NAME) 86 | public Database jpaVendorDatabase() { 87 | return Database.H2; 88 | } 89 | 90 | @Bean(autowire = Autowire.BY_NAME) 91 | public Boolean generateDdl() { 92 | return Boolean.TRUE; 93 | } 94 | 95 | @Bean(autowire = Autowire.BY_NAME) 96 | public Boolean showSql() { 97 | return Boolean.TRUE; 98 | } 99 | 100 | @Bean(autowire = Autowire.BY_NAME) 101 | public SharedCacheMode sharedCacheMode() { 102 | return SharedCacheMode.ENABLE_SELECTIVE; 103 | } 104 | 105 | /* 106 | * HIBERNATE 107 | */ 108 | 109 | public enum Hbm2Ddl { 110 | NONE("none"), VALIDATE("validate"), UPDATE("update"), CREATE("create"), CREATE_AND_DROP("create-drop"); 111 | 112 | private String value; 113 | 114 | private Hbm2Ddl(String value) { 115 | this.value = value; 116 | } 117 | 118 | public String getValue() { 119 | return value; 120 | } 121 | } 122 | 123 | @Bean 124 | @Autowired 125 | public JpaVendorAdapter jpaVendorAdapter( // 126 | @Value("#{jpaVendorDatabase}") Database jpaVendorDatabase, // 127 | @Value("#{jpaVendorDialect}") String jpaVendorDialect, // 128 | @Value("#{generateDdl}") Boolean generateDdl, // 129 | @Value("#{showSql}") Boolean showSql) { 130 | 131 | log.info("Loading Hibernate as JPA vendor."); 132 | HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); 133 | adapter.setDatabase(jpaVendorDatabase); 134 | adapter.setDatabasePlatform(jpaVendorDialect); 135 | adapter.setGenerateDdl(generateDdl); 136 | adapter.setShowSql(showSql); 137 | return adapter; 138 | } 139 | 140 | @Bean(autowire = Autowire.BY_NAME) 141 | public String jpaVendorDialect() { 142 | return H2Dialect.class.getName(); 143 | } 144 | 145 | @Bean(autowire = Autowire.BY_NAME) 146 | public Map jpaPropertiesMap() { 147 | Map bean = new HashMap(); 148 | bean.put("hibernate.hbm2ddl.auto", Hbm2Ddl.UPDATE.getValue()); 149 | bean.put("hibernate.format_sql", true); 150 | // Prevents the throwing of LazyInitializationException. 151 | bean.put("hibernate.enable_lazy_load_no_trans", true); 152 | return bean; 153 | } 154 | 155 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/context/event/ApplicationLoaderListener.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.context.event; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.context.ApplicationListener; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.stereotype.Component; 10 | 11 | import com.risucci.quickstart.jsf.model.Country; 12 | import com.risucci.quickstart.repository.CountryRepository; 13 | 14 | /** 15 | * Spring application context loader that checks if database has initial data. 16 | * If not, it fills database with some mock data. 17 | * 18 | * @author Michel Risucci 19 | */ 20 | @Component 21 | public class ApplicationLoaderListener implements ApplicationListener { 22 | 23 | private CountryRepository countryRepository; 24 | 25 | @Override 26 | public void onApplicationEvent(ContextRefreshedEvent event) { 27 | ApplicationContext context = event.getApplicationContext(); 28 | if (context.getParent() != null) { 29 | this.countryRepository = context.getBean(CountryRepository.class); 30 | long count = countryRepository.count(); 31 | if (count == 0) { 32 | initializeDatabaseWithMockData(); 33 | } 34 | } 35 | } 36 | 37 | private void initializeDatabaseWithMockData() { 38 | List countries = Arrays.asList( // 39 | new Country("Brazil", "BRA", 200_000_000l), // 40 | new Country("Canada", "CAN", 31147000L), // 41 | new Country("Portugal", "PRT", 9997600L), // 42 | new Country("United States", "USA", 315_000_000l), // 43 | new Country("Argentina", "ARG", 42_000_000l), // 44 | new Country("China", "CHN", 1_350_000_000l), // 45 | new Country("India", "IND", 1_250_000_000l), // 46 | new Country("Afghanistan", "AFG", 22720000L), // 47 | new Country("Netherlands", "NLD", 15864000L), // 48 | new Country("Algeria", "DZA", 31471000L), // 49 | new Country("Angola", "AGO", 12878000L), // 50 | new Country("United Arab Emirates", "ARE", 2441000L), // 51 | new Country("United Kingdom", "GBR", 59623400L), // 52 | new Country("Hong Kong", "HKG", 6782000L), // 53 | new Country("Ireland", "IRL", 3775100L), // 54 | new Country("Italy", "ITA", 57680000L), // 55 | new Country("Jamaica", "JAM", 2583000L), // 56 | new Country("Japan", "JPN", 126714000L), // 57 | new Country("South Korea", "KOR", 46844000L), // 58 | new Country("Cuba", "CUB", 11201000L), // 59 | new Country("Lebanon", "LBN", 3282000L), // 60 | new Country("Mexico", "MEX", 98881000L), // 61 | new Country("France", "FRA", 59225700L) // 62 | ); 63 | 64 | countryRepository.save(countries); 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/jsf/bean/CountryBean.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.jsf.bean; 2 | 3 | import static com.risucci.quickstart.jsf.util.FacesMessageSeverity.ERROR; 4 | import static com.risucci.quickstart.jsf.util.FacesMessageSeverity.INFO; 5 | import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.exact; 6 | import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.startsWith; 7 | import static org.springframework.data.domain.ExampleMatcher.StringMatcher.CONTAINING; 8 | 9 | import java.util.Map; 10 | 11 | import javax.annotation.PostConstruct; 12 | import javax.faces.bean.ManagedBean; 13 | import javax.faces.bean.ViewScoped; 14 | import javax.faces.context.ExternalContext; 15 | import javax.faces.context.FacesContext; 16 | import javax.faces.event.AjaxBehaviorEvent; 17 | import javax.inject.Inject; 18 | 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.data.domain.Example; 21 | import org.springframework.data.domain.ExampleMatcher; 22 | import org.springframework.data.domain.Page; 23 | import org.springframework.data.domain.PageRequest; 24 | import org.springframework.util.StringUtils; 25 | import org.springframework.web.context.support.SpringBeanAutowiringSupport; 26 | 27 | import com.risucci.quickstart.jsf.model.Country; 28 | import com.risucci.quickstart.jsf.util.FacesUtils; 29 | import com.risucci.quickstart.repository.CountryRepository; 30 | 31 | /** 32 | * Making the JSF bean extend {@link SpringBeanAutowiringSupport} is the 33 | * simplest way to seamlessly integrate JSF Context with Spring, enabling 34 | * features like DI via @{@link Inject} or @{@link Autowired}. Spring does not 35 | * provide a powerful built-in JSF integration module. 36 | * 37 | * @author Michel Risucci 38 | */ 39 | @ManagedBean 40 | @ViewScoped 41 | public class CountryBean extends SpringBeanAutowiringSupport { 42 | 43 | private static final ExampleMatcher MATCHER = ExampleMatcher.matching() // 44 | .withStringMatcher(CONTAINING) // 45 | .withIgnoreCase() // 46 | .withMatcher("name", startsWith()) // 47 | .withMatcher("acronym", startsWith()) // 48 | .withMatcher("population", exact()); 49 | 50 | @Autowired 51 | private CountryRepository repository; 52 | 53 | // Entity Handlers 54 | private int pageSize; 55 | private int pageIndex; 56 | private Page items; 57 | private Country item; 58 | 59 | @PostConstruct 60 | private void postConstruct() { 61 | pageSize = 10; 62 | pageIndex = 0; 63 | 64 | FacesContext fc = FacesContext.getCurrentInstance(); 65 | ExternalContext ec = fc.getExternalContext(); 66 | Map rp = ec.getRequestParameterMap(); 67 | 68 | String id = rp.get("id"); 69 | if (id != null) { 70 | this.item = repository.findOne(Long.valueOf(id)); 71 | } else { 72 | eraseFilter(); 73 | } 74 | } 75 | 76 | /* 77 | * Actions 78 | */ 79 | 80 | public void save(AjaxBehaviorEvent event) { 81 | try { 82 | item = repository.save(item); 83 | 84 | FacesUtils.addI18nGlobalMessage(INFO, "operations.success.save", item.getName()); 85 | FacesUtils.redirect("/protected/manage/country-list.xhtml"); 86 | } catch (Exception e) { 87 | FacesUtils.addI18nGlobalMessage(ERROR, "operations.failWithDetails", e.getMessage()); 88 | } 89 | } 90 | 91 | public void remove(AjaxBehaviorEvent event) { 92 | try { 93 | repository.delete(item.getId()); 94 | 95 | FacesUtils.addI18nGlobalMessage(INFO, "operations.success.remove", item.getName()); 96 | FacesUtils.redirect("/protected/manage/country-list.xhtml"); 97 | } catch (Exception e) { 98 | FacesUtils.addI18nGlobalMessage(ERROR, "operations.failWithDetails", e.getMessage()); 99 | } 100 | } 101 | 102 | public void filter() { 103 | // Nullifying empty values 104 | if (StringUtils.isEmpty(item.getName())) { 105 | item.setName(null); 106 | } 107 | if (StringUtils.isEmpty(item.getAcronym())) { 108 | item.setAcronym(null); 109 | } 110 | 111 | // Counting page with conditionals 112 | Example example = Example.of(item, MATCHER); 113 | long count = repository.count(example); 114 | 115 | // If first FETCH is an index out of count range, reset page index 116 | int firstFetchOnPage = pageIndex * pageSize; 117 | if (firstFetchOnPage > count) { 118 | pageIndex = 0; 119 | } 120 | 121 | // Filtering page with conditionals 122 | PageRequest pageRequest = new PageRequest(pageIndex, pageSize); 123 | items = repository.findAll(example, pageRequest); 124 | } 125 | 126 | public void eraseFilter() { 127 | this.item = new Country(); 128 | this.filter(); 129 | } 130 | 131 | /* 132 | * Getters and Setters 133 | */ 134 | 135 | public int getPageSize() { 136 | return pageSize; 137 | } 138 | 139 | public void setPageSize(int pageSize) { 140 | this.pageSize = pageSize; 141 | } 142 | 143 | public int getPageIndex() { 144 | return pageIndex; 145 | } 146 | 147 | public void setPageIndex(int pageIndex) { 148 | this.pageIndex = pageIndex; 149 | } 150 | 151 | public Page getItems() { 152 | return items; 153 | } 154 | 155 | public void setItems(Page items) { 156 | this.items = items; 157 | } 158 | 159 | public Country getItem() { 160 | return item; 161 | } 162 | 163 | public void setItem(Country item) { 164 | this.item = item; 165 | } 166 | 167 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/jsf/bean/LocaleManager.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.jsf.bean; 2 | 3 | import java.util.Locale; 4 | import java.util.Map; 5 | 6 | import javax.annotation.PostConstruct; 7 | import javax.faces.bean.ManagedBean; 8 | import javax.faces.bean.RequestScoped; 9 | import javax.faces.component.UIViewRoot; 10 | import javax.faces.context.ExternalContext; 11 | import javax.faces.context.FacesContext; 12 | import javax.servlet.http.HttpSession; 13 | 14 | @ManagedBean 15 | @RequestScoped 16 | public class LocaleManager { 17 | 18 | private static final String LOCALE_KEY = "localeManager.locale"; 19 | 20 | private HttpSession session; 21 | 22 | @PostConstruct 23 | public void postConstruct() { 24 | FacesContext fc = FacesContext.getCurrentInstance(); 25 | UIViewRoot vr = fc.getViewRoot(); 26 | ExternalContext ec = fc.getExternalContext(); 27 | session = (HttpSession) ec.getSession(true); 28 | Map rp = ec.getRequestParameterMap(); 29 | String lang = rp.get("lang"); 30 | 31 | Locale currentLocale = (Locale) session.getAttribute(LOCALE_KEY); 32 | if (currentLocale == null) { 33 | session.setAttribute(LOCALE_KEY, vr.getLocale()); 34 | } else if (lang != null) { 35 | Locale locale = Locale.forLanguageTag(lang); 36 | session.setAttribute(LOCALE_KEY, locale); 37 | } 38 | } 39 | 40 | public Locale getLocale() { 41 | return (Locale) session.getAttribute(LOCALE_KEY); 42 | } 43 | 44 | public String getLanguage() { 45 | return getLocale().getLanguage(); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/jsf/model/Country.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.jsf.model; 2 | 3 | import javax.persistence.Basic; 4 | import javax.persistence.Column; 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | import javax.persistence.Table; 10 | 11 | /** 12 | * @author Michel Risucci 13 | */ 14 | @Entity 15 | @Table(name = "country") 16 | public class Country { 17 | 18 | private Long id; 19 | private String name; 20 | private String acronym; 21 | private Long population; 22 | 23 | /** 24 | * Default no-arg constructor 25 | */ 26 | public Country() { 27 | } 28 | 29 | /** 30 | * @param name 31 | * @param acronym 32 | * @param population 33 | */ 34 | public Country(String name, String acronym, long population) { 35 | this.name = name; 36 | this.acronym = acronym; 37 | this.population = Long.valueOf(population); 38 | } 39 | 40 | /** 41 | * @return 42 | */ 43 | @Id 44 | @GeneratedValue(strategy = GenerationType.AUTO) 45 | @Column(name = "id") 46 | public Long getId() { 47 | return id; 48 | } 49 | 50 | /** 51 | * @param id 52 | */ 53 | public void setId(Long id) { 54 | this.id = id; 55 | } 56 | 57 | /** 58 | * @return 59 | */ 60 | @Basic(optional = false) 61 | @Column(name = "name", nullable = false, length = 64) 62 | public String getName() { 63 | return name; 64 | } 65 | 66 | /** 67 | * @param name 68 | */ 69 | public void setName(String name) { 70 | this.name = name; 71 | } 72 | 73 | /** 74 | * @return 75 | */ 76 | @Basic(optional = true) 77 | @Column(name = "acronym", nullable = true, length = 4) 78 | public String getAcronym() { 79 | return acronym; 80 | } 81 | 82 | /** 83 | * @param acronym 84 | */ 85 | public void setAcronym(String acronym) { 86 | this.acronym = acronym; 87 | } 88 | 89 | /** 90 | * @return 91 | */ 92 | @Basic(optional = true) 93 | @Column(name = "population", nullable = true) 94 | public Long getPopulation() { 95 | return population; 96 | } 97 | 98 | /** 99 | * @param population 100 | */ 101 | public void setPopulation(Long population) { 102 | this.population = population; 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/jsf/util/FacesMessageSeverity.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.jsf.util; 2 | 3 | import javax.faces.application.FacesMessage; 4 | import javax.faces.application.FacesMessage.Severity; 5 | 6 | public enum FacesMessageSeverity { 7 | 8 | INFO(FacesMessage.SEVERITY_INFO), // 9 | WARN(FacesMessage.SEVERITY_WARN), // 10 | ERROR(FacesMessage.SEVERITY_ERROR), // 11 | FATAL(FacesMessage.SEVERITY_FATAL); 12 | 13 | private Severity severity; 14 | 15 | private FacesMessageSeverity(Severity severity) { 16 | this.severity = severity; 17 | } 18 | 19 | public Severity getSeverity() { 20 | return severity; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/jsf/util/FacesUtils.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.jsf.util; 2 | 3 | import java.text.MessageFormat; 4 | import java.util.ResourceBundle; 5 | 6 | import javax.faces.application.Application; 7 | import javax.faces.application.FacesMessage; 8 | import javax.faces.application.NavigationHandler; 9 | import javax.faces.context.ExternalContext; 10 | import javax.faces.context.FacesContext; 11 | import javax.faces.context.Flash; 12 | 13 | public final class FacesUtils { 14 | 15 | public static final String I18N_BUNDLE_NAME = "com.github.michelrisucci.jsf.i18n"; 16 | public static final String I18N_BUNDLE_VAR = "i18n"; 17 | 18 | private FacesUtils() { 19 | } 20 | 21 | /* 22 | * Static Functionalities 23 | */ 24 | 25 | public static FacesContext getFacesContext() { 26 | return FacesContext.getCurrentInstance(); 27 | } 28 | 29 | public static ResourceBundle getResourceBundle() { 30 | FacesContext context = getFacesContext(); 31 | Application application = context.getApplication(); 32 | return application.getResourceBundle(context, I18N_BUNDLE_VAR); 33 | } 34 | 35 | public static String formatI18nMessage(String I18nMessage, Object... arguments) { 36 | ResourceBundle bundle = getResourceBundle(); 37 | return MessageFormat.format(bundle.getString(I18nMessage), arguments); 38 | } 39 | 40 | public static void addGlobalMessage(FacesMessageSeverity severity, String title, String detail) { 41 | getFacesContext().addMessage(null, new FacesMessage(severity.getSeverity(), title, detail)); 42 | } 43 | 44 | public static void addGlobalMessage(FacesMessageSeverity severity, String message) { 45 | addGlobalMessage(severity, message, null); 46 | } 47 | 48 | public static void addI18nGlobalMessage(FacesMessageSeverity severity, String i18nTitle, Object[] titleArgs, 49 | String i18nDetail, Object[] detailArgs) { 50 | String title = formatI18nMessage(i18nTitle, titleArgs); 51 | if (i18nDetail != null && !i18nDetail.isEmpty()) { 52 | String detail = formatI18nMessage(i18nDetail, detailArgs); 53 | addGlobalMessage(severity, title, detail); 54 | } else { 55 | addGlobalMessage(severity, title); 56 | } 57 | } 58 | 59 | public static void addI18nGlobalMessage(FacesMessageSeverity severity, String i18nMessage, Object... args) { 60 | addI18nGlobalMessage(severity, i18nMessage, args, null, null); 61 | } 62 | 63 | public static void redirect(String path) { 64 | if (path.contains("?")) { 65 | path += "&faces-redirect=true"; 66 | } else { 67 | path += "?faces-redirect=true"; 68 | } 69 | 70 | FacesContext fc = getFacesContext(); 71 | ExternalContext ec = fc.getExternalContext(); 72 | Flash flashContext = ec.getFlash(); 73 | if (!flashContext.isKeepMessages()) { 74 | flashContext.setKeepMessages(true); 75 | } 76 | 77 | NavigationHandler nh = fc.getApplication().getNavigationHandler(); 78 | nh.handleNavigation(fc, null, path); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/risucci/quickstart/repository/CountryRepository.java: -------------------------------------------------------------------------------- 1 | package com.risucci.quickstart.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import com.risucci.quickstart.jsf.model.Country; 6 | 7 | /** 8 | * @author Michel Risucci 9 | */ 10 | public interface CountryRepository extends JpaRepository { 11 | } -------------------------------------------------------------------------------- /src/main/resources/com/risucci/quickstart/ascii_table.txt: -------------------------------------------------------------------------------- 1 | # decimal hexadecimal html encode xml javascript java (unicode) 2 | # 0 0 � \x00 \u0000 3 | # 9 9 	 \x09 \u0009 4 | # 10 A \x0A \u000A 5 | # 11 B  \x0B \u000B 6 | # 12 C  \x0C \u000C 7 | # 13 D \x0D \u000D 8 | # 32 20   \x20 \u0020 9 | # ! 33 21 ! ! \x21 \u0021 10 | # " 34 22 " " \x22 \u0022 11 | # # 35 23 # # \x23 \u0023 12 | # $ 36 24 $ $ \x24 \u0024 13 | # % 37 25 % % \x25 \u0025 14 | # & 38 26 & & \x26 \u0026 15 | # ' 39 27 ' ' \x27 \u0027 16 | # ( 40 28 ( ( \x28 \u0028 17 | # ) 41 29 ) ) \x29 \u0029 18 | # * 42 2A * * \x2A \u002A 19 | # + 43 2B + + \x2B \u002B 20 | # , 44 2C , , \x2C \u002C 21 | # - 45 2D - - \x2D \u002D 22 | # . 46 2E . . \x2E \u002E 23 | # / 47 2F / / \x2F \u002F 24 | # 0 48 30 0 0 \x30 \u0030 25 | # 1 49 31 1 1 \x31 \u0031 26 | # 2 50 32 2 2 \x32 \u0032 27 | # 3 51 33 3 3 \x33 \u0033 28 | # 4 52 34 4 4 \x34 \u0034 29 | # 5 53 35 5 5 \x35 \u0035 30 | # 6 54 36 6 6 \x36 \u0036 31 | # 7 55 37 7 7 \x37 \u0037 32 | # 8 56 38 8 8 \x38 \u0038 33 | # 9 57 39 9 9 \x39 \u0039 34 | # : 58 3A : : \x3A \u003A 35 | # ; 59 3B ; ; \x3B \u003B 36 | # < 60 3C < < \x3C \u003C 37 | # = 61 3D = = \x3D \u003D 38 | # > 62 3E > > \x3E \u003E 39 | # ? 63 3F ? ? \x3F \u003F 40 | # @ 64 40 @ @ \x40 \u0040 41 | # A 65 41 A A \x41 \u0041 42 | # B 66 42 B B \x42 \u0042 43 | # C 67 43 C C \x43 \u0043 44 | # D 68 44 D D \x44 \u0044 45 | # E 69 45 E E \x45 \u0045 46 | # F 70 46 F F \x46 \u0046 47 | # G 71 47 G G \x47 \u0047 48 | # H 72 48 H H \x48 \u0048 49 | # I 73 49 I I \x49 \u0049 50 | # J 74 4A J J \x4A \u004A 51 | # K 75 4B K K \x4B \u004B 52 | # L 76 4C L L \x4C \u004C 53 | # M 77 4D M M \x4D \u004D 54 | # N 78 4E N N \x4E \u004E 55 | # O 79 4F O O \x4F \u004F 56 | # P 80 50 P P \x50 \u0050 57 | # Q 81 51 Q Q \x51 \u0051 58 | # R 82 52 R R \x52 \u0052 59 | # S 83 53 S S \x53 \u0053 60 | # T 84 54 T T \x54 \u0054 61 | # U 85 55 U U \x55 \u0055 62 | # V 86 56 V V \x56 \u0056 63 | # W 87 57 W W \x57 \u0057 64 | # X 88 58 X X \x58 \u0058 65 | # Y 89 59 Y Y \x59 \u0059 66 | # Z 90 5A Z Z \x5A \u005A 67 | # [ 91 5B [ [ \x5B \u005B 68 | # \ 92 5C \ \ \x5C \u005C 69 | # ] 93 5D ] ] \x5D \u005D 70 | # ^ 94 5E ^ ^ \x5E \u005E 71 | # _ 95 5F _ _ \x5F \u005F 72 | # ` 96 60 ` ` \x60 \u0060 73 | # a 97 61 a a \x61 \u0061 74 | # b 98 62 b b \x62 \u0062 75 | # c 99 63 c c \x63 \u0063 76 | # d 100 64 d d \x64 \u0064 77 | # e 101 65 e e \x65 \u0065 78 | # f 102 66 f f \x66 \u0066 79 | # g 103 67 g g \x67 \u0067 80 | # h 104 68 h h \x68 \u0068 81 | # i 105 69 i i \x69 \u0069 82 | # j 106 6A j j \x6A \u006A 83 | # k 107 6B k k \x6B \u006B 84 | # l 108 6C l l \x6C \u006C 85 | # m 109 6D m m \x6D \u006D 86 | # n 110 6E n n \x6E \u006E 87 | # o 111 6F o o \x6F \u006F 88 | # p 112 70 p p \x70 \u0070 89 | # q 113 71 q q \x71 \u0071 90 | # r 114 72 r r \x72 \u0072 91 | # s 115 73 s s \x73 \u0073 92 | # t 116 74 t t \x74 \u0074 93 | # u 117 75 u u \x75 \u0075 94 | # v 118 76 v v \x76 \u0076 95 | # w 119 77 w w \x77 \u0077 96 | # x 120 78 x x \x78 \u0078 97 | # y 121 79 y y \x79 \u0079 98 | # z 122 7A z z \x7A \u007A 99 | # { 123 7B { { \x7B \u007B 100 | # | 124 7C | | \x7C \u007C 101 | # } 125 7D } } \x7D \u007D 102 | # ~ 126 7E ~ ~ \x7E \u007E 103 | # 160 A0   \xA0 \u00A0 104 | # ¡ 161 A1 ¡ ¡ \xA1 \u00A1 105 | # ¢ 162 A2 ¢ ¢ \xA2 \u00A2 106 | # £ 163 A3 £ £ \xA3 \u00A3 107 | # ¤ 164 A4 ¤ ¤ \xA4 \u00A4 108 | # ¥ 165 A5 ¥ ¥ \xA5 \u00A5 109 | # ¦ 166 A6 ¦ ¦ \xA6 \u00A6 110 | # § 167 A7 § § \xA7 \u00A7 111 | # ¨ 168 A8 ¨ ¨ \xA8 \u00A8 112 | # © 169 A9 © © \xA9 \u00A9 113 | # ª 170 AA ª ª \xAA \u00AA 114 | # « 171 AB « « \xAB \u00AB 115 | # ¬ 172 AC ¬ ¬ \xAC \u00AC 116 | # 173 AD ­ \xAD \u00AD 117 | # ® 174 AE ® ® \xAE \u00AE 118 | # ¯ 175 AF ¯ ¯ \xAF \u00AF 119 | # ° 176 B0 ° ° \xB0 \u00B0 120 | # ± 177 B1 ± ± \xB1 \u00B1 121 | # ² 178 B2 ² ² \xB2 \u00B2 122 | # ³ 179 B3 ³ ³ \xB3 \u00B3 123 | # ´ 180 B4 ´ ´ \xB4 \u00B4 124 | # µ 181 B5 µ µ \xB5 \u00B5 125 | # ¶ 182 B6 ¶ ¶ \xB6 \u00B6 126 | # · 183 B7 · · \xB7 \u00B7 127 | # ¸ 184 B8 ¸ ¸ \xB8 \u00B8 128 | # ¹ 185 B9 ¹ ¹ \xB9 \u00B9 129 | # º 186 BA º º \xBA \u00BA 130 | # » 187 BB » » \xBB \u00BB 131 | # ¼ 188 BC ¼ ¼ \xBC \u00BC 132 | # ½ 189 BD ½ ½ \xBD \u00BD 133 | # ¾ 190 BE ¾ ¾ \xBE \u00BE 134 | # ¿ 191 BF ¿ ¿ \xBF \u00BF 135 | # À 192 C0 À À \xC0 \u00C0 136 | # Á 193 C1 Á Á \xC1 \u00C1 137 | # Â 194 C2 Â Â \xC2 \u00C2 138 | # Ã 195 C3 Ã Ã \xC3 \u00C3 139 | # Ä 196 C4 Ä Ä \xC4 \u00C4 140 | # Å 197 C5 Å Å \xC5 \u00C5 141 | # Æ 198 C6 Æ Æ \xC6 \u00C6 142 | # Ç 199 C7 Ç Ç \xC7 \u00C7 143 | # È 200 C8 È È \xC8 \u00C8 144 | # É 201 C9 É É \xC9 \u00C9 145 | # Ê 202 CA Ê Ê \xCA \u00CA 146 | # Ë 203 CB Ë Ë \xCB \u00CB 147 | # Ì 204 CC Ì Ì \xCC \u00CC 148 | # Í 205 CD Í Í \xCD \u00CD 149 | # Î 206 CE Î Î \xCE \u00CE 150 | # Ï 207 CF Ï Ï \xCF \u00CF 151 | # Ð 208 D0 Ð Ð \xD0 \u00D0 152 | # Ñ 209 D1 Ñ Ñ \xD1 \u00D1 153 | # Ò 210 D2 Ò Ò \xD2 \u00D2 154 | # Ó 211 D3 Ó Ó \xD3 \u00D3 155 | # Ô 212 D4 Ô Ô \xD4 \u00D4 156 | # Õ 213 D5 Õ Õ \xD5 \u00D5 157 | # Ö 214 D6 Ö Ö \xD6 \u00D6 158 | # × 215 D7 × × \xD7 \u00D7 159 | # Ø 216 D8 Ø Ø \xD8 \u00D8 160 | # Ù 217 D9 Ù Ù \xD9 \u00D9 161 | # Ú 218 DA Ú Ú \xDA \u00DA 162 | # Û 219 DB Û Û \xDB \u00DB 163 | # Ü 220 DC Ü Ü \xDC \u00DC 164 | # Ý 221 DD Ý Ý \xDD \u00DD 165 | # Þ 222 DE Þ Þ \xDE \u00DE 166 | # ß 223 DF ß ß \xDF \u00DF 167 | # à 224 E0 à à \xE0 \u00E0 168 | # á 225 E1 á á \xE1 \u00E1 169 | # â 226 E2 â â \xE2 \u00E2 170 | # ã 227 E3 ã ã \xE3 \u00E3 171 | # ä 228 E4 ä ä \xE4 \u00E4 172 | # å 229 E5 å å \xE5 \u00E5 173 | # æ 230 E6 æ æ \xE6 \u00E6 174 | # ç 231 E7 ç ç \xE7 \u00E7 175 | # è 232 E8 è è \xE8 \u00E8 176 | # é 233 E9 é é \xE9 \u00E9 177 | # ê 234 EA ê ê \xEA \u00EA 178 | # ë 235 EB ë ë \xEB \u00EB 179 | # ì 236 EC ì ì \xEC \u00EC 180 | # í 237 ED í í \xED \u00ED 181 | # î 238 EE î î \xEE \u00EE 182 | # ï 239 EF ï ï \xEF \u00EF 183 | # ð 240 F0 ð ð \xF0 \u00F0 184 | # ñ 241 F1 ñ ñ \xF1 \u00F1 185 | # ò 242 F2 ò ò \xF2 \u00F2 186 | # ó 243 F3 ó ó \xF3 \u00F3 187 | # ô 244 F4 ô ô \xF4 \u00F4 188 | # õ 245 F5 õ õ \xF5 \u00F5 189 | # ö 246 F6 ö ö \xF6 \u00F6 190 | # ÷ 247 F7 ÷ ÷ \xF7 \u00F7 191 | # ø 248 F8 ø ø \xF8 \u00F8 192 | # ù 249 F9 ù ù \xF9 \u00F9 193 | # ú 250 FA ú ú \xFA \u00FA 194 | # û 251 FB û û \xFB \u00FB 195 | # ü 252 FC ü ü \xFC \u00FC 196 | # ý 253 FD ý ý \xFD \u00FD 197 | # þ 254 FE þ þ \xFE \u00FE 198 | # ÿ 255 FF ÿ ÿ \xFF \u00FF -------------------------------------------------------------------------------- /src/main/resources/com/risucci/quickstart/i18n_en.properties: -------------------------------------------------------------------------------- 1 | # GENERICS 2 | new = New 3 | save = Save 4 | submit = Submit 5 | cancel = Cancel 6 | find = Find 7 | filter = Filter 8 | erase = Erase 9 | edit = Edit 10 | remove = Remove 11 | actions = Actions 12 | language = Language 13 | language.en = English 14 | language.pt = Portuguese 15 | language.es = Spanish 16 | login.failure = Failure trying to sign in using submitted credentials. Sign in using username "admin" and password "123456". 17 | logout = Logout 18 | logout.success = Logout successfully. 19 | signIn = Sign In 20 | username = Username 21 | password = Password 22 | toggle = Toggle 23 | pagination = Pagination 24 | previous = Previous 25 | next = Next 26 | 27 | # OPERATIONS 28 | operations = Operations 29 | operations.success = Operations Success! 30 | operations.success.save = Success saving {0} 31 | operations.success.remove = Success removing {0} 32 | operations.fail = Operations Fail 33 | operations.failWithDetails = Operations Fail: {0} 34 | operations.remove.areYouSure = Are you sure you want to remove {0}? 35 | 36 | # ENTITIES 37 | country = Country 38 | countries = Countries 39 | country.name = Name 40 | country.acronym = Acronym 41 | country.population = Population -------------------------------------------------------------------------------- /src/main/resources/com/risucci/quickstart/i18n_es.properties: -------------------------------------------------------------------------------- 1 | # GENERICS 2 | new = Nuevo 3 | save = Grabar 4 | submit = Enviar 5 | cancel = Cancelar 6 | find = Buscar 7 | filter = Filtrar 8 | erase = Limpiar 9 | edit = Editar 10 | remove = Eliminar 11 | actions = Acciones 12 | language = Idioma 13 | language.en = Ingl\u00E9s 14 | language.pt = Portugu\u00E9s 15 | language.es = Espa\u00F1ol 16 | login.failure = Fallo al iniciar sesi\u00F3n con las credenciales informadas. Ingresar mediante usuario "admin" y contrase\u00F1a "123456". 17 | logout = Salir 18 | logout.success = Sesi\u00F3n cerrada con \u00E9xito. 19 | signIn = Ingresar 20 | username = Usuario 21 | password = Contrase\u00F1a 22 | toggle = Alternar 23 | pagination = Paginaci\u00F3n 24 | previous = Anterior 25 | next = Siguiente 26 | 27 | # OPERATIONS 28 | operations = Operaciones 29 | operations.success = ¡Operaci\u00F3n Exitosa! 30 | operations.success.save = \u00C9xito ao grabar {0} 31 | operations.success.remove = \u00C9xito ao eliminar {0} 32 | operations.fail = Operaci\u00F3nes con error 33 | operations.failWithDetails = Operaci\u00F3nes con error: {0} 34 | operations.remove.areYouSure = \u00BFEst\u00E1s seguro que quieres eliminar {0}? 35 | 36 | # ENTITIES 37 | country = Pa\u00EDs 38 | countries = Pa\u00EDses 39 | country.name = Nombre 40 | country.acronym = Sigla 41 | country.population = Poblaci\u00F3n -------------------------------------------------------------------------------- /src/main/resources/com/risucci/quickstart/i18n_pt.properties: -------------------------------------------------------------------------------- 1 | # GENERICS 2 | new = Novo 3 | save = Salvar 4 | submit = Enviar 5 | cancel = Cancelar 6 | find = Buscar 7 | filter = Filtrar 8 | erase = Limpar 9 | edit = Editar 10 | remove = Remover 11 | actions = A\u00E7\u00F5es 12 | language = Linguagem 13 | language.en = Ingl\u00EAs 14 | language.pt = Portugu\u00EAs 15 | language.es = Espanhol 16 | login.failure = Falha ao tentar efetuar login com as credenciais informadas. Entrar com usu\u00E1rio "admin" e senha "123456". 17 | logout = Sair 18 | logout.success = Sess\u00E3o finalizada com sucesso. 19 | signIn = Entrar 20 | username = Usu\u00E1rio 21 | password = Senha 22 | toggle = Alternar 23 | pagination = Pagina\u00E7\u00E3o 24 | previous = Anterior 25 | next = Pr\u00F3ximo 26 | 27 | # OPERATIONS 28 | operations = Opera\u00E7\u00F5es 29 | operations.success = \u00A1Sucesso nas Opera\u00E7\u00F5es! 30 | operations.success.save = Sucesso ao gravar {0} 31 | operations.success.remove = Sucesso ao remover {0} 32 | operations.fail = Falha nas Opera\u00E7\u00F5es 33 | operations.failWithDetails = Falha nas Opera\u00E7\u00F5es: {0} 34 | operations.remove.areYouSure = Tem certeza que deseja remover {0}? 35 | 36 | # ENTITIES 37 | country = Pa\u00EDs 38 | countries = Pa\u00EDses 39 | country.name = Nome 40 | country.acronym = Sigla 41 | country.population = Popula\u00E7\u00E3o -------------------------------------------------------------------------------- /src/main/resources/datasource.properties: -------------------------------------------------------------------------------- 1 | # ##################################################################################### # 2 | # ### FOR ADDITIONAL INFORMATION, SEE APACHE COMMONS DBCP2 CONFIGURATION PROPERTIES ### # 3 | # ######## AT http://commons.apache.org/proper/commons-dbcp/configuration.html ######## # 4 | # ##################################################################################### # 5 | 6 | # ##################################################################################### # 7 | # ################################# BASIC ADJUSTMENTS ################################# # 8 | # ##################################################################################### # 9 | 10 | # The connection username to be passed to our JDBC driver to establish a connection. 11 | username=quickstart 12 | 13 | # The connection password to be passed to our JDBC driver to establish a connection. 14 | password=quickstart 15 | 16 | # The connection URL to be passed to our JDBC driver to establish a connection. 17 | url=jdbc:h2:mem:quickstart 18 | 19 | # The fully qualified Java class name of the JDBC driver to be used. 20 | driverClassName=org.h2.Driver 21 | 22 | # The connection properties that will be sent to our JDBC driver when establishing new connections. 23 | # Format of the string must be [propertyName=property;]* 24 | # NOTE - The "user" and "password" properties will be passed explicitly, so they do not need to be included here. 25 | connectionProperties= 26 | 27 | # The SQL query that will be used to validate connections from this pool before returning them to the caller. If specified, this query MUST be an SQL SELECT statement that returns at least one row. If not specified, connections will be validation by calling the isValid() method. 28 | validationQuery=SELECT 1 29 | 30 | # The default auto-commit state of connections created by this pool. If not set then the setAutoCommit method will not be called. 31 | defaultAutoCommit=false 32 | 33 | # The default read-only state of connections created by this pool. If not set then the setReadOnly method will not be called. (Some drivers don't support read only mode, ex: Informix). 34 | defaultReadOnly=false 35 | 36 | # The default TransactionIsolation state of connections created by this pool. One of the following: (see javadoc) 37 | # - NONE 38 | # - READ_COMMITTED 39 | # - READ_UNCOMMITTED 40 | # - REPEATABLE_READ 41 | # - SERIALIZABLE 42 | defaultTransactionIsolation=READ_COMMITTED 43 | 44 | # The default catalog of connections created by this pool. 45 | defaultCatalog= 46 | 47 | # If true, the pooled connection will cache the current readOnly and autoCommit settings when first read or written and on all subsequent writes. This removes the need for additional database queries for any further calls to the getter. If the underlying connection is accessed directly and the readOnly and/or autoCommit settings changed the cached values will not reflect the current state. In this case, caching should be disabled by setting this attribute to false. 48 | cacheState=true 49 | 50 | # The initial number of connections that are created when the pool is started. 51 | initialSize=8 52 | 53 | # The maximum number of active connections that can be allocated from this pool at the same time, or negative for no limit. 54 | maxTotal=32 55 | 56 | # The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit. 57 | maxIdle=16 58 | 59 | # The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none. 60 | minIdle=8 61 | 62 | # The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or -1 to wait indefinitely. 63 | # default = -1 (indefinitely) 64 | maxWaitMillis=16000 65 | 66 | # ##################################################################################### # 67 | # ############################### ADVANCED ADJUSTMENTS ################################ # 68 | # ##################################################################################### # 69 | 70 | # The indication of whether objects will be validated after creation. If the object fails to validate, the borrow attempt that triggered the object creation will fail. 71 | testOnCreate=true 72 | 73 | # The indication of whether objects will be validated before being borrowed from the pool. If the object fails to validate, it will be dropped from the pool, and we will attempt to borrow another. 74 | testOnBorrow=true 75 | 76 | # The indication of whether objects will be validated before being returned to the pool. 77 | testOnReturn=true 78 | 79 | # The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to validate, it will be dropped from the pool. 80 | testWhileIdle=true 81 | 82 | # The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread will be run. 83 | timeBetweenEvictionRunsMillis=-1 84 | 85 | # The number of objects to examine during each run of the idle object evictor thread (if any). 86 | numTestsPerEvictionRun=3 87 | 88 | # The minimum amount of time an object may sit idle in the pool before it is eligable for eviction by the idle object evictor (if any). 89 | # default = 1000 * 60 * 30 90 | minEvictableIdleTimeMillis=1800000 91 | 92 | # The minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the idle connection evictor, with the extra condition that at least "minIdle" connections remain in the pool. When miniEvictableIdleTimeMillis is set to a positive value, miniEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are visited by the evictor, idle time is first compared against miniEvictableIdleTimeMillis (without considering the number of idle connections in the pool) and then against softMinEvictableIdleTimeMillis, including the minIdle constraint. 93 | softMiniEvictableIdleTimeMillis=-1 94 | 95 | # The maximum lifetime in milliseconds of a connection. After this time is exceeded the connection will fail the next activation, passivation or validation test. A value of zero or less means the connection has an infinite lifetime. 96 | maxConnLifetimeMillis=-1 97 | 98 | # Flag to log a message indicating that a connection is being closed by the pool due to maxConnLifetimeMillis exceeded. Set this property to false to suppress expired connection logging that is turned on by default. 99 | logExpiredConnections=true 100 | 101 | # A Collection of SQL statements that will be used to initialize physical connections when they are first created. These statements are executed only once - when the configured connection factory creates the connection. 102 | connectionInitSqls= 103 | 104 | # True means that borrowObject returns the most recently used ("last in") connection in the pool (if there are idle connections available). False means that the pool behaves as a FIFO queue - connections are taken from the idle instance pool in the order that they are returned to the pool. 105 | lifo=true 106 | 107 | # Enable prepared statement pooling for this pool. 108 | poolPreparedStatements=false 109 | 110 | # The maximum number of open statements that can be allocated from the statement pool at the same time, or negative for no limit. 111 | # default = -1 (unlimited) 112 | maxOpenPreparedStatements=-1 113 | 114 | # Controls if the PoolGuard allows access to the underlying connection. 115 | accessToUnderlyingConnectionAllowed=false 116 | 117 | # Flags to remove abandoned connections if they exceed the removeAbandonedTimout. 118 | # A connection is considered abandoned and eligible for removal if it has not been used for longer than removeAbandonedTimeout. 119 | # Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one of the execute methods) resets the lastUsed property of the parent connection. 120 | # Setting one or both of these to true can recover db connections from poorly written applications which fail to close connections. 121 | # Setting removeAbandonedOnMaintenance to true removes abandoned connections on the maintenance cycle (when eviction ends). This property has no effect unless maintenance is enabled by setting timeBetweenEvicionRunsMillis to a positive value. 122 | # If removeAbandonedOnBorrow is true, abandoned connections are removed each time a connection is borrowed from the pool, with the additional requirements that 123 | # - getNumActive() > getMaxTotal() - 3; and 124 | # - getNumIdle() < 2 125 | removeAbandonedOnMaintenance=false 126 | removeAbandonedOnBorrow=false 127 | 128 | # Timeout in seconds before an abandoned connection can be removed. 129 | removeAbandonedTimeout=300 130 | 131 | # Flag to log stack traces for application code which abandoned a Statement or Connection. 132 | # Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because a stack trace has to be generated. 133 | logAbandoned=false 134 | 135 | # When this property is true, validation fails fast for connections that have thrown "fatal" SQLExceptions. Requests to validate disconnected connections fail immediately, with no call to the driver's isValid method or attempt to execute a validation query. 136 | # The SQL_STATE codes considered to signal fatal errors are by default the following: 137 | # - 57P01 (ADMIN SHUTDOWN) 138 | # - 57P02 (CRASH SHUTDOWN) 139 | # - 57P03 (CANNOT CONNECT NOW) 140 | # - 01002 (SQL92 disconnect error) 141 | # - JZ0C0 (Sybase disconnect error) 142 | # - JZ0C1 (Sybase disconnect error) 143 | # - Any SQL_STATE code that starts with "08" 144 | # To override this default set of disconnection codes, set the disconnectionSqlCodes property. 145 | fastFailValidation=false 146 | 147 | # Comma-delimited list of SQL_STATE codes considered to signal fatal disconnection errors. Setting this property has no effect unless fastFailValidation is set to true. 148 | disconnectionSqlCodes= -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/faces-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | en 6 | pt 7 | es 8 | 9 | 10 | 11 | com.risucci.quickstart.i18n 12 | i18n 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/main-with-nav.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/main.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Spring JSF and JPA Quickstart 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/nav.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #{i18n['toggle']} 7 | 8 | 9 | 10 | 11 | Quickstart 12 | 13 | 14 | 15 | #{i18n['countries']} 16 | 17 | 18 | #{i18n['logout']} 19 | #{i18n['language']} 20 | 21 | #{i18n['language.en']} 22 | #{i18n['language.pt']} 23 | #{i18n['language.es']} 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | index.html 7 | 8 | 9 | 10 | 11 | com.sun.faces.config.ConfigureListener 12 | 13 | 14 | 15 | 16 | Faces Servlet 17 | javax.faces.webapp.FacesServlet 18 | 1 19 | 20 | 21 | 22 | 23 | Faces Servlet 24 | *.xhtml 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Quickstart 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/webapp/protected/index.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/webapp/protected/manage/country-edit.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | #{i18n['save']} 22 | 23 | 24 | 25 | 26 | 27 | #{i18n['cancel']} 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/webapp/protected/manage/country-list.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #{i18n['new']} 10 | 11 | 12 | #{i18n['find']} 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 | #{i18n['filter']} 47 | 48 | 49 | 50 | 51 | #{i18n['erase']} 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | #{i18n['remove']} 152 | 153 | 154 | 155 | 156 | 157 | 158 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /src/main/webapp/public/login.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | #{i18n['signIn']} 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 | -------------------------------------------------------------------------------- /src/main/webapp/resources/css/login.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 12em; 3 | background-color: #fff; 4 | } 5 | 6 | form#loginForm { 7 | max-width: 24em; 8 | padding: 0; 9 | margin: 0 auto; 10 | } 11 | 12 | form#loginForm .form-signin-heading, form#loginForm .checkbox { 13 | margin-bottom: 1em; 14 | } 15 | 16 | form#loginForm { 17 | font-weight: normal; 18 | } 19 | 20 | form#loginForm .form-control { 21 | position: relative; 22 | height: auto; 23 | -webkit-box-sizing: border-box; 24 | -moz-box-sizing: border-box; 25 | box-sizing: border-box; 26 | padding: 1em; 27 | font-size: 1em; 28 | } 29 | 30 | form#loginForm .form-control:focus { 31 | z-index: 10; 32 | } 33 | 34 | form#loginForm input#username { 35 | border-bottom-right-radius: 0; 36 | border-bottom-left-radius: 0; 37 | } 38 | 39 | form#loginForm input#password { 40 | margin-top: -1px; 41 | border-top-left-radius: 0; 42 | border-top-right-radius: 0; 43 | } 44 | 45 | form#loginForm input#signin { 46 | margin: 1em 0; 47 | } --------------------------------------------------------------------------------