Java EE | Java Enterprise Edition |
Java SE | Java Standart Edition |
SOAP | Simplke Object Transfair Protocol |
ACC | Application Client Container |
EJB | Enterprise Java Bean |
DD | Deployment Descriptor |
POJO | Plain Old Java Object |
IoC | Inversion of COntrol |
JSF | Java Server Faces |
JSP | Java Server Pages |
JSF | Java Server Faces |
JPA | Java Persistance API |
JMS | Java Messaging Service |
JDBC | Java Database COnnectivity |
JNDI | Java Naming and DIrectory Service |
RMI | Remote Method Invocation |
Introduction into JEE | https://docs.oracle.com/javaee/6/tutorial/doc/gfirp.html |
Introduction into Hibernate - JPA implementation delivered with JBoss Application Server | http://docs.jboss.org/hibernate/core/3.3/reference/en/html/index.html |
This service offers a transaction demarcation API used by the container and the application. It also provides an interface between the transaction manager and a resource manager at the Service Provider Interface (SPI) level.
JPA - Standard API for object-relational mapping (ORM). With its Java Persistence Query Language (JPQL), you can query objects stored in the underlying database.
Hibernate implements JPA.
Bean Validation provides class and method level constraint declaration and validation facilities.
JMS - Java Message Service : This allows components to communicate asynchronously through messages. It supports reliable point-to-point (P2P) messaging as well as the publish-subscribe (pub-sub) model.
JDBC is an application programming interface (API) for the programming language Java, that defines how a client may access a database. It is part of the Java Standard Edition platform. For different Databases there are different implementations: for PostGreSQL, Oracle etc.
JNDI - This API, included in Java SE, is used to access naming and directory systems. Your application uses it to associate (bind) names to objects and then to find these objects (lookup) in a directory. You can look up data sources, JMS factories, EJBs, and other resources. Omnipresent in your code until J2EE 1.4, JNDI is used in a more transparent way through injection.
Article: http://www.javaworld.com/article/2074186/jndi/j2ee-or-j2se--jndi-works-with-both.html
The Syntax of JNDI Path is the following:
namespace | java:/, java:global/ - the prefix of the ressource path, to make the ressource name unique for a given server |
ressource path | everything after the namespace : java:global/MyBean |
Some Details about JNDI Syntax:
Many applications require the ability to send e-mails, which can be implemented through use of the JavaMail API.
The JAF API, included in Java SE, provides a framework for handling data in different MIME types. It is used by JavaMail.
Most Java EE components can be deployed with optional XML deployment descriptors, and applications often have to manipulate XML documents. The Java API for XML Processing (JAXP) provides support for parsing documents with SAX and DOM APIs, as well as for XSLT. The Streaming API for XML (StAX) provides a pull-parsing API for XML.
New in Java EE 7 the Java API for JSON Processing (JSON-P) allows applications to parse, generate, transform, and query JSON.
Connectors allow you to access EIS (enterprise information systems) from a Java EE component. These could be databases, mainframes, or enterprise resource planning (ERP) programs.
Java Authentication and Authorization Service (JAAS) enables services to authenticate and enforce access controls upon users. The Java Authorization Service Provider Contract for Containers (JACC) defines a contract between a Java EE application server and an authorization service provider, allowing custom authorization service providers to be plugged into any Java EE product. Java Authentication Service Provider Interface for Containers (JASPIC) defines a standard interface by which authentication modules may be integrated with containers so that these modules may establish the authentication identities used by containers.
Java EE provides support for SOAP and RESTful web services. The Java API for XML Web Services (JAX-WS), replacing the Java API for XML-based RPC (JAX-RPC), provides support for web services using the SOAP/HTTP protocol. The Java API for RESTful Web Services (JAX-RS) provides support for web services using the REST style.
Jax-RS - allows to implement REST Services easily.
Jax-RS vs Servlet
PRO:
CONTRA:
Since Java EE 5, some resources (data sources, JMS factories, persistence units, EJBs . . .) can be injected in managed components. Java EE 7 goes further by using CDI as well as the DI (Dependency Injection for Java) specifications.
Java EE defines APIs for managing containers and servers using a special management enterprise bean. The Java Management Extensions (JMX) API is also used to provide some management support. Deployment: The Java EE Deployment Specification defines a contract between deployment tools and Java EE products to standardize application deployment.
There are many technologies which are using each other.
Since JSF 2.0, JSP has been deprecated as view technology in favor of Facelets.
JSP is a Java view technology running on the server machine which allows you to write template text in (the client side languages like HTML, CSS, JavaScript and so on). JSP supports taglibs, which are backed by pieces of Java code that let you control the page flow or output dynamically. A well known taglib is JSTL. JSP also supports Expression Language, which can be used to access backend data (via attributes available in page, request, session and application scopes), mostly in combination with taglibs.
When a JSP is requested for the first time or when the webapp starts up, the servlet container will compile it into a class extending HttpServlet and use it during the webapp's lifetime. You can find the generated source code in the server's work directory. In for example Tomcat, it's the /work directory. On a JSP request, the servlet container will execute the compiled JSP class and send the generated output (usually just HTML/CSS/JS) through the webserver over network to the client side, which in turn displays it in the web browser.
Servlet is an Java application programming interface (API) running on the server machine, which intercepts requests made by the client and generates/sends a response. A well known example is the HttpServlet which provides methods to hook on HTTP requests using the popular HTTP methods such as GET and POST. You can configure HttpServlets to listen on a certain HTTP URL pattern, which is configurable in web.xml, or more recently with Java EE 6, with @WebServlet annotation.
When a Servlet is first requested or during webapp startup, the servlet container will create an instance of it and keep it in memory during the webapp's lifetime. The same instance will be reused for every incoming request whose URL matches the servlet's URL pattern. You can access the request data by HttpServletRequest and handle the response by HttpServletResponse. Both objects are available as method arguments inside any of the overridden methods of HttpServlet, such as doGet() and doPost().
JSF is a replacement for JSP
JSF (Java Server Faces) is a component based MVC framework which is built on top of the Servlet API, and provides components via taglibs which can be used in JSP or any other Java based view technology such as Facelets. Facelets is much more suited to JSF than JSP. It namely provides great templating capabilities such as composite components, while JSP basically only offers the <jsp:include> for templating, so that you're forced to create custom components with raw Java code (which is a bit opaque and a lot of tedious work in JSF) when you want to replace a repeated group of components with a single component. Since JSF 2.0, JSP has been deprecated as view technology in favor of Facelets.
As being a MVC (Model-View-Controller) framework, JSF provides the FacesServlet as the sole request-response Controller. It takes all the standard and tedious HTTP request/response work from your hands, such as gathering user input, validating/converting them, putting them in model objects, invoking actions and rendering the response.
This way you end up with basically a JSP or Facelets (XHTML) page for View and a Javabean class as Model. The JSF components are been used to bind the view with the model (such as your ASP.NET web control does) and the FacesServlet uses the JSF component tree to do all the work.
Facelets are an alternative view technology based on pure XML templates (no scriptlets) which was introduced with Version 2 of the JSF standard. They can only be used in a JSF application.
Deployment describtor is a file, which may be added to the application. It may contain metadata. It is optional. Its data may be added via annotations.
application.xml | Java EE META-INF |
application-client.xml | Java EE META-INF |
beans.xml | CDI META-INF or WEB-INF |
ra.xml | JCA META-INF |
ejb-jar.xml | EJB META-INF or WEB-INF |
faces-config.xml | JSF WEB -INF |
persistence.xml | JPA META-INF |
validation.xml | Bean Validation META-INF or WEB-INF |
web.xml | Servlet WEB-INF |
web-fragment.xml | Servlet WEB-INF |
webservices.xml | SOAP Web Services META-INF or WEB-INF |
Beans. At deployment time, CDI checks all of your application’s jar and war files and each time it finds a beans.xml deployment descriptor it manages all the POJOs, which then become CDI Beans.
Without a beans.xml file in the class path (under the META-INF or WEB-INF directory), CDI will not be able to use injection, interception, decoration, and so forth.
If your web application contains several jar files and you want to have CDI enabled across the entire application, each jar will need its own beans.xml to trigger CDI and bean discovery for each jar.
To be deployed in a container, components have first to be packaged in a standard formatted archive. EAR, JAR, WAR. Goncalves, Antonio (2013-06-26). Beginning Java EE 7 (p. 6). Apress. Kindle Edition.
An application client module contains Java classes and other resource files packaged in a jar file. This jar file can be executed in a Java SE environment or in an application client container. Like any other archive format, the jar file contains an optional META-INF directory for meta information describing the archive. The META-INF/MANIFEST.MF file is used to define extension- and package-related data. If deployed in an ACC, the deployment descriptor can optionally be located at META-INF/application-client.xml.
An EJB module contains one or more session and/or message-driven beans (MDBs) packaged in a jar file (often called an EJB jar file). It contains an optional META-INF/ejb-jar.xml deployment descriptor and can be deployed only in an EJB container.
A web application module contains servlets, JSPs, JSF pages, and web services, as well as any other web-related files (HTML and XHTML pages, Cascading Style Sheets (CSS), Java-Scripts, images, videos, and so on). Since Java EE 6, a web application module can also contain EJB Lite beans (a subset of the EJB API described in Chapter 7). All these artifacts are packaged in a jar file with a .war extension (commonly referred to as a war file, or a Web Archive). The optional web deployment descriptor is defined in the WEB-INF/web.xml file. If the war contains EJB Lite beans, an optional deployment descriptor can be set at WEB-INF/ejb-jar.xml. Java.class files are placed under the WEB-INF/classes directory and dependent jar files in the WEB-INF/lib directory.
An enterprise module can contain zero or more web application modules, zero or more EJB modules, and other common or external libraries. All this is packaged into an enterprise archive (a jar file with an .ear extension) so that the deployment of these various modules happens simultaneously and coherently. The optional enterprise module deployment descriptor is defined in the META-INF/application.xml file. The special lib directory is used to share common libraries between the modules.
Classes define Depnedencies via Injection Points by using Interfaces or classes
If there are unambigouties - the applicaiton wont deploy.
To resolve unambiguties - use Qualifiers or @Default annotation.
Qualifiers are applied at 2 different places:
Declare Qualifier
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.inject.Qualifier; /** * The most unusual annotation is - @Qualifier */ @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) public @interface NumberCalculation2002{ }
IMplement Injection Point INterface “NumberGenerator”.
It will be the default IMplementation.
It will be an IMplementation qualified with @NumberCalculation2016
@Default @NumberCalculation2016 @Stateless public class ISBNGenerator implements NumberGenerator { @Override public String generateNumber() { return "13-84356-" + Math.abs(new Random().nextInt()); } }
Inject implementations.
@Inject @NumberCalculation2002 private NumberGenerator numberGeneratorOld; @Inject @NumberCalculation2016 private NumberGenerator numberGeneratorNew; // @Default annotated implementation will be injected @Inject private NumberGenerator numberGeneratorDefault;
Define some numbers and name them, by using Quialifier-annotations.
import java.util.Random; import javax.enterprise.inject.Produces; import de.exp.cdibean.stateless.qualifier.NumberCalculation2016Middle; import de.exp.cdibean.stateless.qualifier.NumberCalculation2016Prefix; import de.exp.cdibean.stateless.qualifier.NumberCalculation2016Random; /** * This is a Producer class. * It only defines some injectable numbers. * The numbers are injected by type and name. * * @NumberCalculation2016Prefix, @NumberCalculation2016Middle, @NumberCalculation2016Random * are Qualifiers - names to distinguish which String needs to be injected. */ public class NumberProducer { @Produces @NumberCalculation2016Prefix private String prefix13DIgits = "13-"; @Produces @NumberCalculation2016Middle private double middleDigits = 12345; @Produces @NumberCalculation2016Random private int random(){ return Math.abs(new Random().nextInt()); } }
Use the numbers, created by Producers. The INjections is resolved by
// @Stateless annotation is not needed! @Default public class ISBNGeneratorWithProducer implements NumberGenerator { /** * Injecting those variables is possible, because there are @Produces annotations in NumberProducer.class */ @Inject @NumberCalculation2016Prefix String prefix; @Inject @NumberCalculation2016Middle double middle; @Inject @NumberCalculation2016Random int random; @Override public String generateNumber() { return prefix + middle + random; } }
The environment of an InjectionPoint may be retrieved by defining the InjectionPoint.class as Producer-methods parameter.
It provides infos about:
@Produces @TempFile private FileOutputStream getFileInputStream(InjectionPoint injectionPoint){ String beantype = injectionPoint.getBean().getBeanClass().getSimpleName();
A Destructor is a method in same class as Producer method, with an argument equal to the producers result. It is called, after Context destruction to clean up Producers' value.
/** * Producer method - creates a FileOutputStream * * @param injectionPoint - contains infos about the environment: InjectionPoint, Bean containing the InjectionPoint etc. * * @TempFile will be used at InjectionPoints, so say, that this concrete FileOutputStream is needed * * @return */ @Produces @TempFile private FileOutputStream getFileInputStream(InjectionPoint injectionPoint){ String beantype = injectionPoint.getBean().getBeanClass().getSimpleName(); String name = UUID.randomUUID().toString(); File file = new File("d:\\Temp\\"+beantype+name); FileOutputStream f = null; try { f = new FileOutputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } return f; } /** * Destructor method - closes FileOutputStream, opened by Producer method. * Destructor is triggered, when the associated Context is destoyed by the Application. * E.g. if the injectionPoint is within a RESTful service - the Destruction will happen directly after the service returned it's value. * * The Qualifier MUST be the same for disposal method to work. */ private void disposeFileInputStream(@Disposes @TempFile FileOutputStream f) throws IOException{ f.close(); }
You have first to define some informations about the Web-Application itselfe first.
Details
Just create a subclass of javax.ws.rs.core.Application and annotate it with @ApplicationPath
import javax.ws.rs.ApplicationPath; /** * Read: https://docs.jboss.org/author/display/AS7/JAX-RS+Reference+Guide * * ACHTUNG: * /jaxrs/ * not /jaxrs/* as you would wright in web.xml. Appending * is not necessary. */ @ApplicationPath("/jaxrs/") public class TheApplication extends javax.ws.rs.core.Application { /* this represents the Web-applicaiton itselfe, * which contains servlets etc. */ }
Add the following to your web.xml. Where /jaxrs/* is the path segment to your Servlets in this web Application.
<servlet-mapping> <servlet-name>javax.ws.rs.core.Application</servlet-name> <url-pattern>/jaxrs/*</url-pattern> </servlet-mapping>
TO define a Servlet which would respond on @GET implement this class.
import java.util.HashMap; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("GPS/mine") public class MyGpsCoordinates { @GET @Produces(MediaType.APPLICATION_JSON) public Map<String, String> getMyGpsCoordinates(){ Map<String, String> m = new HashMap<>(); m.put("y", "47.177546"); m.put("x", "8.430578"); return m; } }
Responding on POST is possible via annotating a method via @POST
@POST @Consumes("text/plain") public void postClichedMessage(String message) { // Store the message }
The URL is a composite of
The Result in my case is:
http://localhost:8080/ Hochzeitsportalweb/ jaxrs/ System/properties
Find out which Port your WildFly provides the HTTP data: http://asasa.paywyw.com/wiki/doku.php?id=jboss&#socket_bindings_-_ports
The default HTTP Prt is 8080
In web.xml there you should find the definition of url-pattern
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>Hochzeitsportalweb</display-name> <servlet> <description>JAX-RS Tools Generated - Do not modify</description> <servlet-name>javax.ws.rs.core.Application</servlet-name> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>javax.ws.rs.core.Application</servlet-name> <url-pattern>/jaxrs/*</url-pattern> </servlet-mapping> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> </web-app>
or if you defined your Application in an own subclass of javax.ws.rs.core.Application and used annotations:
@ApplicationPath("/jaxrs/") public class TheApplication extends javax.ws.rs.core.Application { /* this represents the Web-applicaiton itselfe, * which contains servlets etc. */ }
The Class, which is responsible for handling get Requests is annotated by @Path
import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; // where to expose this service? @Path("System/properties") public class SystemProperties { // provide some information on "GET" requests @GET @Produces(MediaType.APPLICATION_JSON) public Map<String, String> getSystemProperties() { Map<String, String> result = new HashMap<>(); Properties props = System.getProperties(); for (Map.Entry<Object, Object> entry : props.entrySet()) { result.put((String) entry.getKey(), (String) entry.getValue()); } return result; } @POST @Consumes("text/plain") public void postClichedMessage(String message) { // Store the message } }
JBoss does NOT have drivers to every DB by default - you have to upload the JNDI Driver, and reference it later, when adding a new DataSource. Deploy the JNDI Driver for your Database (here PostGreSQL) by using admin console.
Here the driver is a file named postgresql-9.4.1207.jre6.jar
Important data:
JNDI Name | java:/PostgresDS | Used to reference the DB from the JEE application. You can find it standalone.sql: <datasource jta="false" jndi-name="java:/PostgresDS" pool-name="PostgresDS" enabled="true" use-ccm="false"> |
Connection URL | Used to connect to the DB via http://squirrel-sql.sourceforge.net/ |
<subsystem xmlns="urn:jboss:domain:datasources:4.0"> <datasources> <datasource jta="false" jndi-name="java:/PostgresDS" pool-name="PostgresDS" enabled="true" use-ccm="false"> <connection-url>jdbc:postgresql://localhost:5432/hochzeitsportaldb</connection-url> <driver-class>org.postgresql.Driver</driver-class> <driver>postgresql-9.4.1207.jre6.jar</driver> <security> <user-name>phppgadmin</user-name> <password>YOURPASSWORDHERE</password> </security> <validation> <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/> <background-validation>true</background-validation> <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"/> </validation> </datasource>
Your JEE Application (here a web-application) has a file named ..src\META-INF\persistence.xml. It contains the DataBase Data.
Modify it as following:
This class Foto is an https://docs.oracle.com/javaee/6/tutorial/doc/bnbqa.html and has to be registered in persistance.xml as all Entities has to be.
import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Foto implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.AUTO) String id; @Column(name="pathPreviewFoto") String pathPreviewFoto; @Column(name="pathFullSizeFoto") String pathFullSizeFoto; @Column(name="priority") int priority; public Foto() { super(); } }
All available dialects are listed here:
This is the resulting persistence.xml for now.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="Hochzeitsportalweb" transaction-type="JTA"> <jta-data-source>java:/PostgresDS</jta-data-source> <class>de.hochzeitsportal.entity.Foto</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
Managed Context Dependency Injection (CDI) Beans.
What is treated as a CDI bean by the container?
What is available?
DB transactions encapsulate a set of DB operations.
The begin with connection creation and
end with a commit or rollback
In CMT container manages start / finish of transaction. The transaction scope of a method is defined by annotations.
possible method annotations:
The explanations are here:
Example:
import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; @Stateless @TransactionManagement(TransactionManagementType.CONTAINER) public class DepartmentBean implements DepartmentBeanRemote { @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void createDepartment() { } }
In bean-managed transaction demarcation, the code in the session or message-driven bean explicitly marks the boundaries of the transaction.
Scopes are a part of JSF - Java Server Faces. The may be used to preserve the Bean in Context.
import java.io.Serializable; import java.util.UUID; import javax.enterprise.context.SessionScoped; import javax.inject.Named; /** * - no public methods in non @Dependent (default) scoped beans * - must be passivation capable * - @javax.inject.Named must be added to the bean to be able to resolve the bean via java-faces. Or it wont be discovered. Further registration in faces.config is not necessary */ @Named @SessionScoped public class UUIDContainerSessionScoped implements Serializable { private static final long serialVersionUID = -866171745569996844L; final String uuid = UUID.randomUUID().toString(); public String getUuid() { return uuid; } }
Must be available
The @Named Bean is referenced from a jsp via #{uUIDContainerSessionScoped .uuid}.
JSF is available in JBoss. But Eclipse won't know it. So you have to add JSF implementation to the project, e.g. via Maven.
<!-- JSF implementation, even if the JBoss app server already has this libs. --> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-impl</artifactId> <version>1.2_15</version> </dependency> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.1</version> </dependency>
The JSF Page is located under WebContent\YourPage.jsp.
It is requested as: http://localhost:8080/YOURPROJECT/faces/YourPage.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <f:view> <h:outputLabel value="Application: "></h:outputLabel> <h:outputLabel value="#{uUIDContainerSessionScoped .uuid}"></h:outputLabel> <br> </f:view> </body> </html>
The container may execute some code, before EVERY method in the container. The place, where you define the executed code is called interceptor.
Related annotations:
@AroundInvoke |
@AroundConstruct |
@Interceptors(MyInterceptor1.class) |
@ExcludeClassInterceptors |
@PostConstruct |
@PreDestroy |
@InterceptorBinding |
@Interceptor |
@Priority(200) |
In WebContent\WEB-INF\beans.xml the interceptors have to be enabled before use.
Registration of Interceptor implemented in org.agoncal.book.javaee7.chapter02.LoggingInterceptor
<beans xmlns=" http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all"> <interceptors> <class>org.agoncal.book.javaee7.chapter02.LoggingInterceptor</class> </interceptors> </beans>
Interceptors are methods, which are triggered by special hooks.
The execution context is available for them.
Hooks
Class construction
public class MyInterceptedClass{ ... @AroundConstruct private void init( InvocationContext ic ) throws Exception { logger.fine("Entering constructor"); try { ic.proceed(); } finally { logger.fine("Exiting constructor"); } }
Any method invocation in class MyInterceptedClass
public class MyInterceptedClass{ ... @AroundInvoke public Object logMethod(InvocationContext ic) throws Exception { logger.entering(ic.getTarget().toString(), ic.getMethod().getName()); try { return ic.proceed(); } finally { logger.exiting(ic.getTarget().toString(), ic.getMethod().getName()); } }
LifeCycle annotation to intercept object-creation and destruction
public class MyInterceptor{ ... @PostConstruct public void prePostConstruct(InvocationContext c) throws Exception{ ... } @PreDestroy public void prePredestroy(InvocationContext c) throws Exception{ ... } // now apply the interceptor @Transactional @Interceptors(MyInterceptor.class) public class CustomerService { // interceptor will be triggered first @PostConstruct void onPostConstruct(){.. // interceptor will be triggered first @PreDestroy void onPreDestroy(){..
You can put the Intercepting methods into an own class and reference it via an annotation:
public class LoggingInterceptor { @Inject private Logger logger; @AroundConstruct ... @AroundInvoke ... } // Reference the interceptor via @Interceptors annotation. // You can annotate classes @Transactional @Interceptors({LoggingInterceptor.class, AnotherInterceptor.class}) public class CustomerService { // you can annotate methods @Interceptors({LoggingInterceptor.class, AnotherInterceptor.class}) public void createCustomer(Customer customer) { em.persist(customer); }
Is an tool for loose coupling.
Enabling CDI is Required to use Interceptor bindings.
Because this feature is implemented in CDI Spec, which extended the Interceptor spec.
Define annotation
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Loggable { }
Associate @Loggable with 2 Interceptors LoggingInterceptor.class, LoggingInterceptor2.class
When @Loggable is applied to an intercepted class - LoggingInterceptor will be executed prior to LoggingInterceptor2, because it's priority is smaller.
@Interceptor @Loggable @Priority(100) public class LoggingInterceptor {...} @Interceptor @Loggable @Priority(200) public class LoggingInterceptor {...}
Apply @Loggable to a method or class
@Loggable public class CustomerService { @Loggable public void createCustomer(Customer customer) {
Predefined prorities are defined here: javax.interceptor.Interceptor
PLATFORM_BEFORE = 0: | Start of range for early interceptors defined by the Java EE platform, |
LIBRARY_BEFORE = 1000: | Start of range for early interceptors defined by extension libraries, |
APPLICATION = 2000: | Start of range for interceptors defined by applications, |
LIBRARY_AFTER = 3000: | Start of range for late interceptors defined by extension libraries, and |
PLATFORM_AFTER = 4000: | Start of range for late interceptors defined by the Java EE platform. |
There is always a @Default version of an injectable bean.
You can modify this injectable bean, by implementing a decorator.
Important:
Enabling a decorator implementation de.exp.decorator.NumberGeneratorDecorator.class in beans.xml
<beans ..> ... <decorators> <class>de.exp.decorator.NumberGeneratorDecorator</class> </decorators> </beans>
Decorator
import javax.decorator.Decorator; import javax.decorator.Delegate; import javax.inject.Inject; import de.exp.cdibean.stateless.NumberGenerator; /** * Check, how the output is decorated: http://localhost:8080/ExpWebProject/jaxrs/books/isbn/ * */ @Decorator public class NumberGeneratorDecorator implements NumberGenerator { /* * @Delegate - markup is important here. It says, that the decorated method go's here * @Default - annotated NumberGenerator.class implementation will be injected here */ @Delegate @Inject NumberGenerator numberGenerator; @Override public String generateNumber() { String originalNumber = numberGenerator.generateNumber(); // decorate here return getClass().getSimpleName() + "-" + originalNumber; } }
Producers send events. Observers receive events.
Producer
public class ... @AddedQualifier @IsNewerThan(date=1458493052) @Inject Event<Date> eventPushTime; @RemovedQualifier @Inject Event<Date> eventPopTime; public void push(){ eventPushTime.fire(new Date()); } public void pop(){ eventPopTime.fire(dao.timeFifoQueue.peekLast()); }
Observer
public void push(@Observes @AddedQualifier @IsNewerThan(date=1458493052) Date date){ ...
Optionally the events may be marked by symantically valuable Qualifiers.
The Qualifiers must be added to the Producers Event-Injection point and to Receiver's @Observes parameter
Optionally members (parameters) may be added to the Qualifiers.
@Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) public @interface AddedQualifier{ } @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) public @interface RemovedQualifier{ } @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) public @interface IsNewerThan { /** * Last date as long * @return */ public long date(); }
Annotation
Apply @Constraint with the validating class, to tell, that its a constraint.
@Constraint(validatedBy = { URLValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RetentionPolicy.RUNTIME) public @interface URL { String message() default "Malformed URL"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String protocol() default ""; String host() default ""; int port() default -1; }
Validator.
This one Validates @URL. (generic parameter)
This one os triggered, when @URL annotates a String. (generic parameter)
public class URLValidator implements ConstraintValidator<URL, String> { private String protocol; private String host; private int port; public void initialize(URL url) { this.protocol = url.protocol(); this.host = url.host(); this.port = url.port(); } public boolean isValid(String value, ConstraintValidatorContext context) { ... } }
You can apply annotations to
@NotNull @Pattern(regexp = "[C,D,M][A-Z][0-9]*") private String orderId; @ClassNameValidator class Order{ } public Order( @Past Date creationDate) { this.creationDate = creationDate; } public @NotNull Double calculateTotalAmount( @GreaterThanZero Double changeRate) { ... }
You can aply existing constraints to your own,
ifg existing constraints are annotated by ANNOTATION_TYPE
@NotNull @Size(min = 7) @Pattern(regexp = "") @Constraint(validatedBy = {}) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RetentionPolicy.RUNTIME) public @interface Email { String message() default "Email address doesn't look good"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
You can apply same annotation multiple times as following:
@Pattern.List({ @Pattern(regexp = "^1.*"), @Pattern(regexp = ".*9$"), }) String var;
Herer @Pattern defines an inner annotation @Pattern.List member, which owns an array of Patterns.
A validator would request the list of Patterns and apply the PatternValidator to each of them.
*/ @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented @Constraint(validatedBy = {}) public @interface Pattern { ... /** * Defines several <code>@Pattern</code> annotations on the same element * @see Pattern * * @author Emmanuel Bernard */ @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented @interface List { Pattern[] value(); } }
javax.persistence.Query query = getEm().createQuery("select e from " + entityClass.getName() + " e"); // QueryImpl(select e from de.ivu.fare.core.domain.MengeMandantBean e) query.unwrap(QueryImpl.class).getHibernateQuery().getQueryString();
package my.example; import java.nio.file.Path; import java.util.Date; import java.util.List; import javax.annotation.Resource; import javax.ejb.Schedule; import javax.ejb.SessionContext; import javax.ejb.Stateless; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Stateless public class ReoccuringQueryExecutor { private static final Logger LOG = LoggerFactory.getLogger(ReoccuringQueryExecutor.class); private static boolean scanning = false; private Object lock = new Object(); @Inject private CrudService crudService; @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false) public void scanFS() { synchronized (lock) { if (scanning) { return; } scanning = true; } try { executeQuery(); } catch (Exception e) { String message = null; LOG.warn(message); } finally { synchronized (lock) { scanning = false; } } } /** You can debug execute the query here */ private void executeQuery(){ CollectorService collectorService = NamingAdapter.get(CollectorService.class, ModuleIds.SALES_MODULE_ID); // Execute the query here Session session = ((HasHibernateSession) ctx.getTarget()).getSession(); Query query = session.createQuery("update Stock set stockName = :stockName" + " where stockCode = :stockCode"); query.setParameter("stockName", "DIALOG1"); query.setParameter("stockCode", "7277"); int result = query.executeUpdate(); } }