Showing posts with label J2EE. Show all posts
Showing posts with label J2EE. Show all posts

Java Config: Integrating JAX-RS Jersey with Spring Security


The Scenario
When we were developing the admin backend, we split it into 2 projects: backend application using jax-rs jersey, front end with angularjs - following single app design principle.

Later we decide to merge these 2 into one project, and use Spring security to protect front side(web url, page section etc) and jersey jax-rs.

We prefer Spring Java config over xml because it's more flexible, and XML configuration is kind of black box to developers,  using Java config, we can know more about the implementation and help us debug it later.

Update:
Later we upgrade to jersey 2:

@Priority(value = 1)
public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] {MyAppConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }

    @Override
    public void onStartup(final ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        // this is to fix issues in jersey-srping3
        // org.glassfish.jersey.server.spring.SpringWebApplicationInitializer
        servletContext.setInitParameter("contextConfigLocation", "");
        servletContext.addListener(RequestContextListener.class);
        MyUtil.addDefaultUncaughtExceptionHandler();
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        final WebApplicationContext context = super.createRootApplicationContext();
        final ConfigurableEnvironment env = (ConfigurableEnvironment) context.getEnvironment();
        final String profile = (String) env.getSystemProperties().get("env");
        env.setActiveProfiles(profile);
        return context;
    }
}

public class MySecurityInitializer extends AbstractSecurityWebApplicationInitializer {}

