Hello!!
Thanks to be here.
I would like to show a brief configuration inside persistence.xml to enable the second level cache over JBoss EAP 6.x, 7 or Wildfly 8.x, 9.
The second level cache is based on Infinispan framework.
First of all, edit the persistence.xml file.
<!-- Caching is enabled for all entities for Cacheable(true) is specified -->
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<!-- shared-cache-mode>ALL</shared-cache-mode -->
<properties>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
<property name="hibernate.jdbc.batch_versioned_data" value="true"/>
<property name="hibernate.generate_statistics" value="false" />
<property name="hibernate.jdbc.use_streams_for_binary" value="true" />
<!-- second level cache with infinispan -->
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.jboss.as.jpa.hibernate4.infinispan.InfinispanRegionFactory"/>
<property name="hibernate.cache.infinispan.cachemanager" value="java:jboss/infinispan/container/hibernate"/>
<property name="hibernate.cache.inifinispan.statistics" value="true"/>
<property name="hibernate.cache.use_minimal_puts" value="true"/>
<property name="hibernate.cache.infinispan.use_synchronization" value="false"/>
<property name="hibernate.cache.infinispan.entity.eviction.strategy" value="LIRS"/>
<property name="hibernate.cache.infinispan.entity.eviction.wake_up_interval" value="3000"/>
<property name="hibernate.cache.infinispan.entity.eviction.max_entries" value="12000"/>
<property name="hibernate.cache.infinispan.entity.expiration.lifespan" value="60000"/>
<property name="hibernate.cache.infinispan.entity.expiration.max_idle" value="40000"/>
</properties>
After that, just enable entity classes (hibernate implementation):
@Cacheable(true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
That's it.
Thanks a lot and regards.
Java World blog...comments, posts and informations about JEE development
Tuesday, November 22, 2016
Monday, August 29, 2016
JBoss EAP with Java Module for Testing - Arquillian, Selenium, Spring Boot and JUnit Together
Hi All,
Thanks again to stay here!
Today, I would like to show you how to create a java module configuration to test your WS service using Arquillian, Selenium, Spring Boot and Junit...
Pre-Requirements
JBoss EAP 6.x
Java 7 or 8
Maven 3.3
So, let's do it!
First of all and the most important point: configure your pom.xml with frameworks and appropriate versions to run tests.
Arquillian
Define your arquillian.xml file into test/resources:
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 3.0"/>
<container qualifier="jboss" default="true">
<configuration>
<property name="jbossHome">/opt/java/jboss/jboss-eap-6.4/</property>
<property name="serverConfig">standalone-full-ha.xml</property>
<property name="javaVmArguments">-Xms512m -Xmx1024m -XX:MaxPermSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+UseCompressedOops -XX:+AggressiveOpts -XX:+HeapDumpOnOutOfMemoryError -noverify -Xss512k -XX:StackShadowPages=8 -XX:+UseFastAccessorMethods</property>
<property name="managementAddress">localhost</property>
<property name="managementPort">9999</property>
<property name="username">admin</property>
<property name="password">yadayadaxpto</property>
</configuration>
</container>
</arquillian>
Put the versions and packages into pom.xml
<arquillian.version>1.1.2.Final</arquillian.version>
<arquillian.warp.version>1.0.0.Alpha6</arquillian.warp.version>
<arquillian.rest-client.version>1.0.0.Alpha2</arquillian.rest-client.version>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.protocol</groupId>
<artifactId>arquillian-protocol-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-client-impl-jersey</artifactId>
<version>1.0.0.Alpha3</version>
<exclusions>
<exclusion>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
</exclusion>
<exclusion>
<artifactId>javax.ws.rs</artifactId>
<groupId>javax.ws.rs-api</groupId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-warp</artifactId>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<!-- http://arquillian.org/modules/contacts-extension/ -->
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-warp-impl-jaxrs-2.0</artifactId>
<version>${arquillian.rest-client.version}</version>
<exclusions>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-client-impl-3x</artifactId>
<version>${arquillian.rest-client.version}</version>
<exclusions>
<exclusion>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-client-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-client-impl-base</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-warp-api</artifactId>
</dependency>
Create your test base class
@RunWith(Arquillian.class)
public class ArquillianDefaultTest {
@Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test-arquillian.war")
.addPackages(true, Filters.exclude(".*Test.*"),
ArquillianDefaultTest.class.getPackage())
.addAsLibraries(Maven.resolver().resolve("javax.ws.rs:javax.ws.rs-api:2.0").withTransitivity().asFile())
.addAsLibraries(Maven.resolver().resolve("org.jboss.arquillian.extension:arquillian-rest-warp-api:1.0.0.Alpha2").withTransitivity().asFile())
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
@RunAsClient
@Test
public void testWS(@ArquillianResource URL deploymentURL) throws URISyntaxException {
WebTarget target = buildWebTarget(deploymentURL);
System.out.println("WebTarget: " + target);
assertNotNull(target);
}
}
Spring Boot
<spring.boot.version>1.3.5.RELEASE</spring.boot.version>
<spring.boot.maven.plugin.version>1.3.5</spring.boot.maven.plugin.version>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
Test Sample
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = BaseSpringBootApplicationStartup.class)
@WebAppConfiguration
@IntegrationTest("server.port:7070")
public class ApplicationSpringBootITest extends FluentTest {
@Value("${local.server.port:7070}")
private int serverPort;
protected WebDriver webDriver;
@Before
public void setUp() {
webDriver = new FirefoxDriver();
webDriver.get("http://google.com");
System.out.println(webDriver.getPageSource());
}
@After
public void teardown() {
if (webDriver != null) {
webDriver.quit();
}
}
@Override
public WebDriver getDefaultDriver() {
return webDriver;
}
protected String getUrl() {
return "http://localhost:" + serverPort;
}
@Test
public void hasPageTitleMock() {
when().
get(getUrl() + "/homeMock").
then().
assertThat().
statusCode(200);
}
}
Selenium and JUnit
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-api</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-support</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
It's done! But I just want to show the libraries and versions here, because you can find all details about implementation at my github project.
So, check all artefacts and classes over here:
https://github.com/alvesfred/samples-jboss/tree/master/samples-test
How to Run the tests or the environment...
1 - mvn clean install or
2 - mvn clean integration-test -P integration-ws-test
Thanks a lot and regards!
Thanks again to stay here!
Today, I would like to show you how to create a java module configuration to test your WS service using Arquillian, Selenium, Spring Boot and Junit...
Pre-Requirements
JBoss EAP 6.x
Java 7 or 8
Maven 3.3
So, let's do it!
First of all and the most important point: configure your pom.xml with frameworks and appropriate versions to run tests.
Arquillian
Define your arquillian.xml file into test/resources:
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 3.0"/>
<container qualifier="jboss" default="true">
<configuration>
<property name="jbossHome">/opt/java/jboss/jboss-eap-6.4/</property>
<property name="serverConfig">standalone-full-ha.xml</property>
<property name="javaVmArguments">-Xms512m -Xmx1024m -XX:MaxPermSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+UseCompressedOops -XX:+AggressiveOpts -XX:+HeapDumpOnOutOfMemoryError -noverify -Xss512k -XX:StackShadowPages=8 -XX:+UseFastAccessorMethods</property>
<property name="managementAddress">localhost</property>
<property name="managementPort">9999</property>
<property name="username">admin</property>
<property name="password">yadayadaxpto</property>
</configuration>
</container>
</arquillian>
Put the versions and packages into pom.xml
<arquillian.version>1.1.2.Final</arquillian.version>
<arquillian.warp.version>1.0.0.Alpha6</arquillian.warp.version>
<arquillian.rest-client.version>1.0.0.Alpha2</arquillian.rest-client.version>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.protocol</groupId>
<artifactId>arquillian-protocol-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-client-impl-jersey</artifactId>
<version>1.0.0.Alpha3</version>
<exclusions>
<exclusion>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
</exclusion>
<exclusion>
<artifactId>javax.ws.rs</artifactId>
<groupId>javax.ws.rs-api</groupId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-warp</artifactId>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<!-- http://arquillian.org/modules/contacts-extension/ -->
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-warp-impl-jaxrs-2.0</artifactId>
<version>${arquillian.rest-client.version}</version>
<exclusions>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-client-impl-3x</artifactId>
<version>${arquillian.rest-client.version}</version>
<exclusions>
<exclusion>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-client-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-client-impl-base</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-rest-warp-api</artifactId>
</dependency>
Create your test base class
@RunWith(Arquillian.class)
public class ArquillianDefaultTest {
@Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test-arquillian.war")
.addPackages(true, Filters.exclude(".*Test.*"),
ArquillianDefaultTest.class.getPackage())
.addAsLibraries(Maven.resolver().resolve("javax.ws.rs:javax.ws.rs-api:2.0").withTransitivity().asFile())
.addAsLibraries(Maven.resolver().resolve("org.jboss.arquillian.extension:arquillian-rest-warp-api:1.0.0.Alpha2").withTransitivity().asFile())
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
@RunAsClient
@Test
public void testWS(@ArquillianResource URL deploymentURL) throws URISyntaxException {
WebTarget target = buildWebTarget(deploymentURL);
System.out.println("WebTarget: " + target);
assertNotNull(target);
}
}
Spring Boot
<spring.boot.version>1.3.5.RELEASE</spring.boot.version>
<spring.boot.maven.plugin.version>1.3.5</spring.boot.maven.plugin.version>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
Test Sample
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = BaseSpringBootApplicationStartup.class)
@WebAppConfiguration
@IntegrationTest("server.port:7070")
public class ApplicationSpringBootITest extends FluentTest {
@Value("${local.server.port:7070}")
private int serverPort;
protected WebDriver webDriver;
@Before
public void setUp() {
webDriver = new FirefoxDriver();
webDriver.get("http://google.com");
System.out.println(webDriver.getPageSource());
}
@After
public void teardown() {
if (webDriver != null) {
webDriver.quit();
}
}
@Override
public WebDriver getDefaultDriver() {
return webDriver;
}
protected String getUrl() {
return "http://localhost:" + serverPort;
}
@Test
public void hasPageTitleMock() {
when().
get(getUrl() + "/homeMock").
then().
assertThat().
statusCode(200);
}
}
Selenium and JUnit
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-api</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-support</artifactId>
<version>2.53.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
It's done! But I just want to show the libraries and versions here, because you can find all details about implementation at my github project.
So, check all artefacts and classes over here:
https://github.com/alvesfred/samples-jboss/tree/master/samples-test
How to Run the tests or the environment...
1 - mvn clean install or
2 - mvn clean integration-test -P integration-ws-test
Thanks a lot and regards!
Sunday, August 28, 2016
JBoss EAP 6.x with HornetQ Backup Cluster (Broadcast/Loopback) using JGroups
Hi everyone...
I am back!
Thanks a lot to stay here for reading my post. Sorry about my english, but i am studying hard to improve it :-)!
Today, i would like to present a configuration over HornetQ (jboss jms server), settting up a backup server into a HA Cluster.
HornetQ is a good choice to delivery messages using JBoss EAP 6.x, and you can define properties to work with a lot of nodes where the messages will be sent and received in miliseconds.
So, how can i create a HornetQ Live Server, Backup HornetQ Server and setting up a cluster configuration to provide performance for any tasks in Java EE Applications?
It is not a simple question, because a lot of issues and situations must be specified to ensure a good performance solution. But work with JMS as a important part of JEE that solves problems for working in asynchronous process.
So, let's see how we could create a good configuration for working in cluster with HornetQ Messages.
JGroups Properties
For a group server you have to define 3 essencials properties...
<property name="jboss.default.multicast.address" value="231.0.0.3"/>
<property name="jboss.messaging.group.address" value="231.3.3.3"/>
<property name="hornetq-discovery-group-name" value="dg-hornetq-a"/>
These properties will be used for all servers inside the group, and messages will be received by the servers in a cluster environment.
For instance:
<server-group name="grp-b" profile="prf-b">
<jvm name="default">
<heap size="3096m" max-size="3096m"/>
<jvm-options>
<option value="-XX:+CMSClassUnloadingEnabled"/>
<option value="-XX:+UseConcMarkSweepGC"/>
<option value="-XX:+UseCompressedOops"/>
<option value="-XX:+AggressiveOpts"/>
<option value="-XX:+ScavengeBeforeFullGC"/>
<option value="-XX:+HeapDumpOnOutOfMemoryError"/>
<option value="-noverify"/>
<option value="-Xss1024k"/>
<option value="-XX:StackShadowPages=10"/>
<option value="-XX:+UseFastAccessorMethods"/>
</jvm-options>
</jvm>
<socket-binding-group ref="full-ha-sockets"/>
<system-properties>
<property name="jboss.default.multicast.address" value="231.0.0.3"/>
<property name="jboss.messaging.group.address" value="231.3.3.3"/>
<property name="hornetq-discovery-group-name" value="dg-hornetq-a"/>
<property name="jboss.tx.node.id" value="node-a"/>
</system-properties>
</server-group>
HornetQ Journal
We have to define the path where HornetQ will save informations for handling messages...
<system-properties>
<property name="java.net.preferIPv4Stack" value="true"/>
<property name="org.apache.tomcat.util.http.Parameters.MAX_COUNT" value="5000"/>
<property name="user.country" value="BR"/>
<property name="user.language" value="pt"/>
</system-properties>
<paths>
<path name="hornetq_storage_a" path="/opt/hornetq/a-queue"/>
<path name="hornetq_storage_b" path="/opt/hornetq/b-queue"/>
<!-- hornetq backups -->
<path name="hornetq_storage_a_bkp" path="/opt/hornetq_bkp/a-queue"/>
<path name="hornetq_storage_b_bkp" path="/opt/hornetq_bkp/b-queue"/>
</paths>
These paths must be used by lived servers and HornetQ backup servers.
But if you prefer, according to your environment, a shared path must be defined for both into the same profile.
<subsystem xmlns="urn:jboss:domain:messaging:1.4">
<hornetq-server>
<persistence-enabled>true</persistence-enabled>
<security-enabled>false</security-enabled>
<!--transaction-timeout>180000</transaction-timeout-->
<backup>false</backup>
<allow-failback>true</allow-failback>
<failover-on-shutdown>true</failover-on-shutdown>
<shared-store>true</shared-store>
<journal-type>ASYNCIO</journal-type>
<!--journal-buffer-timeout>2000</journal-buffer-timeout-->
<journal-sync-transactional>true</journal-sync-transactional>
<journal-sync-non-transactional>true</journal-sync-non-transactional>
<log-journal-write-rate>false</log-journal-write-rate>
<journal-min-files>20</journal-min-files>
<!--journal-max-io>65000</journal-max-io-->
<run-sync-speed-test>false</run-sync-speed-test>
<check-for-live-server>true</check-for-live-server>
<backup-group-name>${live.group.a:a-live}</backup-group-name>
<paging-directory path="paging" relative-to="hornetq_storage_a"/>
<bindings-directory path="bindings" relative-to="hornetq_storage_a"/>
<journal-directory path="journal" relative-to="hornetq_storage_a"/>
<large-messages-directory path="largemessages" relative-to="hornetq_storage_a"/>
Broadcast and Cluster Configuration
<broadcast-groups>
<broadcast-group name="bg-a">
<socket-binding>messaging-group</socket-binding>
<broadcast-period>2000</broadcast-period>
<connector-ref>
netty
</connector-ref>
</broadcast-group>
</broadcast-groups>
<discovery-groups>
<discovery-group name="dg-hornetq-a">
<socket-binding>messaging-group</socket-binding>
<refresh-timeout>2000</refresh-timeout>
</discovery-group>
</discovery-groups>
<cluster-connections>
<cluster-connection name="a-cluster">
<address>jms</address>
<connector-ref>netty</connector-ref>
<discovery-group-ref discovery-group-name="dg-hornetq-a"/> </cluster-connection>
</cluster-connections>
<security-settings>
<security-setting match="#">
<permission type="send" roles="guest"/>
<permission type="consume" roles="guest"/>
<permission type="createNonDurableQueue" roles="guest"/>
<permission type="deleteNonDurableQueue" roles="guest"/>
</security-setting>
</security-settings>
<address-settings>
<address-setting match="#">
<dead-letter-address>jms.queue.DLQ</dead-letter-address>
<expiry-address>jms.queue.ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<max-size-bytes>10485760</max-size-bytes>
<page-size-bytes>2097152</page-size-bytes>
<address-full-policy>BLOCK</address-full-policy> <message-counter-history-day-limit>10</message-counter-history-day-limit>
</address-setting>
</address-settings>
<jms-connection-factories>
<connection-factory name="InVmConnectionFactory">
<connectors>
<connector-ref connector-name="in-vm"/>
</connectors>
<entries>
<entry name="java:/ConnectionFactory"/>
</entries>
<producer-window-size>-1</producer-window-size>
<consumer-window-size>0</consumer-window-size>
<consumer-max-rate>-1</consumer-max-rate>
<producer-max-rate>-1</producer-max-rate>
</connection-factory>
<connection-factory name="RemoteConnectionFactory">
<discovery-group-ref discovery-group-name="dg-hornetq-a"/>
<entries>
<entry name="java:/RemoteJmsXA"/>
<entry name="java:jboss/exported/jms/RemoteConnectionFactory"/>
</entries>
<ha>true</ha>
<block-on-acknowledge>true</block-on-acknowledge> <retry-interval>1000</retry-interval>
<retry-interval-multiplier>1.0</retry-interval-multiplier>
<reconnect-attempts>-1</reconnect-attempts>
<producer-window-size>-1</producer-window-size>
<consumer-window-size>0</consumer-window-size> <consumer-max-rate>-1</consumer-max-rate>
<producer-max-rate>-1</producer-max-rate>
</connection-factory>
<pooled-connection-factory name="hornetq-ra">
<transaction mode="xa"/>
<connectors>
<connector-ref connector-name="in-vm"/>
</connectors>
<entries>
<entry name="java:/JmsXA"/>
</entries>
<ha>true</ha>
<block-on-acknowledge>true</block-on-acknowledge> <retry-interval>1000</retry-interval>
<retry-interval-multiplier>1.0</retry-interval-multiplier>
<reconnect-attempts>-1</reconnect-attempts>
<producer-window-size>-1</producer-window-size>
<consumer-window-size>0</consumer-window-size> <consumer-max-rate>-1</consumer-max-rate>
<producer-max-rate>-1</producer-max-rate>
</pooled-connection-factory>
</jms-connection-factories>
HornetQ Backup Server
<hornetq-server name="a-bkp">
<persistence-enabled>true</persistence-enabled>
<security-enabled>false</security-enabled>
<!--transaction-timeout>180000</transaction-timeout-->
<backup>true</backup>
<allow-failback>true</allow-failback>
<failover-on-shutdown>true</failover-on-shutdown>
<shared-store>true</shared-store>
<journal-type>ASYNCIO</journal-type>
<!--journal-buffer-timeout>2000</journal-buffer-timeout-->
<journal-sync-transactional>true</journal-sync-transactional>
<journal-sync-non-transactional>true</journal-sync-non-transactional>
<log-journal-write-rate>false</log-journal-write-rate>
<journal-min-files>20</journal-min-files>
<!--journal-max-io>65000</journal-max-io-->
<run-sync-speed-test>false</run-sync-speed-test>
<check-for-live-server>true</check-for-live-server>
<backup-group-name>${backup.group.a:a-bkp}</backup-group-name>
<paging-directory path="paging" relative-to="hornetq_storage_a_bkp"/>
<bindings-directory path="bindings" relative-to="hornetq_storage_a_bkp"/>
<journal-directory path="journal" relative-to="hornetq_storage_a_bkp"/>
<large-messages-directory path="largemessages" relative-to="hornetq_storage_a_bkp"/>
... (the same lines as you put on lived server)
That's it!
Your HornetQ Cluster was created...So, you can have 2 or more hosts using <server-group name="grp-b" profile="prf-b">.
The complete file was saved into my github profile. Please, see it at:
https://github.com/alvesfred/samples-jboss/blob/master/deploy/domain-block-hornetq-backup.xml
In this file, i created 3 profiles and 3 groups.
If you would like to know if the packages over the network have been sending, just execute the linux command below for each server/host:
# tcpdump -vv | grep 231.3.3.3
(all udp packages will be showed for each host servers)
If you have any doubt, please let me know.
Thanks a lot and regards
I am back!
Thanks a lot to stay here for reading my post. Sorry about my english, but i am studying hard to improve it :-)!
Today, i would like to present a configuration over HornetQ (jboss jms server), settting up a backup server into a HA Cluster.
HornetQ is a good choice to delivery messages using JBoss EAP 6.x, and you can define properties to work with a lot of nodes where the messages will be sent and received in miliseconds.
So, how can i create a HornetQ Live Server, Backup HornetQ Server and setting up a cluster configuration to provide performance for any tasks in Java EE Applications?
It is not a simple question, because a lot of issues and situations must be specified to ensure a good performance solution. But work with JMS as a important part of JEE that solves problems for working in asynchronous process.
So, let's see how we could create a good configuration for working in cluster with HornetQ Messages.
JGroups Properties
For a group server you have to define 3 essencials properties...
<property name="jboss.default.multicast.address" value="231.0.0.3"/>
<property name="jboss.messaging.group.address" value="231.3.3.3"/>
<property name="hornetq-discovery-group-name" value="dg-hornetq-a"/>
These properties will be used for all servers inside the group, and messages will be received by the servers in a cluster environment.
For instance:
<server-group name="grp-b" profile="prf-b">
<jvm name="default">
<heap size="3096m" max-size="3096m"/>
<jvm-options>
<option value="-XX:+CMSClassUnloadingEnabled"/>
<option value="-XX:+UseConcMarkSweepGC"/>
<option value="-XX:+UseCompressedOops"/>
<option value="-XX:+AggressiveOpts"/>
<option value="-XX:+ScavengeBeforeFullGC"/>
<option value="-XX:+HeapDumpOnOutOfMemoryError"/>
<option value="-noverify"/>
<option value="-Xss1024k"/>
<option value="-XX:StackShadowPages=10"/>
<option value="-XX:+UseFastAccessorMethods"/>
</jvm-options>
</jvm>
<socket-binding-group ref="full-ha-sockets"/>
<system-properties>
<property name="jboss.default.multicast.address" value="231.0.0.3"/>
<property name="jboss.messaging.group.address" value="231.3.3.3"/>
<property name="hornetq-discovery-group-name" value="dg-hornetq-a"/>
<property name="jboss.tx.node.id" value="node-a"/>
</system-properties>
</server-group>
HornetQ Journal
We have to define the path where HornetQ will save informations for handling messages...
<system-properties>
<property name="java.net.preferIPv4Stack" value="true"/>
<property name="org.apache.tomcat.util.http.Parameters.MAX_COUNT" value="5000"/>
<property name="user.country" value="BR"/>
<property name="user.language" value="pt"/>
</system-properties>
<paths>
<path name="hornetq_storage_a" path="/opt/hornetq/a-queue"/>
<path name="hornetq_storage_b" path="/opt/hornetq/b-queue"/>
<!-- hornetq backups -->
<path name="hornetq_storage_a_bkp" path="/opt/hornetq_bkp/a-queue"/>
<path name="hornetq_storage_b_bkp" path="/opt/hornetq_bkp/b-queue"/>
</paths>
These paths must be used by lived servers and HornetQ backup servers.
But if you prefer, according to your environment, a shared path must be defined for both into the same profile.
<subsystem xmlns="urn:jboss:domain:messaging:1.4">
<hornetq-server>
<persistence-enabled>true</persistence-enabled>
<security-enabled>false</security-enabled>
<!--transaction-timeout>180000</transaction-timeout-->
<backup>false</backup>
<allow-failback>true</allow-failback>
<failover-on-shutdown>true</failover-on-shutdown>
<shared-store>true</shared-store>
<journal-type>ASYNCIO</journal-type>
<!--journal-buffer-timeout>2000</journal-buffer-timeout-->
<journal-sync-transactional>true</journal-sync-transactional>
<journal-sync-non-transactional>true</journal-sync-non-transactional>
<log-journal-write-rate>false</log-journal-write-rate>
<journal-min-files>20</journal-min-files>
<!--journal-max-io>65000</journal-max-io-->
<run-sync-speed-test>false</run-sync-speed-test>
<check-for-live-server>true</check-for-live-server>
<backup-group-name>${live.group.a:a-live}</backup-group-name>
<paging-directory path="paging" relative-to="hornetq_storage_a"/>
<bindings-directory path="bindings" relative-to="hornetq_storage_a"/>
<journal-directory path="journal" relative-to="hornetq_storage_a"/>
<large-messages-directory path="largemessages" relative-to="hornetq_storage_a"/>
Broadcast and Cluster Configuration
<broadcast-groups>
<broadcast-group name="bg-a">
<socket-binding>messaging-group</socket-binding>
<broadcast-period>2000</broadcast-period>
<connector-ref>
netty
</connector-ref>
</broadcast-group>
</broadcast-groups>
<discovery-groups>
<discovery-group name="dg-hornetq-a">
<socket-binding>messaging-group</socket-binding>
<refresh-timeout>2000</refresh-timeout>
</discovery-group>
</discovery-groups>
<cluster-connections>
<cluster-connection name="a-cluster">
<address>jms</address>
<connector-ref>netty</connector-ref>
<discovery-group-ref discovery-group-name="dg-hornetq-a"/> </cluster-connection>
</cluster-connections>
<security-settings>
<security-setting match="#">
<permission type="send" roles="guest"/>
<permission type="consume" roles="guest"/>
<permission type="createNonDurableQueue" roles="guest"/>
<permission type="deleteNonDurableQueue" roles="guest"/>
</security-setting>
</security-settings>
<address-settings>
<address-setting match="#">
<dead-letter-address>jms.queue.DLQ</dead-letter-address>
<expiry-address>jms.queue.ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<max-size-bytes>10485760</max-size-bytes>
<page-size-bytes>2097152</page-size-bytes>
<address-full-policy>BLOCK</address-full-policy> <message-counter-history-day-limit>10</message-counter-history-day-limit>
</address-setting>
</address-settings>
<jms-connection-factories>
<connection-factory name="InVmConnectionFactory">
<connectors>
<connector-ref connector-name="in-vm"/>
</connectors>
<entries>
<entry name="java:/ConnectionFactory"/>
</entries>
<producer-window-size>-1</producer-window-size>
<consumer-window-size>0</consumer-window-size>
<consumer-max-rate>-1</consumer-max-rate>
<producer-max-rate>-1</producer-max-rate>
</connection-factory>
<connection-factory name="RemoteConnectionFactory">
<discovery-group-ref discovery-group-name="dg-hornetq-a"/>
<entries>
<entry name="java:/RemoteJmsXA"/>
<entry name="java:jboss/exported/jms/RemoteConnectionFactory"/>
</entries>
<ha>true</ha>
<block-on-acknowledge>true</block-on-acknowledge> <retry-interval>1000</retry-interval>
<retry-interval-multiplier>1.0</retry-interval-multiplier>
<reconnect-attempts>-1</reconnect-attempts>
<producer-window-size>-1</producer-window-size>
<consumer-window-size>0</consumer-window-size> <consumer-max-rate>-1</consumer-max-rate>
<producer-max-rate>-1</producer-max-rate>
</connection-factory>
<pooled-connection-factory name="hornetq-ra">
<transaction mode="xa"/>
<connectors>
<connector-ref connector-name="in-vm"/>
</connectors>
<entries>
<entry name="java:/JmsXA"/>
</entries>
<ha>true</ha>
<block-on-acknowledge>true</block-on-acknowledge> <retry-interval>1000</retry-interval>
<retry-interval-multiplier>1.0</retry-interval-multiplier>
<reconnect-attempts>-1</reconnect-attempts>
<producer-window-size>-1</producer-window-size>
<consumer-window-size>0</consumer-window-size> <consumer-max-rate>-1</consumer-max-rate>
<producer-max-rate>-1</producer-max-rate>
</pooled-connection-factory>
</jms-connection-factories>
HornetQ Backup Server
<hornetq-server name="a-bkp">
<persistence-enabled>true</persistence-enabled>
<security-enabled>false</security-enabled>
<!--transaction-timeout>180000</transaction-timeout-->
<backup>true</backup>
<allow-failback>true</allow-failback>
<failover-on-shutdown>true</failover-on-shutdown>
<shared-store>true</shared-store>
<journal-type>ASYNCIO</journal-type>
<!--journal-buffer-timeout>2000</journal-buffer-timeout-->
<journal-sync-transactional>true</journal-sync-transactional>
<journal-sync-non-transactional>true</journal-sync-non-transactional>
<log-journal-write-rate>false</log-journal-write-rate>
<journal-min-files>20</journal-min-files>
<!--journal-max-io>65000</journal-max-io-->
<run-sync-speed-test>false</run-sync-speed-test>
<check-for-live-server>true</check-for-live-server>
<backup-group-name>${backup.group.a:a-bkp}</backup-group-name>
<paging-directory path="paging" relative-to="hornetq_storage_a_bkp"/>
<bindings-directory path="bindings" relative-to="hornetq_storage_a_bkp"/>
<journal-directory path="journal" relative-to="hornetq_storage_a_bkp"/>
<large-messages-directory path="largemessages" relative-to="hornetq_storage_a_bkp"/>
... (the same lines as you put on lived server)
That's it!
Your HornetQ Cluster was created...So, you can have 2 or more hosts using <server-group name="grp-b" profile="prf-b">.
The complete file was saved into my github profile. Please, see it at:
https://github.com/alvesfred/samples-jboss/blob/master/deploy/domain-block-hornetq-backup.xml
In this file, i created 3 profiles and 3 groups.
If you would like to know if the packages over the network have been sending, just execute the linux command below for each server/host:
# tcpdump -vv | grep 231.3.3.3
(all udp packages will be showed for each host servers)
If you have any doubt, please let me know.
Thanks a lot and regards
Monday, May 30, 2016
Basic Authentication/Validation for Webservices using REST API and Interceptors
Hi All,
Thanks for reading this post...
Let's talk about how to implement a set of classes using REST concepts, and basic control access to the WebServices. An interceptor will be responsible for reading the request and manage the access control to the resources.
First of all, it will be necessary to define the pom.xml (maven resources) with the following dependencies:
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-crypto</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
</dependency>
JBoss EAP 6.4 and Resteasy API 2.3.10.Final were used to validate the sample code.
- Rest Activator
@ApplicationPath("/rest")
public class WsRestActivator extends Application {
}
- Exception Class
public class ServiceAPIException extends Exception {
public ServiceAPIException(String message) {
super(message);
}
public ServiceAPIException(Exception e) {
super(e);
}
public ServiceAPIException(String msg, Throwable t) {
super(msg, t);
}
}
@Provider
public class ExceptionHttpStatusResolver implements ExceptionMapper<ServiceAPIException> {
@Override
public Response toResponse(ServiceAPIException exception) {
Response.Status httpStatus = Response.Status.INTERNAL_SERVER_ERROR;
if (exception instanceof ServiceAPIException)
httpStatus = Response.Status.BAD_REQUEST;
return Response.status(httpStatus).entity(exception.getMessage()).build();
}
}
- Annotation to allow access to the Webservice methods
@Documented
@Retention (RUNTIME)
@Target({TYPE, METHOD})
public @interface WsAccessMethodPermition {
}
- Service Abstracttion
public abstract class ServiceRest {
protected void handleException(String msg, Throwable t) throws ServiceAPIException {
throw new ServiceAPIException(msg, t);
}
}
- Security Abstraction for Resource Classes
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.security.smime.EnvelopedOutput;
public abstract class SecureResource extends ServiceRest {
public static final String USER_CERTIFICATE = "user-certificate";
private static CertificateFactory factory;
static {
try {
factory = CertificateFactory.getInstance("X.509");
} catch (Exception e) {
}
}
protected X509Certificate extractCertificate(HttpServletRequest request) {
try {
InputStream is = new ByteArrayInputStream((byte[]) request.getAttribute(
SecureResource.USER_CERTIFICATE));
return (X509Certificate) factory.generateCertificate(is);
} catch (CertificateException e) {
return null;
}
}
protected EnvelopedOutput encryptResponse(HttpServletRequest request, Object result) {
X509Certificate certificate = extractCertificate(request);
return encryptResponse(certificate, result);
}
protected EnvelopedOutput encryptResponse(X509Certificate certificate, Object result) {
// Object user = UserContext.getUser(result);
EnvelopedOutput output = new EnvelopedOutput(
new Object()/* your user object */, MediaType.APPLICATION_JSON);
output.setCertificate(certificate);
return output;
}
}
- Interceptor
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.annotations.interception.ServerInterceptor;
import org.jboss.resteasy.core.Headers;
import org.jboss.resteasy.core.ResourceMethod;
import org.jboss.resteasy.core.ServerResponse;
import org.jboss.resteasy.spi.Failure;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.interception.AcceptedByMethod;
import org.jboss.resteasy.spi.interception.PreProcessInterceptor;
import org.jboss.resteasy.util.Base64;
@Provider
@ServerInterceptor
public class SecurityInterceptor implements PreProcessInterceptor, AcceptedByMethod {
private static final String AUTHORIZATION_PROPERTY = "Authorization";
private static final String AUTHENTICATION_SCHEME = "Basic";
private static final ServerResponse ACCESS_DENIED = new ServerResponse("Access Denied!", 401, new Headers<Object>());
private static final ServerResponse ACCESS_FORBIDDEN = new ServerResponse("Access Forbidden!", 403, new Headers<Object>());
private static final ServerResponse SERVER_ERROR = new ServerResponse("Internal Error!", 500, new Headers<Object>());
@Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod methodInvoked) throws Failure, WebApplicationException {
Method method = methodInvoked.getMethod();
if (method.isAnnotationPresent(WsAccessMethodPermition.class) ||
method.isAnnotationPresent(PermitAll.class)) {
return null;
}
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
return ACCESS_FORBIDDEN;
}
// Get request headers
final HttpHeaders headers = request.getHttpHeaders();
// Fetch authorization header
final List<String> authorization = headers.getRequestHeader(AUTHORIZATION_PROPERTY);
// If no authorization information present; block access
if (authorization == null || authorization.isEmpty()) {
return ACCESS_DENIED;
}
// Get encoded username and password
final String encodedUserPassword = authorization.get(0).replaceFirst(
AUTHENTICATION_SCHEME.concat(" "), "");
// Decode username and password
String usernameAndPassword;
try {
usernameAndPassword = new String(Base64.decode(encodedUserPassword));
} catch (IOException e) {
return SERVER_ERROR;
}
// Split username and password tokens
final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
final String username = tokenizer.nextToken();
final String password = tokenizer.nextToken();
// Verify user access
if (!isUserAllowed(request, username, password)) {
return ACCESS_DENIED;
}
return null;
}
@SuppressWarnings("serial")
private boolean isUserAllowed(final HttpRequest request, final String username, final String password) {
UserWS user = new UserWS(username, password);
if (user != null) {
if (!user.getRoles().isEmpty() && !user.hasPermission()) {
byte[] certificate = user.getCertificate();
request.setAttribute(SecureResource.USER_CERTIFICATE, certificate);
return true;
}
}
return false;
}
@Override
public boolean accept(@SuppressWarnings("rawtypes") Class declaring, Method method) {
// bypass authentication - get methods for instance
if (method.isAnnotationPresent(WsAccessMethodPermition.class) ||
method.isAnnotationPresent(PermitAll.class)) {
return false;
}
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
// TODO here for instance log denied access
return true;
}
return true;
}
}
And now...the resource...
- WebService Implementation
@Path("/test")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class TestResourceWS extends SecureResource {
@POST
@Path("/info/")
@Produces(MediaType.APPLICATION_JSON)
@WsAccessMethodPermition
@Override
public String info() throws ServiceAPIException {
return "Hello, Access OK!";
}
@POST
@Path("/infodenied/")
@Produces(MediaType.APPLICATION_JSON)
@Override
public void infodenied() throws ServiceAPIException {
// "denied!";
}
}
- Sample invocation
http://<host>/<app-name>/rest/test/info
OK!
http://<host>/<app-name>/rest/test/infodenied
Access Denied!
- WS Client Sample...post methods for instance
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Authorization", "Basic " + base64Creds);
headers.add("Content-Type", "application/json");
RestTemplate restTemplate = new RestTemplate();
HttpEntity<ObjectToPass> request = new HttpEntity<ObjectToPass>(ObjectToPass, headers);
restTemplate.postForObject("http://<host>/<app>/rest/test/info", request, Boolean.class);
Thanks a lot and regards!
Thanks for reading this post...
Let's talk about how to implement a set of classes using REST concepts, and basic control access to the WebServices. An interceptor will be responsible for reading the request and manage the access control to the resources.
First of all, it will be necessary to define the pom.xml (maven resources) with the following dependencies:
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-crypto</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>${resteasy.version}</version>
<scope>provided</scope>
</dependency>
JBoss EAP 6.4 and Resteasy API 2.3.10.Final were used to validate the sample code.
- Rest Activator
@ApplicationPath("/rest")
public class WsRestActivator extends Application {
}
- Exception Class
public class ServiceAPIException extends Exception {
public ServiceAPIException(String message) {
super(message);
}
public ServiceAPIException(Exception e) {
super(e);
}
public ServiceAPIException(String msg, Throwable t) {
super(msg, t);
}
}
@Provider
public class ExceptionHttpStatusResolver implements ExceptionMapper<ServiceAPIException> {
@Override
public Response toResponse(ServiceAPIException exception) {
Response.Status httpStatus = Response.Status.INTERNAL_SERVER_ERROR;
if (exception instanceof ServiceAPIException)
httpStatus = Response.Status.BAD_REQUEST;
return Response.status(httpStatus).entity(exception.getMessage()).build();
}
}
- Annotation to allow access to the Webservice methods
@Documented
@Retention (RUNTIME)
@Target({TYPE, METHOD})
public @interface WsAccessMethodPermition {
}
- Service Abstracttion
public abstract class ServiceRest {
protected void handleException(String msg, Throwable t) throws ServiceAPIException {
throw new ServiceAPIException(msg, t);
}
}
- Security Abstraction for Resource Classes
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.security.smime.EnvelopedOutput;
public abstract class SecureResource extends ServiceRest {
public static final String USER_CERTIFICATE = "user-certificate";
private static CertificateFactory factory;
static {
try {
factory = CertificateFactory.getInstance("X.509");
} catch (Exception e) {
}
}
protected X509Certificate extractCertificate(HttpServletRequest request) {
try {
InputStream is = new ByteArrayInputStream((byte[]) request.getAttribute(
SecureResource.USER_CERTIFICATE));
return (X509Certificate) factory.generateCertificate(is);
} catch (CertificateException e) {
return null;
}
}
protected EnvelopedOutput encryptResponse(HttpServletRequest request, Object result) {
X509Certificate certificate = extractCertificate(request);
return encryptResponse(certificate, result);
}
protected EnvelopedOutput encryptResponse(X509Certificate certificate, Object result) {
// Object user = UserContext.getUser(result);
EnvelopedOutput output = new EnvelopedOutput(
new Object()/* your user object */, MediaType.APPLICATION_JSON);
output.setCertificate(certificate);
return output;
}
}
- Interceptor
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.annotations.interception.ServerInterceptor;
import org.jboss.resteasy.core.Headers;
import org.jboss.resteasy.core.ResourceMethod;
import org.jboss.resteasy.core.ServerResponse;
import org.jboss.resteasy.spi.Failure;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.interception.AcceptedByMethod;
import org.jboss.resteasy.spi.interception.PreProcessInterceptor;
import org.jboss.resteasy.util.Base64;
@Provider
@ServerInterceptor
public class SecurityInterceptor implements PreProcessInterceptor, AcceptedByMethod {
private static final String AUTHORIZATION_PROPERTY = "Authorization";
private static final String AUTHENTICATION_SCHEME = "Basic";
private static final ServerResponse ACCESS_DENIED = new ServerResponse("Access Denied!", 401, new Headers<Object>());
private static final ServerResponse ACCESS_FORBIDDEN = new ServerResponse("Access Forbidden!", 403, new Headers<Object>());
private static final ServerResponse SERVER_ERROR = new ServerResponse("Internal Error!", 500, new Headers<Object>());
@Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod methodInvoked) throws Failure, WebApplicationException {
Method method = methodInvoked.getMethod();
if (method.isAnnotationPresent(WsAccessMethodPermition.class) ||
method.isAnnotationPresent(PermitAll.class)) {
return null;
}
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
return ACCESS_FORBIDDEN;
}
// Get request headers
final HttpHeaders headers = request.getHttpHeaders();
// Fetch authorization header
final List<String> authorization = headers.getRequestHeader(AUTHORIZATION_PROPERTY);
// If no authorization information present; block access
if (authorization == null || authorization.isEmpty()) {
return ACCESS_DENIED;
}
// Get encoded username and password
final String encodedUserPassword = authorization.get(0).replaceFirst(
AUTHENTICATION_SCHEME.concat(" "), "");
// Decode username and password
String usernameAndPassword;
try {
usernameAndPassword = new String(Base64.decode(encodedUserPassword));
} catch (IOException e) {
return SERVER_ERROR;
}
// Split username and password tokens
final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
final String username = tokenizer.nextToken();
final String password = tokenizer.nextToken();
// Verify user access
if (!isUserAllowed(request, username, password)) {
return ACCESS_DENIED;
}
return null;
}
@SuppressWarnings("serial")
private boolean isUserAllowed(final HttpRequest request, final String username, final String password) {
UserWS user = new UserWS(username, password);
if (user != null) {
if (!user.getRoles().isEmpty() && !user.hasPermission()) {
byte[] certificate = user.getCertificate();
request.setAttribute(SecureResource.USER_CERTIFICATE, certificate);
return true;
}
}
return false;
}
@Override
public boolean accept(@SuppressWarnings("rawtypes") Class declaring, Method method) {
// bypass authentication - get methods for instance
if (method.isAnnotationPresent(WsAccessMethodPermition.class) ||
method.isAnnotationPresent(PermitAll.class)) {
return false;
}
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
// TODO here for instance log denied access
return true;
}
return true;
}
}
And now...the resource...
- WebService Implementation
@Path("/test")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class TestResourceWS extends SecureResource {
@POST
@Path("/info/")
@Produces(MediaType.APPLICATION_JSON)
@WsAccessMethodPermition
@Override
public String info() throws ServiceAPIException {
return "Hello, Access OK!";
}
@POST
@Path("/infodenied/")
@Produces(MediaType.APPLICATION_JSON)
@Override
public void infodenied() throws ServiceAPIException {
// "denied!";
}
}
- Sample invocation
http://<host>/<app-name>/rest/test/info
OK!
http://<host>/<app-name>/rest/test/infodenied
Access Denied!
- WS Client Sample...post methods for instance
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Authorization", "Basic " + base64Creds);
headers.add("Content-Type", "application/json");
RestTemplate restTemplate = new RestTemplate();
HttpEntity<ObjectToPass> request = new HttpEntity<ObjectToPass>(ObjectToPass, headers);
restTemplate.postForObject("http://<host>/<app>/rest/test/info", request, Boolean.class);
Thanks a lot and regards!
Friday, May 20, 2016
JEE7 - Working with Asynchronous methods and Observer
Hi all,
Thanks for reading my posts.
Now, I would like to present some tips about Asynch implementation.
Let's see the following code below...
Environment:
Java EE 6/7 and Java SE 1.7/1.8
CDI 1.x
JBoss EAP/AS/Wildfly and so on...
- EJB Asynch
public interface CustomEvent extends Serializable {
/**
* Submit event execution
*
* @param event
*/
void submit();
}
public class DispatchEvent implements CustomEvent { private String name;
protected int age;
public DispatchEvent(String name, int age) { this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
@Override
public void submit() {
// builder pattern sample...see other posts about this pattern
StudentsBuilder studentsBuilder = new StudentsBuilder();
studentsBuilder.addStudent()
.getCurrentStudentPosition()
.defineName(this.name)
.defineAge(this.age)
.build()
.print("Hello!!");
}
}
public class Dispatch2Event extends DispatchEvent {
private String nickname;
public Dispatch2Event(String name, int age, String nickname) {
this.name = name;
this.age = age;
this.nickname = nickname;
}
public String getNickname() {
return this.nickname;
}
}
@Local
public interface StatelessEjbEventObserver extends Serializable {
/**
* Observe the event execution...
*
* @param event
*/
void onEjbAsynchEvent(@Observes DispatchEvent event);
void onEjbEvent(@Observes Dispatch2Event event);
}
@Stateless
public class EjbStatelessEjbEventObserverImpl implements StatelessEjbEventObserver {
/**
* serial
*/
private static final long serialVersionUID = 2264643954576089691L;
@Asynchronous
@Override
public void onEjbAsynchEvent(@Observes DispatchEvent<E> event) {
// do anything here...
event.submit(); // execution
System.out.println("Hello: " + event.getName()); }
@Override
public void onEjbEvent(@Observes Dispatch2Event<E> event) {
// do anything here...
event.submit(); // execution
System.out.println("Hello2: " + event.getNickname());
}
}
Pay attention if you need to work with Thread Safe...
The event will be fired from a CDI Object and after that the EJB will dispatch the "submit" method as an Asynchronous operation.
Take it easy to avoid overhead on performance stuff, if you are using transactions, because the container must lost the control over Asynch method.
- CDI Service
public class PersonService {
@Inject
private Event<DispatchEvent> dispatcher;
@Inject
private Event<Dispatch2Event> dispatcher2;
public dispatch(DispatchEvent event) {
dispatcher.fire(event);
}
public dispatch(Dispatch2Event event) {
dispatcher2.fire(event);
}
}
- Singleton EJB (Startup)
@Singleton
@Startup
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class EjbSingletonStartup {
//@Inject // repository implementation...access person data information
//private PersonRepository personRepo;
@Inject PersonService pService;
@PostConstruct
protected void init() throws InterruptedException, ExecutionException, TimeoutException {
//PersonLegacy p = personRepo.findById(0L); // ADMIN test sample
pService.dispatch(new DispatchEvent("alvesfred", 38));
pService.dispatch2(new Dispatch2Event("alvesfred", 38, "fred"));
}
}
So, it is just a sample concept and not a real implementation or production code.
In JEE 7, I advice you to use services like ManagedExecutorService (see the assumptions over JSR-236 to know more about concurrency/multithread).
Thanks a lot and regards.
Thanks for reading my posts.
Now, I would like to present some tips about Asynch implementation.
Let's see the following code below...
Environment:
Java EE 6/7 and Java SE 1.7/1.8
CDI 1.x
JBoss EAP/AS/Wildfly and so on...
- EJB Asynch
public interface CustomEvent extends Serializable {
/**
* Submit event execution
*
* @param event
*/
void submit();
}
public class DispatchEvent implements CustomEvent { private String name;
protected int age;
public DispatchEvent(String name, int age) { this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
@Override
public void submit() {
// builder pattern sample...see other posts about this pattern
StudentsBuilder studentsBuilder = new StudentsBuilder();
studentsBuilder.addStudent()
.getCurrentStudentPosition()
.defineName(this.name)
.defineAge(this.age)
.build()
.print("Hello!!");
}
}
public class Dispatch2Event extends DispatchEvent {
private String nickname;
public Dispatch2Event(String name, int age, String nickname) {
this.name = name;
this.age = age;
this.nickname = nickname;
}
public String getNickname() {
return this.nickname;
}
}
@Local
public interface StatelessEjbEventObserver extends Serializable {
/**
* Observe the event execution...
*
* @param event
*/
void onEjbAsynchEvent(@Observes DispatchEvent event);
void onEjbEvent(@Observes Dispatch2Event event);
}
@Stateless
public class EjbStatelessEjbEventObserverImpl implements StatelessEjbEventObserver {
/**
* serial
*/
private static final long serialVersionUID = 2264643954576089691L;
@Asynchronous
@Override
public void onEjbAsynchEvent(@Observes DispatchEvent<E> event) {
// do anything here...
event.submit(); // execution
System.out.println("Hello: " + event.getName()); }
@Override
public void onEjbEvent(@Observes Dispatch2Event<E> event) {
// do anything here...
event.submit(); // execution
System.out.println("Hello2: " + event.getNickname());
}
}
Pay attention if you need to work with Thread Safe...
The event will be fired from a CDI Object and after that the EJB will dispatch the "submit" method as an Asynchronous operation.
Take it easy to avoid overhead on performance stuff, if you are using transactions, because the container must lost the control over Asynch method.
- CDI Service
public class PersonService {
@Inject
private Event<DispatchEvent> dispatcher;
@Inject
private Event<Dispatch2Event> dispatcher2;
public dispatch(DispatchEvent event) {
dispatcher.fire(event);
}
public dispatch(Dispatch2Event event) {
dispatcher2.fire(event);
}
}
- Singleton EJB (Startup)
@Singleton
@Startup
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class EjbSingletonStartup {
//@Inject // repository implementation...access person data information
//private PersonRepository personRepo;
@Inject PersonService pService;
@PostConstruct
protected void init() throws InterruptedException, ExecutionException, TimeoutException {
//PersonLegacy p = personRepo.findById(0L); // ADMIN test sample
pService.dispatch(new DispatchEvent("alvesfred", 38));
pService.dispatch2(new Dispatch2Event("alvesfred", 38, "fred"));
}
}
So, it is just a sample concept and not a real implementation or production code.
In JEE 7, I advice you to use services like ManagedExecutorService (see the assumptions over JSR-236 to know more about concurrency/multithread).
Thanks a lot and regards.
Thursday, May 12, 2016
Java Application Performance Management - inspectIT
Hi all...
Thanks again to stay here, reading my post.
Today i will show how to install and configure inspectIT. It is a good tool for java application performance management.
Let's see my environment:
- Ubuntu 15
- JBoss EAP 6.4
- inspectIT 1.5
- JDK 1.8
inspectIT Download
http://www.inspectit.rocks/
After complete the download of the jar file...
# java -jar inspectit.installer-all.linux.x64.jar
Install inspectIT and features by default...
Editing - inspectIT configuration file
# vim /opt/java/inspectIT/agent/config/inspectit-agent.cfg
Uncomment these lines:
$include common/ejb.cfg
$include common/http.cfg
$include common/hibernate.cfg
#$include common/struts.cfg
$include common/jsf.cfg
$include common/jpa.cfg
$include common/jta.cfg
$include common/webservice.cfg
Save the file...
Edit the JBoss Standalone configuration file
# vim $jboss-home/bin/standalone.conf
...
# Added for logging problem
JBOSS_MODULES_SYSTEM_PKGS="org.jboss.logmanager"
if [ "x$JBOSS_MODULES_SYSTEM_PKGS" = "x" ]; then
JBOSS_MODULES_SYSTEM_PKGS="org.jboss.byteman"
fi
...
#inspectIT
INSPECTIT_AGENT_HOME="/opt/java/inspectIT/agent"
echo $INSPECTIT_AGENT_HOME
INSPECTIT_CONFIG_HOME="/opt/java/inspectIT/agent/config/"
echo $INSPECTIT_CONFIG_HOME
INSPECTIT_JAVA_OPTS="-Xbootclasspath/p:$INSPECTIT_AGENT_HOME/inspectit-agent.jar -javaagent:$INSPECTIT_AGENT_HOME/inspectit-agent.jar -Dinspectit.config=$INSPECTIT_CONFIG_HOME"
echo $INSPECTIT_JAVA_OPTS
...
# Sample JPDA settings for remote socket debugging
JAVA_OPTS="$INSPECTIT_JAVA_OPTS $JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n"
# Added for logging problem
JBOSS_HOME="/opt/java/jboss/jboss-eap-6.4.0"
JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Xbootclasspath/p:$JBOSS_HOME/modules/system/layers/base/org/jboss/logmanager/main/jboss-logmanager-1.5.4.Final-redhat-1.jar"
Let's start JBoss...
# $JBOSS_HOME/bin/standalone.sh -c standalone-full-ha.xml
Let's start the Local CMR (repository)
# $INSPECTIT_HOME/CMR/startup.sh
(it will be possible to see that the service and 8182 port were initialized)
Now, local CMR is ready to receive informations about your application inside JBoss EAP Middleware, using inspectIT agents/sensors.
That's it!!
So, we need to manage the java application performance using inspectIT client...
# $INSPECTIT_HOME/inspectit/inspectIT
Thanks a lot and see you on the next post!
If you have any doubts or problems with java features, please let me know. I will do my best to help you.
Thanks again to stay here, reading my post.
Today i will show how to install and configure inspectIT. It is a good tool for java application performance management.
Let's see my environment:
- Ubuntu 15
- JBoss EAP 6.4
- inspectIT 1.5
- JDK 1.8
inspectIT Download
http://www.inspectit.rocks/
After complete the download of the jar file...
# java -jar inspectit.installer-all.linux.x64.jar
Install inspectIT and features by default...
Editing - inspectIT configuration file
# vim /opt/java/inspectIT/agent/config/inspectit-agent.cfg
Uncomment these lines:
$include common/ejb.cfg
$include common/http.cfg
$include common/hibernate.cfg
#$include common/struts.cfg
$include common/jsf.cfg
$include common/jpa.cfg
$include common/jta.cfg
$include common/webservice.cfg
Save the file...
Edit the JBoss Standalone configuration file
# vim $jboss-home/bin/standalone.conf
...
# Added for logging problem
JBOSS_MODULES_SYSTEM_PKGS="org.jboss.logmanager"
if [ "x$JBOSS_MODULES_SYSTEM_PKGS" = "x" ]; then
JBOSS_MODULES_SYSTEM_PKGS="org.jboss.byteman"
fi
...
#inspectIT
INSPECTIT_AGENT_HOME="/opt/java/inspectIT/agent"
echo $INSPECTIT_AGENT_HOME
INSPECTIT_CONFIG_HOME="/opt/java/inspectIT/agent/config/"
echo $INSPECTIT_CONFIG_HOME
INSPECTIT_JAVA_OPTS="-Xbootclasspath/p:$INSPECTIT_AGENT_HOME/inspectit-agent.jar -javaagent:$INSPECTIT_AGENT_HOME/inspectit-agent.jar -Dinspectit.config=$INSPECTIT_CONFIG_HOME"
echo $INSPECTIT_JAVA_OPTS
...
# Sample JPDA settings for remote socket debugging
JAVA_OPTS="$INSPECTIT_JAVA_OPTS $JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n"
# Added for logging problem
JBOSS_HOME="/opt/java/jboss/jboss-eap-6.4.0"
JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Xbootclasspath/p:$JBOSS_HOME/modules/system/layers/base/org/jboss/logmanager/main/jboss-logmanager-1.5.4.Final-redhat-1.jar"
Let's start JBoss...
# $JBOSS_HOME/bin/standalone.sh -c standalone-full-ha.xml
Let's start the Local CMR (repository)
# $INSPECTIT_HOME/CMR/startup.sh
(it will be possible to see that the service and 8182 port were initialized)
Now, local CMR is ready to receive informations about your application inside JBoss EAP Middleware, using inspectIT agents/sensors.
That's it!!
So, we need to manage the java application performance using inspectIT client...
# $INSPECTIT_HOME/inspectit/inspectIT
Thanks a lot and see you on the next post!
If you have any doubts or problems with java features, please let me know. I will do my best to help you.
Wednesday, May 4, 2016
Hibernate/JPA Entity Model
Hi All,
Thanks again to stay here reading my post.
I would like to help other developers to solve problems about Java and middleware implementations.
If you have any doubts or problems about Java/JEE or JBoss Midleware feel free to contact me (fredericocerqueiraalves@gmail.com). It will be a pleasure to help you.
Now, i would like to show you a model implementation to use hibernate entity beans.
These classes are implemented to support hibernate first or second level cache, audit with envers and native or named queries.
So, let's see...
- Base Model
package br.com.alvesfred.entity;
import java.io.Serializable;
/**
* Base Model Interface
*
* @author alvesfred
*
*/
public interface BaseModel<ID> extends Serializable {
/**
* Set ID definition
*
* @param id
*/
void setId(ID id);
/**
* Get ID
*
* @return
*/
ID getId();
}
- Entity Base Model
package br.com.alvesfred.entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
/**
* Model for Entities
*
* @author alvesfred
*
* @param <ID>
*/
@MappedSuperclass
public abstract class BaseModelEntity<ID> implements BaseModel<ID> {
/**
* serial
*/
private static final long serialVersionUID = 3958601406206249649L;
//@Id
//@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "default_id_generator")
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hilo_sequence_generator")
@GenericGenerator(
name = "hilo_sequence_generator",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = { // default parameters
@Parameter(name = "sequence_name", value = "sq_id"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1"),
@Parameter(name = "optimizer", value = "hilo")
})
protected ID id;
public BaseModelEntity() {
}
public BaseModelEntity(ID id) {
setId(id);
}
public ID getId() {
return id;
}
public void setId(ID id) {
this.id = id;
}
@Override
public int hashCode() {
HashCodeBuilder hcb = new HashCodeBuilder();
hcb.append(this.id);
return hcb.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass().isAssignableFrom(BaseModelEntity.class)) {
return false;
}
@SuppressWarnings("unchecked")
BaseModelEntity<ID> other = (BaseModelEntity<ID>) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.getId(), other.getId());
return eb.isEquals();
}
}
- Version (Entity Base Model)
package br.com.alvesfred.entity;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
/**
* Lock version entity - base model
*
* @author alvesfred
*
* @param <ID>
* @param <VERSION>
*/
@MappedSuperclass
public abstract class BaseModelVersionEntity<ID> extends BaseModelEntity<ID> {
/**
* serial
*/
private static final long serialVersionUID = 9205887194329558055L;
//@Generated(GenerationTime.NEVER)
@Version
@Column(name = "versionId", nullable = false)
private Long version;
public Long getVersion() {
return (this.version != null) ? this.version : this.hashCode();
}
public void setVersion(Long versao) {
this.version = versao;
}
}
- Finally Entity Class
package br.com.alvesfred.entity;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.ColumnResult;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.QueryHint;
import javax.persistence.SequenceGenerator;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.SqlResultSetMappings;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.envers.Audited;
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) // using JTA by container
@Entity
@Audited
@Table(name="person")
@SequenceGenerator(name = "hilo_sequence_generator", sequenceName = "seq_id_person", allocationSize = 1)
@AttributeOverrides({
@AttributeOverride(name="id", column=@Column(name = "person_id", unique = true, nullable = false, scale = 0)),
})
@NamedQueries({
@NamedQuery(
name = PersonEntity.LIST_BY_ID_NAME,
query = "select new PersonEntity(p.id) "
+ "from PersonEntity p "
+ "where p.name = :name",
hints = {
@QueryHint (name="org.hibernate.cacheable", value="true"),
}
),
})
@NamedNativeQueries(
value = {
@NamedNativeQuery(
name = PersonEntity.LIST_NATIVE_BY_NAME,
query = PersonEntity.SQL_NATIVE_BY_NAME,
resultSetMapping = PersonEntity.MAPPING_NATIVE_BY_NAME),
})
@SqlResultSetMappings(
value = {
@SqlResultSetMapping(
name = PersonEntity.MAPPING_NATIVE_BY_NAME,
columns = {
@ColumnResult(name="size")}),
}
)
public class PersonEntity extends BaseModelVersionEntity<Long> {
private static final long serialVersionUID = -1355055022303449688L;
// Named Queries
public static final String LIST_BY_ID_NAME = "PersonEntity.listByIdName";
// Native Named Queries
public static final String LIST_NATIVE_BY_NAME = "PersonEntity.nativeListByIdName";
// SQL
protected static final String SQL_NATIVE_BY_NAME =
" select count(*) as size "
+ " from person "
+ " where name = :name ";
// MAPPING
public static final String MAPPING_NATIVE_BY_NAME = "PersonEntity.mappingListByIdName";
@Lob
@Column(name = "jsonInfo", nullable = false)
private String jsonInfo; // a complete file text information, using json jackson parser
@Column(name = "name", nullable = false)
private String name;
@Column(name = "age", nullable = true)
private int age;
}
That's it!
Thanks a lot and feel free to contact me for any help.
See you soon...
Thanks again to stay here reading my post.
I would like to help other developers to solve problems about Java and middleware implementations.
If you have any doubts or problems about Java/JEE or JBoss Midleware feel free to contact me (fredericocerqueiraalves@gmail.com). It will be a pleasure to help you.
Now, i would like to show you a model implementation to use hibernate entity beans.
These classes are implemented to support hibernate first or second level cache, audit with envers and native or named queries.
So, let's see...
- Base Model
package br.com.alvesfred.entity;
import java.io.Serializable;
/**
* Base Model Interface
*
* @author alvesfred
*
*/
public interface BaseModel<ID> extends Serializable {
/**
* Set ID definition
*
* @param id
*/
void setId(ID id);
/**
* Get ID
*
* @return
*/
ID getId();
}
- Entity Base Model
package br.com.alvesfred.entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
/**
* Model for Entities
*
* @author alvesfred
*
* @param <ID>
*/
@MappedSuperclass
public abstract class BaseModelEntity<ID> implements BaseModel<ID> {
/**
* serial
*/
private static final long serialVersionUID = 3958601406206249649L;
//@Id
//@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "default_id_generator")
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hilo_sequence_generator")
@GenericGenerator(
name = "hilo_sequence_generator",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = { // default parameters
@Parameter(name = "sequence_name", value = "sq_id"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1"),
@Parameter(name = "optimizer", value = "hilo")
})
protected ID id;
public BaseModelEntity() {
}
public BaseModelEntity(ID id) {
setId(id);
}
public ID getId() {
return id;
}
public void setId(ID id) {
this.id = id;
}
@Override
public int hashCode() {
HashCodeBuilder hcb = new HashCodeBuilder();
hcb.append(this.id);
return hcb.toHashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass().isAssignableFrom(BaseModelEntity.class)) {
return false;
}
@SuppressWarnings("unchecked")
BaseModelEntity<ID> other = (BaseModelEntity<ID>) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.getId(), other.getId());
return eb.isEquals();
}
}
- Version (Entity Base Model)
package br.com.alvesfred.entity;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
/**
* Lock version entity - base model
*
* @author alvesfred
*
* @param <ID>
* @param <VERSION>
*/
@MappedSuperclass
public abstract class BaseModelVersionEntity<ID> extends BaseModelEntity<ID> {
/**
* serial
*/
private static final long serialVersionUID = 9205887194329558055L;
//@Generated(GenerationTime.NEVER)
@Version
@Column(name = "versionId", nullable = false)
private Long version;
public Long getVersion() {
return (this.version != null) ? this.version : this.hashCode();
}
public void setVersion(Long versao) {
this.version = versao;
}
}
- Finally Entity Class
package br.com.alvesfred.entity;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.ColumnResult;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.QueryHint;
import javax.persistence.SequenceGenerator;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.SqlResultSetMappings;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.envers.Audited;
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) // using JTA by container
@Entity
@Audited
@Table(name="person")
@SequenceGenerator(name = "hilo_sequence_generator", sequenceName = "seq_id_person", allocationSize = 1)
@AttributeOverrides({
@AttributeOverride(name="id", column=@Column(name = "person_id", unique = true, nullable = false, scale = 0)),
})
@NamedQueries({
@NamedQuery(
name = PersonEntity.LIST_BY_ID_NAME,
query = "select new PersonEntity(p.id) "
+ "from PersonEntity p "
+ "where p.name = :name",
hints = {
@QueryHint (name="org.hibernate.cacheable", value="true"),
}
),
})
@NamedNativeQueries(
value = {
@NamedNativeQuery(
name = PersonEntity.LIST_NATIVE_BY_NAME,
query = PersonEntity.SQL_NATIVE_BY_NAME,
resultSetMapping = PersonEntity.MAPPING_NATIVE_BY_NAME),
})
@SqlResultSetMappings(
value = {
@SqlResultSetMapping(
name = PersonEntity.MAPPING_NATIVE_BY_NAME,
columns = {
@ColumnResult(name="size")}),
}
)
public class PersonEntity extends BaseModelVersionEntity<Long> {
private static final long serialVersionUID = -1355055022303449688L;
// Named Queries
public static final String LIST_BY_ID_NAME = "PersonEntity.listByIdName";
// Native Named Queries
public static final String LIST_NATIVE_BY_NAME = "PersonEntity.nativeListByIdName";
// SQL
protected static final String SQL_NATIVE_BY_NAME =
" select count(*) as size "
+ " from person "
+ " where name = :name ";
// MAPPING
public static final String MAPPING_NATIVE_BY_NAME = "PersonEntity.mappingListByIdName";
@Lob
@Column(name = "jsonInfo", nullable = false)
private String jsonInfo; // a complete file text information, using json jackson parser
@Column(name = "name", nullable = false)
private String name;
@Column(name = "age", nullable = true)
private int age;
}
That's it!
Thanks a lot and feel free to contact me for any help.
See you soon...
Subscribe to:
Posts (Atom)