To use the entities you create, you must define a persistence unit. Doing so is simple. Create a persistence.xml file not dissimilar from a deployment descriptor, but with far fewer options to worry about. The root element of a persistence configuration file is <persistence>. This element may contain one or more <persistence-unit> elements. No other elements are within <persistence>. <persistence-unit> has two attributes: name specifies the name of the persistence unit and transaction-type indicates whether this persistence unit uses Java Transaction API (JTA) transactions or standard local transactions.
You must specify a name, which is how you locate the persistence unit in code. If not specified, transaction-type defaults to JTA in a Java EE application server and RESOURCE_LOCAL in a Java SE environment or simple Servlet container. However, to prevent unexpected behavior it’s best to always set this value explicitly instead of relying on a default value.
<persistence-unit> contains the following inner elements. None of them are required (so <persistence-unit> may be empty); however, you must specify whichever elements you use in the following order:
- <description> contains a useful description for this persistence unit. Although it makes reading the persistence file easier, it has no semantic value.
- <provider> specifies the fully qualified class name of the javax.persistence.spi.PersistenceProvider implementation used for this persistence unit. By default, when you look up the persistence unit, the API will use the first JPA provider on the classpath. You can include this element to mandate a specific JPA provider.
- You can use either <jta-data-source> or <non-jta-data-source> (but not both) to use a JNDI DataSource resource. You may use <jta-data-source> only if transaction-type is JTA; likewise you may use <non-jta-data-source> only if transaction-type is RESOURCE_LOCAL. Specifying a DataSource causes the persistence unit to use that DataSource for all entity operations.
- <mapping-file> specifies the classpath-relative path to an XML mapping file. If you don’t specify any <mapping-file>, the provider looks for orm.xml. You may specify multiple <mapping-file> elements to use multiple mapping files.
- You can use one or more <jar-file> elements to specify a JAR file or JAR files that the JPA provider should scan for mapping-annotated entities. Any @Entity, @Embeddable, @javax.persistence.MappedSuperclass, or @javax.persistence.Converter classes found are added to the persistence unit.
- You can use one or more <class> elements to indicate specific @Entity, @Embeddable, @MappedSuperclass, or @Converter classes that should be added to the persistence unit. You must annotate the class or classes with JPA annotations.
- Using <exclude-unlisted-classes /> or <exclude-unlisted-classes>true</ exclude-unlisted-classes> indicates that the provider should ignore classes not specified with <jar-file> or <class>. Omitting <exclude-unlisted-classes> or using <exclude-unlisted-classes>false</exclude-unlisted-classes> causes the JPA provider to scan the classpath location of the persistence file for JPA-annotated classes. If persistence.xml is located in a JAR file, that JAR file (and only that JAR file) is scanned for classes. If persistence.xml is located in a directory-based classpath location (such as /WEB-INF/classes), that directory (and only that directory) is scanned for classes. Prior to Hibernate 4.3.0 and Spring Framework 3.2.5, specifying this element with the value false was incorrectly interpreted as true.
- <shared-cache-mode> indicates how entities are cached in the persistence unit (if the JPA provider supports caching, which is optional). NONE disables caching, whereas ALL enables caching for all entities. ENABLE_SELECTIVE means that only entities annotated @javax.persistence.Cacheable or @Cacheable(true) (or marked as cacheable in orm.xml) are cached. DISABLE_SELECTIVE results in caching of all entities except those annotated @Cacheable(false) (or marked as non-cacheable in orm.xml). The default value, UNSPECIFIED, means that the JPA provider decides what the effective default is. Hibernate ORM defaults to ENABLE_SELECTIVE, but relying on this is not portable.
- <validation-mode> indicates if and how Bean Validation should be applied to entities. NONE means that Bean Validation is not enabled, whereas CALLBACK makes the provider validate all entities on insert, update, and delete. AUTO has an effective value of CALLBACK if a Bean Validation provider exists on the classpath and an effective value of NONE if no Bean Validation provider exists on the classpath. If you enable validation, the JPA provider configures a new Validator to validate your entities. If you have configured a special Spring Framework Validator with your custom localized error codes, the JPA provider ignores it. As such, it’s best to set the validation mode to NONE and use Bean Validation before your persistence layer is invoked.
- <properties> provides a way to specify other JPA properties, including standard JPA properties (such as JDBC connection string, username, and password, or schema generation settings) as well as provider-specific properties (such as Hibernate settings). You specify one or more properties using nested <property> elements, each with a name and value attribute.
Labels
- OCPJP
- OCPJP 8
- Path
- Comparator
- Eclipse
- Archetypes
- Arrays
- BufferedReader
- BufferedWriter
- Comparable
- DataInputStream
- DataOutputStream
- DateTimeFormatter
- FileInputStream
- FileOutputStream
- FileReader
- FileWriter
- Files
- Logger
- Maven
- Paths
- Singleton
- StandardCopyOption
- Static nested class
- Threading
- ZonedDateTime
- enum
Showing posts with label Java EE. Show all posts
Showing posts with label Java EE. Show all posts
Friday, December 16, 2016
Sunday, December 11, 2016
Understanding Distributable Java EE Applications
Strictly speaking, a Java EE web application is considered distributable as long as the <distributable/> tag is present in its deployment descriptor and in all /META-INF/web-fragment.xml descriptors in any JAR files packaged in its /WEB-INF/lib directory. If a JAR file does not contain a web-fragment.xml file, it is not considered a web fragment, so it doesn’t count. If a single JAR with a web-fragment.xml lacking <distributable/> is present in an application, or if the deployment descriptor is lacking <distributable/>, the application is considered non-distributable.
This doesn’t mean anything without understanding what, precisely, a distributable Java EE application is. The <distributable/> element indicates that the web application was written to deploy to multiple JVMs running on the same host or on different hosts. In almost all cases, this means that all attributes written to HttpSessions are Serializable. Containers are allowed to support non-Serializable session attributes in distributable applications, but they are not required to, and most simple Servlet containers do not. Tomcat, for example, throws an IllegalArgumentException if a <distributable/> application adds a non-Serializable attribute to a session. The point of using Serializable session attributes is that it permits HttpSessions to be shared among servers in a cluster, which is perhaps the most important reason for using <distributable/>. If two or more containers are configured to work in a cluster, they may share HttpSession data across the cluster only for distributable applications.
Why would you want to have HttpSession data shared across servers in a cluster? The answer to that is quite simple and boils down to the reasons you use a cluster to begin with: scalability and availability. A single server cannot service an infinitely increasing number of users. When a server fails, you want your users transparently shuffled to other servers. Because the majority of applications interact with users using sessions, it’s important for that session data to be shareable across a cluster. This can serve two purposes:
- If a server fails, a user can be sent to a different server and that server will have all the same session data for the user that the failed server had.
- In an ideal world, consecutive user requests can be handled independently of which server receives the request, so a user’s requests can conceivably be handled on different servers every time without losing session information.
For either of these scenarios to work properly, you must make your session attributes Serializable. Because Java objects cannot live beyond the confines of a single Java Virtual Machine, HttpSessions must be serialized before being sent to other servers in the cluster whether over shared memory, a file system, or a network connection. This pattern presents two interesting challenges with solutions for both.
First, sometimes session attributes simply cannot be 100 percent Serializable. This is especially true for legacy applications that are upgraded and refactored. For example, a session attribute may (for whatever reason, however bad) hold on to a database connection or open file handle. These attributes obviously cannot be serialized and shared across the cluster or can they? The javax.servlet.http.HttpSessionActivationListener interface specifies a special type of attribute that knows when it is about to be serialized and sent to other servers in a cluster or has just been deserialized on a server. Any session attribute that implements this interface is notified when it is about to be sent to other servers (via the sessionWillPassivate method) and when it has just been received from another server (via the sessionDidActivate method). In the aforementioned examples, a session attribute could re-open a database connection marked transient in sessionDidActivate.
A more common problem with clustered sessions is performance. For complete server independence to be possible, the server must serialize and share an HttpSession every time you update a session attribute as well as on every request (so that the lastAccessTime property stays up-to-date). This can present a real performance issue in some cases. (Although it still has a net benefit over using only one server.)
For this reason and others, the concept of session stickiness is an important consideration whenever you deploy a distributable application. How session stickiness is configured varies from one container and load balancer to the next, but the concept is the same: Within a single session, all that session’s requests are handled in the same JVM. Sessions are serialized and shared across the cluster only periodically, as often as is practical by the performance standards set by the deployment team.
Sharing sessions less often can cause problems: Imagine having added several items to your shopping cart, and on the next request, the items are no longer in your shopping cart. With sticky sessions, you are always sent to the same server unless your session ends or the server fails, and the problem of session state inconsistency is mitigated. This is not without its downside. Server failures are not predictable, and sessions are rarely left in a consistent state when a failure occurs. When possible, it is always best to maintain session state across the cluster every time a session is updated.
This doesn’t mean anything without understanding what, precisely, a distributable Java EE application is. The <distributable/> element indicates that the web application was written to deploy to multiple JVMs running on the same host or on different hosts. In almost all cases, this means that all attributes written to HttpSessions are Serializable. Containers are allowed to support non-Serializable session attributes in distributable applications, but they are not required to, and most simple Servlet containers do not. Tomcat, for example, throws an IllegalArgumentException if a <distributable/> application adds a non-Serializable attribute to a session. The point of using Serializable session attributes is that it permits HttpSessions to be shared among servers in a cluster, which is perhaps the most important reason for using <distributable/>. If two or more containers are configured to work in a cluster, they may share HttpSession data across the cluster only for distributable applications.
Understanding HTTP Sessions, Stickiness, and Serialization
Why would you want to have HttpSession data shared across servers in a cluster? The answer to that is quite simple and boils down to the reasons you use a cluster to begin with: scalability and availability. A single server cannot service an infinitely increasing number of users. When a server fails, you want your users transparently shuffled to other servers. Because the majority of applications interact with users using sessions, it’s important for that session data to be shareable across a cluster. This can serve two purposes:
- If a server fails, a user can be sent to a different server and that server will have all the same session data for the user that the failed server had.
- In an ideal world, consecutive user requests can be handled independently of which server receives the request, so a user’s requests can conceivably be handled on different servers every time without losing session information.
For either of these scenarios to work properly, you must make your session attributes Serializable. Because Java objects cannot live beyond the confines of a single Java Virtual Machine, HttpSessions must be serialized before being sent to other servers in the cluster whether over shared memory, a file system, or a network connection. This pattern presents two interesting challenges with solutions for both.
First, sometimes session attributes simply cannot be 100 percent Serializable. This is especially true for legacy applications that are upgraded and refactored. For example, a session attribute may (for whatever reason, however bad) hold on to a database connection or open file handle. These attributes obviously cannot be serialized and shared across the cluster or can they? The javax.servlet.http.HttpSessionActivationListener interface specifies a special type of attribute that knows when it is about to be serialized and sent to other servers in a cluster or has just been deserialized on a server. Any session attribute that implements this interface is notified when it is about to be sent to other servers (via the sessionWillPassivate method) and when it has just been received from another server (via the sessionDidActivate method). In the aforementioned examples, a session attribute could re-open a database connection marked transient in sessionDidActivate.
A more common problem with clustered sessions is performance. For complete server independence to be possible, the server must serialize and share an HttpSession every time you update a session attribute as well as on every request (so that the lastAccessTime property stays up-to-date). This can present a real performance issue in some cases. (Although it still has a net benefit over using only one server.)
For this reason and others, the concept of session stickiness is an important consideration whenever you deploy a distributable application. How session stickiness is configured varies from one container and load balancer to the next, but the concept is the same: Within a single session, all that session’s requests are handled in the same JVM. Sessions are serialized and shared across the cluster only periodically, as often as is practical by the performance standards set by the deployment team.
Sharing sessions less often can cause problems: Imagine having added several items to your shopping cart, and on the next request, the items are no longer in your shopping cart. With sticky sessions, you are always sent to the same server unless your session ends or the server fails, and the problem of session state inconsistency is mitigated. This is not without its downside. Server failures are not predictable, and sessions are rarely left in a consistent state when a failure occurs. When possible, it is always best to maintain session state across the cluster every time a session is updated.
Saturday, November 5, 2016
Configuring Sessions in the Deployment Descriptor
In many cases, HTTP sessions are ready to go in Java EE and require no explicit configuration. However, configure them you can, and for security purposes, you should. You configure sessions in the deployment descriptor using the <session-config> tag. Within this tag, you can configure the method by which sessions are tracked, the age after which sessions timeout, and the details of the session ID cookie, if you use that. Many of these have default values that you never need to change. The following code demonstrates all the possible deployment descriptor settings for sessions.
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<name>JSESSIONID</name>
<domain>example.org</domain>
<path>/shop</path>
<comment><![CDATA[Keeps you logged in. See our privacy policy for more information.]]></comment>
<http-only>true</http-only>
<secure>false</secure>
<max-age>1800</max-age>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
<tracking-mode>URL</tracking-mode>
<tracking-mode>SSL</tracking-mode>
</session-config>
All of the tags within <session-config> and <cookie-config> are optional, but they must appear in the order shown in this example (excluding omitted tags).
The <session-timeout> tag specifies how long sessions should remain inactive, in minutes, before being invalidated. If the value is 0 or less, the session never expires. If this tag is omitted, the container default applies. Tomcat’s default container is 30, which can be changed in the Tomcat configuration. If you want consistency, you should explicitly set the timeout using this tag. In this example the timeout is 30 minutes. Each time a user with a certain session ID makes a request to your application, the timer resets on his session’s inactivity. If he goes more than 30 minutes without making a request, his session is considered invalid and he is given a new session.
The <tracking-mode> tag, which was added in Servlet 3.0/Java EE 6, indicates which technique the container should use for tracking session IDs. The legal values are:
- URL : The container only embeds session IDs in URLs. It does not use cookies or SSL session IDs. This approach is not very secure.
- COOKIE : The container uses session cookies for tracking session IDs. This technique is very secure.
- SSL : The container uses SSL Session IDs as HTTP session IDs. This method is the most secure approach available but requires all requests to be HTTPS for it to work properly.
You may use <tracking-mode> more than once to tell the container it can use multiple strategies. For example, if you specify both COOKIE and URL, the container prefers cookies but uses URLs when cookies are not available. Specifying COOKIE as the only tracking mode tells the container to never embed sessions in URLs and always assume the user has cookies enabled. Likewise, specifying URL as the only tracking mode tells the container to never use cookies. If you enable the SSL tracking mode, you cannot also enable the COOKIE or URL modes. SSL Session IDs must be used on their own; the container cannot fall back to cookies or URLs in the absence of HTTPS.
The <cookie-config> tag applies only when COOKIE is specified as one of the (or the only) tracking modes. Tags within it customize the session cookies that the container returns to the browser:
- The <name> tag enables you to customize the name of the session cookie. The default is JSESSIONID, and you will probably never need to change that.
- The <domain> and <path> tags correspond to the Domain and Path attributes of the cookie. The web container appropriately defaults these for you so that you should usually not need to customize them. The Domain defaults to the domain name used to make the request during which the session was created. The Path defaults to the deployed application context name.
- The <comment> tag adds a Comment attribute to the session ID cookie, providing the opportunity to add arbitrary text. This is often used to explain the purpose of the cookie and point users to the site’s privacy policy. Whether you use this is entirely up to you. If you omit this tag, the Comment attribute is not added to the cookie.
- The <http-only> and <secure> tags correspond to the HttpOnly and Secure cookie attributes, and both default to false. For increased security, you should always customize <http-only> to true <secure> should be changed to true only if you have HTTPS enabled.
- The final tag, <max-age>, specifies the Max-Age cookie attribute that controls when the cookie expires. By default, the cookie has no expiration date, which means it expires when the browser closes. Setting this to -1 has the same effect. Expiring the cookie when the browser closes is almost always what you want. You customize this value in seconds (unlike <session-timeout>, which is in minutes), but doing so could cause the cookie to expire and session tracking to fail while the user is in the middle of actively using your application. It’s best to leave this one alone and not use this tag.
As of Servlet 3.0/Java EE 6, you can skip the deployment descriptor and configure most of these options programmatically using the ServletContext. Use the setSessionTrackingModes method to specify a Set of one or more javax.servlet.SessionTrackingMode enum constants. getSessionCookieConfig returns a javax.servlet.SessionCookieConfig use this object to configure any of the <cookie-config> settings. You can configure the tracking modes or cookie configuration only within a ServletContextListener’s contextInitialized method or a ServletContainerInitializer’s onStartup method. Currently, you cannot configure the session timeout programmatically this oversight should be corrected in Java EE 8.
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<name>JSESSIONID</name>
<domain>example.org</domain>
<path>/shop</path>
<comment><![CDATA[Keeps you logged in. See our privacy policy for more information.]]></comment>
<http-only>true</http-only>
<secure>false</secure>
<max-age>1800</max-age>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
<tracking-mode>URL</tracking-mode>
<tracking-mode>SSL</tracking-mode>
</session-config>
All of the tags within <session-config> and <cookie-config> are optional, but they must appear in the order shown in this example (excluding omitted tags).
The <session-timeout> tag specifies how long sessions should remain inactive, in minutes, before being invalidated. If the value is 0 or less, the session never expires. If this tag is omitted, the container default applies. Tomcat’s default container is 30, which can be changed in the Tomcat configuration. If you want consistency, you should explicitly set the timeout using this tag. In this example the timeout is 30 minutes. Each time a user with a certain session ID makes a request to your application, the timer resets on his session’s inactivity. If he goes more than 30 minutes without making a request, his session is considered invalid and he is given a new session.
The <tracking-mode> tag, which was added in Servlet 3.0/Java EE 6, indicates which technique the container should use for tracking session IDs. The legal values are:
- URL : The container only embeds session IDs in URLs. It does not use cookies or SSL session IDs. This approach is not very secure.
- COOKIE : The container uses session cookies for tracking session IDs. This technique is very secure.
- SSL : The container uses SSL Session IDs as HTTP session IDs. This method is the most secure approach available but requires all requests to be HTTPS for it to work properly.
You may use <tracking-mode> more than once to tell the container it can use multiple strategies. For example, if you specify both COOKIE and URL, the container prefers cookies but uses URLs when cookies are not available. Specifying COOKIE as the only tracking mode tells the container to never embed sessions in URLs and always assume the user has cookies enabled. Likewise, specifying URL as the only tracking mode tells the container to never use cookies. If you enable the SSL tracking mode, you cannot also enable the COOKIE or URL modes. SSL Session IDs must be used on their own; the container cannot fall back to cookies or URLs in the absence of HTTPS.
The <cookie-config> tag applies only when COOKIE is specified as one of the (or the only) tracking modes. Tags within it customize the session cookies that the container returns to the browser:
- The <name> tag enables you to customize the name of the session cookie. The default is JSESSIONID, and you will probably never need to change that.
- The <domain> and <path> tags correspond to the Domain and Path attributes of the cookie. The web container appropriately defaults these for you so that you should usually not need to customize them. The Domain defaults to the domain name used to make the request during which the session was created. The Path defaults to the deployed application context name.
- The <comment> tag adds a Comment attribute to the session ID cookie, providing the opportunity to add arbitrary text. This is often used to explain the purpose of the cookie and point users to the site’s privacy policy. Whether you use this is entirely up to you. If you omit this tag, the Comment attribute is not added to the cookie.
- The <http-only> and <secure> tags correspond to the HttpOnly and Secure cookie attributes, and both default to false. For increased security, you should always customize <http-only> to true <secure> should be changed to true only if you have HTTPS enabled.
- The final tag, <max-age>, specifies the Max-Age cookie attribute that controls when the cookie expires. By default, the cookie has no expiration date, which means it expires when the browser closes. Setting this to -1 has the same effect. Expiring the cookie when the browser closes is almost always what you want. You customize this value in seconds (unlike <session-timeout>, which is in minutes), but doing so could cause the cookie to expire and session tracking to fail while the user is in the middle of actively using your application. It’s best to leave this one alone and not use this tag.
As of Servlet 3.0/Java EE 6, you can skip the deployment descriptor and configure most of these options programmatically using the ServletContext. Use the setSessionTrackingModes method to specify a Set of one or more javax.servlet.SessionTrackingMode enum constants. getSessionCookieConfig returns a javax.servlet.SessionCookieConfig use this object to configure any of the <cookie-config> settings. You can configure the tracking modes or cookie configuration only within a ServletContextListener’s contextInitialized method or a ServletContainerInitializer’s onStartup method. Currently, you cannot configure the session timeout programmatically this oversight should be corrected in Java EE 8.
Subscribe to:
Comments (Atom)