@WebServlet(loadOnStartup = 1)
@ApplicationPath("/v1/*")
public class MyJerseyApplication extends ResourceConfig {
    public JerseyRestProvisionApplication() {
        packages("the_package_xx");
        property(ServerProperties.WADL_FEATURE_DISABLE, true);
        register(JacksonFeature.class);
        register(GZipEncoder.class);
        register(MultiPartFeature.class);

        register(new LoggingFilter(Logger.getLogger(MyJerseyApplication.class.getName()), true));
        register(RequestContextFilter.class);
        register(MyHttpHeaderFilter.class);
    }
}
How To
Basically we configure two servlets:

  • web.servlet.DispatcherServlet: map it to / (notice not /*). This handles Spring Security and Spring MVC.
  • Jersey SpringServlet: map to v1(all rest API starts with v1/).

Spring security is used to do authentication and authorization.

Jersery 1

public class AppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(final ServletContext servletContext) {
        final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(AppConfig.class);

        final ConfigurableEnvironment env = rootContext.getEnvironment();

        final String profile = (String) env.getSystemProperties().get("env");
        env.setActiveProfiles(profile);

        servletContext.addListener(new ContextLoaderListener(rootContext));

        addSpringServlet(servletContext, profile);
        addSpringJersyServlet(servletContext, env);
    }

    protected void addSpringServlet(final ServletContext servletContext, final String profile) {

        final DispatcherServlet dispatcherServlet = new DispatcherServlet(new GenericWebApplicationContext());

        final Dynamic dispatcherDynamic = servletContext.addServlet("dispatcherServlet", dispatcherServlet);;
        dispatcherDynamic.setLoadOnStartup(1);

        dispatcherDynamic.addMapping("/");

        servletContext
                .addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class)
                .addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
    }

    protected void addSpringJersyServlet(final ServletContext servletContext, final ConfigurableEnvironment env) {
        final ServletRegistration.Dynamic appServlet = servletContext.addServlet("jersey-servlet", new SpringServlet());

        appServlet.setInitParameter(JSONConfiguration.FEATURE_POJO_MAPPING, "true");
        appServlet.setInitParameter(ResourceConfig.FEATURE_TRACE, env.getProperty("jersey.enable.trace", "false"));
        appServlet.setInitParameter(ResourceConfig.FEATURE_DISABLE_WADL,
                env.getProperty("jersey.disable.wadl", "true"));

        appServlet.setInitParameter(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS,..);
        appServlet.setInitParameter(ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS, ..);

        appServlet.setLoadOnStartup(2);
        appServlet.addMapping("/v1/*");
    }
}
Resources
Difference between / and /* in servlet mapping url pattern
http://javapapers.com/servlet/what-is-servlet-mapping/

JBoss Tips


Commands
shutdown.sh -S
run.sh -b 0.0.0.0 -c default
run.bat –Djboss.server.log.dir=d:/log
Change ports
In jboss 5, in $JBoss\server\default\conf\bindingservice.beans\META-INF\bindings-jboss-beans.xml, change the port offset of PortsDefaultBindings.
<bean name="PortsDefaultBindings"  class="org.jboss.services.binding.impl.ServiceBindingSet">
  <constructor>
     <!-- The port offset -->
     <parameter>1000</parameter>
     <!-- Set of bindings to which the "offset by X" approach can't be applied -->
     <parameter><null/></parameter>
  </constructor>
</bean>
To use the port assignments defined by the Ports01Bindings bean, set the jboss.service.binding.set system property to ports-01 when starting the application server.
run -c myconfig2 -Djboss.service.binding.set=ports-01
Configuring logging

The log4j configuration file is located at server/xxx/conf/jboss-log4j.xml.
Defining a rolling log appender
<appender name="FILE">
    <param name="Append" value="true"/>
    <param name="MaxFileSize" value="10MB"/>
    <param name="MaxBackupIndex" value="20"/>
    <param name="Threshold" value="ERROR"/>
</appender>
Defining logging for your application
You can log your application by adding category entries to the jboss-log4j.xml file.
<appender name="JBIA" ...>
    <param name="File" value="${jboss.server.log.dir}/jbia.log"/>
</appender>
<category name="org.jbia">
    <priority value="DEBUG"/>
    <appender-ref ref="JBIA" />
</category>

Edit the server.xml file. For the default server in the default location, it is ${jboss.home}\server\default\deploy\jbossweb.sar\server.xml.
Uncomment the "Access logger" section. The log file will show up in server/default/log/localhost_access_log.{todays_date}.log

<Valve className="org.apache.catalina.valves.AccessLogValve"
                prefix="localhost_access_log." suffix=".log"
                pattern="common" directory="${jboss.server.log.dir}" 
                resolveHosts="false" />


Configuring startup parameters
Rename run.bat for example to run-old.bat.
Create another run.bat file and put this line to it:
set JAVA_OPTS=%JAVA_OPTS% -Xms512m -Xmx1024m -XX:MaxPermSize=512m
run-old.bat -b 0.0.0.0 -c default
Dump SOAP Messages
For the case that is not easy to model as a simple DFS request, it is useful to enable the SOAP dump.
For client side, set "com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true";
For server side, set "com.sun.xml.ws.transport.http.HttpAdapter.dump=true";
In Jboass, put the following line in newly created run.bat:
set JAVA_OPTS=%JAVA_OPTS% -Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true
Enable remote debug
In newly created run.bat:
rem set JAVA_OPTS=%JAVA_OPTS% -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n
Configure apache httpd.conf:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
<Proxy balancer://mycluster>
Order deny,allow
Allow from all
BalancerMember http://node1.mycluster.lan:8080/ route=node1 timeout=15
BalancerMember http://node2.mycluster.lan:8080/ route=node2 timeout=15
ProxySet stickysession=JSESSIONID|jsessionid
# other values: bybusyness|byrequests|bytraffic
ProxySet lbmethod=bytraffic 
</Proxy>
ProxyPass /jmx-console balancer://mycluster/jmx-console 
ProxyPassReverse /jmx-console  http://localhost:9080/jmx-console stickysession=JSESSIONID|jsessionid



Configure JBoss
In jboss, modify {jboss.home}\server\default\deploy\jbossweb.sar\server.xml to configure the jvmRoute for sticky sessions:
<Engine name="jboss.web" defaultHost="localhost" jvmRoute="node1">

Modify {jboss.home}\server\default\deployers\jbossweb.deployer\META-INF\war-deployers-jboss-beans.xml:
<bean name="WebAppClusteringDefaultsDeploye" class="org.jboss.web.tomcat.service.deployers.ClusteringDefaultsDeployer">
  <property name="useJK">true</property>
</bean>

Resources:

Fail to start JBoss5 - Common unexpected


Unable to start JBoss 5 - \Common was unexpected at this time

--Don't use quotes in path variable

Today, I download JBoss 5 in my Windows 7 - 64 bit machine, and try to use run.bat to start the server, but it fails, and reports error:
\Common was unexpected at this time.

Google searched, but found nothing useful.
So I tried to take a look at the run.bat, first I comment the first row "@echo off", so I will now where it stops with the error above. I located the source of the errors:
if not "x%JBOSS_NATIVE_HOME%" == "x" (
  set "PATH=%JBOSS_NATIVE_HOME%;%PATH%;%JBOSS_HOME%\bin"
  set JAVA_OPTS=%JAVA_OPTS% "-Djava.library.path=%JBOSS_NATIVE_HOME%;%PATH%;%JBOSS_HOME%\bin"
)

Then I check the PATH environment:
%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;"C:\Program Files (x86)\Common Files\EMC";C:\Program Files\Perforce;%JAVA_HOME%\bin;%ANT_HOME%\bin;%MVN_HOME%\bin

Yeah, find out the culprit: the quotes around the path to EMC common files - "C:\Program Files (x86)\Common Files\EMC"
After removed the quotes, start a new command line, JBoss can be started with no problem.

Lesson learned: don't put quotes in your environment variables, such as PATH, JAVA_HOME etc, this may make scripts broken. This also applies when installation program update these variables.

EJB3 and JPA Basics



EJB3 and JPA Basics

Mapped Superclasses
A mapped superclass provides a convenient class on which to store shared state and behavior that entities can inherit from, but it is itself not a persistent class and cannot act in the capacity of an entity. It cannot be queried over and cannot be the target of a relationship. Annotations such as @Table are not permitted on mapped superclasses because the state defined in them applies only to its entity subclasses.
It is good practice to make mapped superclass as abstract Java classes.mapped superclasses do not get mapped to tables.
Entity Inheritance
The Java Persistence specification provides three different ways to map an inheritance hierarchy to a relational database:
A single table per class hierarchy
One table will have all properties of every class in the hierarchy.
A table per concrete class
Each class will have a table dedicated to it, with all of its properties and the properties of its superclass mapped to this table.
A table per subclass
Each class will have its own table. Each table will have only the properties that are defined in that particular class. These tables will not have properties of any superclass or subclass.
The root entity class defines the inheritance strategy with the @Inheritance annotation. Inheritance has only one property: InheritanceType strategy InheritanceType is an enum, which has value: SINGLE_TABLE, TABLE_PER_CLASS, JOINED. The default one is SINGLE_TABLE
Single-Table Strategy(A single table per class hierarchy)
This strategy maps all classes in the hierarchy to one table, which contains a superset of all the possible state in any of the entity classes.
@Entity
@Table(name="Employee")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="Employee_Type")
public abstract class Employee
@Entity
@DiscriminatorValue("Contract_Employee")
public class ContractEmployee
Discriminator Column and Discriminator Value
The table has to have one extra column to indicate the type.
Advantages

It offers peak performance for both polymorphic queries and write operations. The SQL that is needed to issue these operations is simple, optimized, and does not require joining.
Single table inheritance mapping is the fastest of all inheritance models, since it never requires a join to retrieve a persistent instance from the database. Similarly, persisting or updating a persistent instance requires only a single INSERT or UPDATE statement. Finally, relations to any class within a single table inheritance hierarchy are just as efficient as relations to a base class.
Disadvantages
Single-table approach tends to be more wasteful of database tablespace, as for every field in the entire inheritance hierarchy, a column must exist in the mapped table, as many columns may be empty.
Joined Strategy(A table per subclass)
The InheritanceType.JOINED strategy uses a different table for each class in the hierarchy. Each table only includes state declared in its class.
@Entity
@Table(name="Employee")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="Employee_Type")
public abstract class Employee
PrimaryKeyJoinColumn annotations tell the JPA implementation how to join each subclass table record to the corresponding record in its direct superclass table.
Advantages
The joined strategy has the following advantages:
Using joined subclass tables results in the most normalized database schema, meaning the schema with the least spurious or redundant data.
As more subclasses are added to the data model over time, the only schema modification that needs to be made is the addition of corresponding subclass tables in the database (rather than having to change the structure of existing tables).
Relations to a base class using this strategy can be loaded through standard joins and can use standard foreign keys, as opposed to the machinations required to load polymorphic relations to table-per-class base types, described below.
Disadvantages
Aside from certain uses of the table-per-class strategy described below, the joined strategy is often the slowest of the inheritance models. Retrieving any subclass requires one or more database joins, and storing subclasses requires multiple INSERT or UPDATE statements.
Table-per-Concrete-Class Strategy(A table per concrete class)
Like the JOINED strategy, the InheritanceType.TABLE_PER_CLASS strategy uses a different table for each concrete class in the hierarchy. Unlike the JOINED strategy, however, each table includes all state for an instance of the corresponding class. Thus to load a subclass instance, the JPA implementation must only read from the subclass table; it does not need to join to superclass tables.
Advantages
The table-per-class strategy is very efficient when operating on instances of a single concrete class. As in this case, the strategy never requires joining to superclass or subclass tables. Reads, joins, inserts, updates, and deletes are all efficient in the absence of polymorphic behavior. Also, as in the joined strategy, adding additional classes to the hierarchy does not require modifying existing class tables.
Disadvantages
The negative side is that it makes polymorphic querying across a class hierarchy more expensive than the other strategies. The problem is that it must either issue multiple separate queries across each of the subclass tables, or query across all of them using a UNION operation. This is always expensive.
Fetch Type
FetchType.EAGER or FetchType.LAZY
Cascade Type
public enum CascadeType {ALL,PERSIST,MERGE,REMOVE,REFRESH,DETACH}
Directionality
Unidirectional or bidirectional
Entitys Relationships
Many-to-one, One-to-one, One-to-many, Many-to-many
Persistence Context
A persistent context manages a set of managed entity object instances.
The entity manager tracks all entity objects within a persistence context for changes and updates made, and flushes these changes to the database.
As soon as an EntityManager object is created, it is implicitly associated with a persistence context for managing a set of entities.
Persistent Context comes in two flavors, one is the transaction-scoped persistent context and the other one is extended persistent context.
Transaction-Scoped Persistence Context
Life-time of transaction-scoped persistence context is dependent on the life-time of the transaction.
When the transaction completes, the transaction-scoped persistence context will be destroyed and all man-aged entity object instances will become detached.
Only persistence contexts managed by an application server may be transaction-scoped.
Extended Persistence Context
@PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
Extended persistence context lives even after a transaction completes.
Entity object instances that are attached to an extended context remain managed even after a transaction is complete.
An EntityManager using an extended persistence context maintains the same persistence context for its entire lifecycle.
It is often used in stateful session beans.
Detached entities
Entity instances become unmanaged and detached when a transaction scope or extended persistence context ends. An interesting side effect is that detached entities can be serialized and sent across the network to a remote client. The client can make changes remotely to these serialized object instances and send them back to the server to be merged back and synchronized with the database.
merge()
The Java Persistence specification allows you to merge state changes made to a detached entity back into persistence storage using the entity manager’s merge() method.
If the entity manager isn’t already managing an instance, a full copy of the parameter is made and returned from the merge() method. This copy is managed by the entity manager, but the instance you pass in will not be managed.
Any additional setter methods called on this copy will be synchronized with the database when the EntityManager decides to flush.
The original parameter remains detached and unmanaged.
Either way will add an entity to a PersistenceContext, the difference is in what you do with the entity afterwards.
Persist takes an entity instance, adds it to the context and makes that instance managed (ie future updates to the entity will be tracked)
Merge creates a new instance of your entity, copies the state from the supplied entity, and makes the new copy managed. The instance you pass in will not be managed (any changes you make will not be part of the transaction - unless you call merge again).
The Stateful Session Bean
Stateful session beans maintain conversational state,
The Singleton Session Bean
@javax.ejb.Singleton
@javax.ejb.Startup
public class MySingletonBean implements MySingletonLocalBusiness{..}
Container Managed Transactions (CMT)
In a CMT the container starts, commits and rolls back a transaction on our behalf, we however must tell the container how to manage the transaction by using either deployment descriptors or annotations and ask it to rollback the transaction when needed.
@TransactionManagement(TransactionManagementType.CONTAINER|BEAN)
@TransactionAttribute
TransactionAttributes
REQUIRED  means the method must always be invoked in a transaction, either creating a new one or joining an existing one, this creates a single umbrella transaction.
REQUIRES_NEW    means that the method will always create a new transaction, if the client already has a transaction; it is temporary suspended until our method returns. The success of the newly created transaction has no affect on an existing transaction.
SUPPORTS  will inherit whatever transactional environment of the caller is, if it does not have one then no transaction is used, if it joins an already existing transaction it will not cause it to suspend
MANDATORY    means that a transaction must already exist if one does not then an EJBTransactionRequiredException error is thrown.
NOT_SUPPORTED   means that the method will not run in an transaction, if one already exists then this is suspended until the method completes then resumes. this is useful for an MDB supporting a JMS provider in a non-transactional, autoknowledge mode.
NEVER means that it cannot be invoked by a transactional client, otherwise a EJBException is thrown.
Transaction Attribute   
Type               Caller Transaction Exists    Effect
REQUIRED          No    Container creates a new transaction
                     Yes   Method joins the callers transaction
REQUIRES_NEW    No    Container creates a new transaction
                     Yes   Container creates a new transaction and the callers transaction is suspended
SUPPORTS          No    No transaction is used
                     Yes    Method joins the callers transaction
MANDATORY        No   javax.ejb.EJBTransactionRequiredException is thrown
                     Yes  Method joins the callers transaction
NOT_SUPPORTED   No   No transaction is used
                     Yes  The callers transaction is suspended and the method is called without a transaction
NEVER             No   No transaction is used
                     Yes   javax.ejb.EJBException is thrown
Bean-Managed Transactions
BMT allows you to specify exactly where the transaction starts, ends, commits and rolls back, using the javax.transaction.UserTransaction interface.
@TransactionManagement(TransactionManagementType.BEAN)
@Resource private UserTransaction userTransaction;
userTransaction.begin;
userTransaction.commit();
userTransaction.setRollbackOnly();
@ApplicationException(rollback=false|true)[TODO]
Applied to an exception to denote that it is an application exception and should be reported to the client directly (i.e., unwrapped).
@ApplicationException(rollback=false)
public class DatabaseException extends RuntimeException
Isolation and Database Locking
Dirty, Repeatable, and Phantom Reads
Dirty reads
A dirty read occurs when a transaction reads uncommitted changes made by a previous transaction. If the first transaction is rolled back, the data read by the second transaction becomes invalid because the rollback undoes the changes. The second transaction will not be aware that the data it has read has become invalid.
Repeatable reads
A repeatable read occurs when the data read is guaranteed to look the same if read again during the same transaction. Repeatable reads are guaranteed in one of two ways: either the data read is locked against changes, or it is a snapshot that doesn’t reflect changes.
If the data is locked, it cannot be changed by any other transaction until the current transaction ends. If the data is a snapshot, other transactions can change the data, but these changes will not be seen by this transaction if the read is repeated.
A nonrepeatable read occurs when the data retrieved in a subsequent read within the same transaction can return different results.
When a transaction queries for the same data twice in the same transaction, the second query returns a different version of the data than was returned the first time because another transaction modified it in the intervening time.
In other words, the subsequent read can see the changes made by other transactions.
Phantom reads
A phantom read occurs when new records added to the database are detectable by transactions that started prior to the insert. Queries will include records added by other transactions after their transaction has started.
Database Locks
The most common locks are read locks, write locks, and exclusive write locks.
Read locks
Read locks prevent other transactions from changing data read during a transaction until the transaction ends, thus preventing non-repeatable reads. Other transactions can read the data but not write to it. The current transaction is also prohibited from making changes.
Write locks
Write locks are used for updates. A write lock prevents other transactions from changing the data until the current transaction is complete but allows dirty reads by other transactions and by the current transaction itself. In other words, the transaction can read its own uncommitted changes.
Exclusive write locks
Exclusive write locks are used for updates. An exclusive write lock prevents other transactions from reading or changing the data until the current transaction is complete. It also prevents dirty reads by other transactions. Some databases do not allow transactions to read their own data while it is exclusively locked.
Snapshots
A snapshot is a frozen view of the data that is taken when a transaction begins.
Some databases get around locking by providing every transaction with its own snapshot. Snapshots can prevent dirty reads, nonrepeatable reads, and phantom reads. They can be problematic because the data is not real-time data; it is old the instant the snapshot is taken.
Transaction Isolation Levels
Read Uncommitted
The transaction can read uncommitted data (i.e., data changed by a different transaction that is still in progress). Dirty reads, nonrepeatable reads, and phantom reads can occur
Read Committed
The transaction cannot read uncommitted data; data that is being changed by a different transaction cannot be read. Dirty reads are prevented; nonrepeatable reads and phantom reads can occur.
Repeatable Read
The transaction cannot change data that is being read by a different transaction.
Dirty reads and non-repeatable reads are prevented; phantom reads can occur.
Serializable
The transaction has exclusive read and update privileges; different transactions can neither read nor write to the same data. Dirty reads, nonrepeatable reads, and phantom reads are prevented.
Optimistic Locking
Using optimistic locking, we assume there is a good chance that current transaction will be the only one that actually changes the entity during that interval.
So we don't acquire a lock on the entity until the change is actually made to the database, usually at the end of the transaction.
At transaction commit time, we let the database resolve whether the data has been altered by another transaction. If it has, we throw an exception and roll back our transaction. In other words, we are being optimistic that the data hasn’t been touched until we need to commit.
Versioning
To determine whether others have changed same data in the intervening time since the committing transaction read the entity, the provider maintains a versioning system for the entity, defines a version column to track the version of a row.
@Version private Long version;
A @Version property is a column that will hold a version ID of a particular row.
Whenever the entity class is updated, the version column is incremented automatically by JPA. When a transaction beginning the commit process and business logic has updated the entity, the entity manager first checks to see whether the version property of the in-memory entity instance matches the version column currently stored in the database. If the versions match, then the version property is incremented. If they don’t match, then the entity manager throws an exception(OptimisticLockException) and rolls back the whole transaction.
Advanced Optimistic Locking Modes
Optimistic Read Locking(LockModeType.OPTIMISTIC)
An optimistic read lock in JPA provides Repeatable Read.
The resulting lock will guarantee that both the transaction that obtains the entity read lock and any other that tries to change that entity instance will not both succeed.
Optimistic Write Locking(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
The write lock guarantees all that the optimistic read lock does, but also pledges to increment the version field in the transaction regardless of whether a user updated the entity or not. This provides a promise of an optimistic lock failure if another transaction also tries to modify the same entity before this one commits.
When not use optimistic lock?
The optimistic locking design pattern does not work all the time.
If you have a row in your database that has a high concurrent write contention, then it is probably less efficient to use the optimistic locking pattern because it will create a lot of rollbacks, which create a lot of overhead in your system.
Pessimistic Locking
Pessimistic locking implies obtaining a lock on one or more objects immediately.
It guarantees locked object will not be modified by another transaction until after the current transaction completes and releases its lock.
Disadvantages
This limits the scalability and concurrency of applications because needless locking serializes many operations that could easily occur in parallel.
Pessimistic Locking Modes
By far the most common is pessimistic write locking.
Pessimistic Write Locking(LockModeType.PESSIMISTIC_WRITE)
This mode will be translated by most providers into a SQL "SELECT FOR UPDATE" statement in the database, obtaining a write lock on the entity so no other applications can modify it.
Pessimistic Read Locking(LockModeType.PESSIMISTIC_READ)
A PESSIMISTIC_READ mode can be used to pessimistically achieve repeatable read semantics when no writes to the entity are expected.
Pessimistic Forced Increment Locking
(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
This mode will also increment the version field of the locked entity regardless of whether changes were made to it.

@Basic
The @Basic annotation is the simplest form of mapping for a persistent property. This is the default mapping type for properties that are primitives, primitive wrapper types.
Lazy Loading
We declare fetch attribute to lazy on mapping relationship, such as @Basic, @OneToMany, @ManyToOne, @OneToOne, and @ManyToMany.
If the fetch() attribute is LAZY, that particular property will not be initialized
until you actually access this field.
Open Session in View
The problem
If your view (jsp) need access object's property that is lazy loaded, you will get exception:
LazyInitializationException: Session has been closed.
This is because the session has already been closed.
Using an interceptor|Filter to implement
sf.getCurrentSession().beginTransaction();
chain.doFilter(request, response);
sf.getCurrentSession().getTransaction().commit();
Solution for Hibernate
Spring provides OpenSessionInViewFilter.
Solution for JPA
In JPA, we can use extended entityManager(extended persistence context), or Spring's OpenEntityManagerInviewFilter.

Resources

Spring Basics


Spring Basics

Bean lifecycle methods

There are three options for controlling bean lifecycle behavior: custom init() and destroy() methods; the @PostConstruct and @PreDestroy annotations and the

InitializingBean and DisposableBean callback interfaces.

Explain Bean lifecycle in Spring framework

The spring container finds the beans definition from the XML file and instantiates the bean.

Using the dependency injection, spring populates all of the properties as specified in the bean definition.

If the bean implements the BeanNameAware interface, the factory calls setBeanName() passing the bean's ID.

If the bean implements the BeanFactoryAware interface, the factory calls setBeanFactory(), passing an instance of itself.

If there are any BeanPostProcessors associated with the bean, their post- ProcessBeforeInitialization() methods will be called.

If an init-method is specified for the bean, it will be called.

Finally, if there are any BeanPostProcessors associated with the bean, their postProcessAfterInitialization() methods will be called.

What are different types of Autowire types?

byName,byType,constructor,autodetect

AutowireCapableBeanFactory{AUTOWIRE_NO, AUTOWIRE_BY_NAME, AUTOWIRE_BY_TYPE, AUTOWIRE_CONSTRUCTOR, AUTOWIRE_AUTODETECT(@Deprecated)}

What are the different advice types in spring?

Around: Intercepts the calls to the target method

Before: This is called before the target method is invoked

After: This is called after the target method is returned

Throws: This is called when the target method throws and exception


Transaction

Defined in TransactionDefinition:

IsolationLevel

ISOLATION_DEFAULT

ISOLATION_READ_UNCOMMITTED

ISOLATION_READ_COMMITTED

ISOLATION_REPEATABLE_READ

ISOLATION_SERIALIZABLE

Propagation behavior(7 types)

PROPAGATION_REQUIRED

PROPAGATION_SUPPORTS

PROPAGATION_MANDATORY

Support a current transaction; throw an exception if no current transaction exists.

PROPAGATION_REQUIRES_NEW

Create a new transaction, suspending the current transaction if one exists

PROPAGATION_NOT_SUPPORTED

Do not support a current transaction; rather always execute non-transactionally.

PROPAGATION_NEVER

Do not support a current transaction; throw an exception if a current transaction exists.

PROPAGATION_NESTED = 6

Execute within a nested transaction if a current transaction exists, behave like {@link #PROPAGATION_REQUIRED} else.

isReadOnly

Declaratively rolling back a transaction

The recommended way to to roll back a transaction is to throw an Exception.

Be default, Any RuntimeException(unchecked exception) triggers rollback, and any checked Exception does not.

You can configure exactly which Exception types mark a transaction for rollback, including checked exceptions.

Programmatically rolling back a transaction

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

Default settings

• Propagation setting is REQUIRED.

• Isolation level is DEFAULT.

• Transaction is read/write.

• Any RuntimeException triggers rollback, and any checked Exception does not.

Spring Transaction Example

First configure dataSource and transactionManager in Spring configuration file.

Declarative Transaction through XML

This is the most common as it is non-intrusive, and has the least impact on application code.

expression="execution(* com.mydomain.spring.transaction.declarative.xml.XmlTransactionTestService.*(..))" />

The definition ensures that the transactional advice defined by the txAdvice bean executes at the appropriate points in the program.

Declarative via Annotations

Configure the transaction attributes via annotations in the Java source file.

@Transactional(propagation, isolation, timeout, readOnly, rollbackFor, noRollbackFor)

Programmatic - TransactionTemplate

final TransactionTemplate tt = new TransactionTemplate(transactionManager);

tt.setReadOnly(true);

tt.execute(new TransactionCallbackWithoutResult() {

public void doInTransactionWithoutResult(TransactionStatus status) {

// do stuff

status.setRollbackOnly();

}

});

Spring Event Framework

ApplicationEvent, ApplicationListener, ApplicationEventPublisher.publishEvent(event)

If a Spring bean implements the ApplicationListener, every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified. This is the standard Observer design pattern, we can use it in our Spring-enabled project.

public class EmailService implements ApplicationEventPublisherAware

ApplicationEventPublisher.publishEvent(event);

Hidden features of Spring framework

StringUtilsremoveDuplicateStrings, hasText, capitalize, uncapitalize, getFilenameExtension, stripFilenameExtension

FileCopyUtils.copy

Resources

Spring Transactions - Sample Applications

spring-framework-reference-3.0.pdf

Using DWR and amCharts to Generate Chart



Using DWR and amCharts to Generate Chart

This article would introduce how to use DWR and amCharts to generate java script charts.

We will develop a demo application to display a histogram to show how many users are registered in this week.

Server side implementation
1.       Download DWR and copy the jar to lib directory.
2.       Export business service using DWR annotations
At server side, we use DWR annotations to export business service so that they can be remote-called by javascript.


package org.codeexample.amChart;
@RemoteProxy
public class ReportServieImpl {
    @RemoteMethod
    public static Map getWeeklyNewUsers(Date date) { Calendar weekStartCalendar = Calendar.getInstance();
    weekStartCalendar.setTime(getWeekStartDay(date));
    LinkedHashMap dateUsers = new LinkedHashMap();
    for (int i = 0; i < 7; i++) {
        dateUsers.put(weekStartCalendar.getTime(), random(100, 1000));
        System.err.println(weekStartCalendar.getTime() + ":"
           + dateUsers.get(weekStartCalendar.getTime()));
        weekStartCalendar.add(Calendar.DAY_OF_YEAR, 1);
    }
    return dateUsers;
    }
    private static Date getWeekStartDay(Date date) {
    Calendar weekStartCalendar = Calendar.getInstance();
    weekStartCalendar.setTime(date);
    int day_of_week = weekStartCalendar.get(Calendar.DAY_OF_WEEK);
    weekStartCalendar.add(Calendar.DAY_OF_YEAR, Calendar.MONDAY
       - day_of_week);
    weekStartCalendar.set(Calendar.HOUR, 0);
    weekStartCalendar.set(Calendar.MINUTE, 0);
    weekStartCalendar.set(Calendar.SECOND, 0);

    return weekStartCalendar.getTime();
    }
    private static int random(int start, int range) {
    Random random = new Random();
    double result = start + range * random.nextDouble();
    return (int) result;
    }
}
3.       Add the DWR servlet definition and mapping to web.xml
 <!DOCTYPE web-app PUBLIC  
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
  "http://java.sun.com/dtd/web-app_2_3.dtd" >  
 <web-app>  
  <display-name>amCharts Demo Application</display-name>  
      <servlet>  
       <description>DWR controller servlet</description>  
       <servlet-name>dwr-invoker</servlet-name>  
       <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>  
       <init-param>  
        <param-name>classes</param-name>  
        <param-value>  
         org.codeexample.amChart.ReportServieImpl  
        </param-value>  
        </init-param>  
           <init-param>  
             <param-name>debug</param-name>  
             <param-value>true</param-value>  
           </init-param>   
      </servlet>  
      <servlet-mapping>  
       <servlet-name>dwr-invoker</servlet-name>  
       <url-pattern>/dwr/*</url-pattern>  
      </servlet-mapping>  
 </web-app>  
Client side implementation
1. Download amCharts from http://www.amcharts.com/
2. Unzip it and copy files under amcharts directory to web application root directory.
 <html>  
 <head>  
  <title>New Users Chart in This week</title>  
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  <script type="text/javascript"  
   src="dwr/interface/ReportServieImpl.js"> </script>   
  <script type='text/javascript' src='dwr/engine.js'> </script>  
  <script type='text/javascript' src='dwr/util.js'> </script>  
  <script src="amcharts/javascript/amcharts.js" type="text/javascript"></script>  
  <script src="amcharts/javascript/raphael.js" type="text/javascript"></script>   
  <script language="JavaScript">  
  function loadReport()  
  {  
   var now = new Date();  
   ReportServieImpl.getWeeklyNewUsers(now, {  
       callback:function(str) {   
       var chartData = [];  
       for (var key in str) {  
    var entry = {};  
    var date = new Date(key);  
    entry["date"] = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();  
    entry["number"] = str[key];  
    chartData.push(entry);  
    }        
   var chart = new AmCharts.AmSerialChart();  
        chart.pathToImages = "amcharts/javascript/images/";  
   chart.dataProvider = chartData;  
      chart.marginTop = 15;  
      chart.marginRight = 20;  
      chart.categoryField = "date";  
      chart.angle = 30;  
      chart.depth3D = 30;  
      var legend = new AmCharts.AmLegend();  
      chart.addLegend(legend);  
      var graph1 = new AmCharts.AmGraph();  
      graph1.title = "Register User";  
      graph1.valueField = "number";  
      graph1.type = "column";  
      graph1.lineAlpha = 0;  
      graph1.fillAlphas = 1;  
      chart.addGraph(graph1);     
   chart.write("chartdiv");  
       }  
      });  
  }  
  loadReport();  
  </script>  
 </head>   
 <body>  
 <h2>New Users Chart in this Week</h2>  
 <div id="chartdiv" style="width:800px; height:600px;"></div>  
 <button onClick="loadReport();">Reload</button>  
 </body>  

Labels

ANT (6) Algorithm (69) Algorithm Series (35) Android (7) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) JSON (7) Java (186) JavaScript (27) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) adsense (5) bat (8) regex (5) xml (5)