Wednesday, December 31, 2014

Logback - SLF4J

Pom.xml file:

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${org.slf4j-version}</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>${logback-version}</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback-version}</version>
        </dependency>



In src/main/resources folder, create logback.xml file. Put these configuration:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration>
    <!-- File appender -->
     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>D:\mmt-ws-logs\mmt-ws-log.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
               <FileNamePattern>D:\mmt-ws-logs\mmt-ws-log.%d{yyyy-MM-dd}.log</FileNamePattern>
               <MaxHistory>30</MaxHistory>
          </rollingPolicy>
   
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{ISO8601} [%-5p] [%t] %c %X - %m%n</pattern>
        </encoder>
    </appender>
   
    <!-- Console appender -->
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <charset>UTF-8</charset>
            <pattern>%d{HH:mm:ss} %level [%thread] %logger [%file:%line] %msg%n</pattern>
        </encoder>
    </appender>

  <root level="INFO,ERROR">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>


In this case, we use RollingFileAppender to write log to file. It also recreate new file for new date.

For showing in Console, use ConsoleAppender.

Tuesday, December 30, 2014

Sequence in Oracle

Create Sequence

CREATE SEQUENCE customers_seq
 START WITH     1000
 INCREMENT BY   1
 NOCACHE
 NOCYCLE;
 
In case that we already have data in DB, use this snippet:

declare
    new_id number;
begin
   select NVL(max(id),0) + 1
   into   new_id
   from   my_table;

    execute immediate 'Create sequence my_seq
                       start with ' || new_id ||
                       ' increment by 1';
end;

/

Use Sequence

In Entity object:

    /** The auto id. */
    private Long autoId;

    /**
     * Gets the auto id.
     *
     * @return the auto id
     */
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sq")
    @SequenceGenerator(name = "sq", sequenceName = "my_seq", allocationSize=1)
    @Column(name = "AUTOID", unique = true, nullable = false, precision = 30, scale = 0)
    public Long getAutoId() {
        return this.autoId;
    }

    /**
     * Sets the auto id.
     *
     * @param autoId the new auto id
     */
    public void setAutoId(Long autoId) {
        this.autoId = autoId;
    }



GenerationType.SEQUENCE is specific for Oracle. Because Oracle uses Sequence strategy for create AutoId.

In @SequenceGenerator, the “allocationSize” is by default set to 50
And, by default, the “increment by” is set to 1.

Note:

It’s important to note that, the sequence generator work correctly, only when the “allocationSize” and the “increment by” are same, otherwise there is a possibility of getting the “unique constraint violation” exception. therefore, it is better to explicitly define “allocationSize” and “increment by”.

Monday, December 29, 2014

Get package version from MANIFEST file

In pom.xml, specify default ImplementationEntries and SpecificationEntries as below:
 

          <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                            <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                        </manifest>
                        <manifestEntries>
                            <Implementation-Version>${project.version}</Implementation-Version>
                        </manifestEntries>
                    </archive>
                    <archiveClasses>true</archiveClasses>
                </configuration>
            </plugin>


These fields will be automatically added to MANIFEST file.

In Java class, use this snippet to read value:
   @Override
    public BuildVersion getVersion() throws IOException {
        Package p = this.getClass().getPackage();
        BuildVersion buildVersion = new BuildVersion();
        buildVersion.setBuildName(p.getImplementationTitle());
        buildVersion.setVersion(p.getImplementationVersion());
        return buildVersion;       
    }


(BuildVersion is a custom class that contains result.)

Note: war file has to be put in server. At that time manifest file will be available to read properly.

Thursday, December 25, 2014

Useful SQL Hints to improve query performance

References:
http://ashokkumartj.blogspot.com/2011/01/useful-sql-hints-to-improve-query.html

Create Index and using Index hints

CREATE INDEX:

There are many types of index introduced by Oracle.
http://docs.oracle.com/cd/B19306_01/server.102/b14231/indexes.htm

Each type have the different way to create. Ex:

CREATE INDEX programId_index ON PROGRAM(programId) COMPUTE STATISTICS;

Put Index on columns that appear in WHERE statement.
Good for single column - one index.
Can put multi-columns in index but make sure that the all these columns appear in WHERE statement. If not, index does not help.

Ex: CREATE INDEX User_index ON PROGRAM(firstName, lastName, title) COMPUTE STATISTICS;

Great if: SELECT * from User WHERE firstName = ? AND lastName = ?

Bad if: SELECT * from User WHERE lastName = ?
       or SELECT * from User WHERE lastName = ? AND title = ?

Index will make DML (insert, update, delete) slow down (3-time slower than the table with no indexes). Should not index on column that value is too much duplicated.

INDEX HINTS:

Use Hints indicate Oracle using index:

SELECT /*+ index(table_name(column_has_indexed)) */  * FROM customer;

Oracle Semi-Joins and Anti-Joins

Using EXISTS and IN.
 
Example 1:
 
SELECT   D.deptno, D.dname
        FROM     dept D, emp E
        WHERE    E.deptno = D.deptno
        ORDER BY D.deptno;
 
Change to:
 
SELECT   D.deptno, D.dname
        FROM     dept D
        WHERE    EXISTS
                 (
                 SELECT 1
                 FROM   emp E
                 WHERE  E.deptno = D.deptno
                 )
        ORDER BY D.deptno; 

Example 2:

SELECT   D1.deptno, D1.dname
        FROM     dept D1
        MINUS
        SELECT   D2.deptno, D2.dname
        FROM     dept D2, emp E2
        WHERE    D2.deptno = E2.deptno
        ORDER BY 1;
 
Change to: 

SELECT   D.deptno, D.dname
        FROM     dept D
        WHERE    NOT EXISTS
                 (
                 SELECT 1
                 FROM   emp E
                 WHERE  E.deptno = D.deptno
                 )
        ORDER BY D.deptno;
 
References:
 
http://www.dbspecialists.com/files/presentations/semijoins.html 

Sunday, December 14, 2014

RestTemplate cannot map a single object to a list



ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
resObject = mapper.readValue(response.getBody(), ResponseObject.class);

The problem is that if ResponseObject in server side has only one item set to a list, by default, JAXB will convert this list to a single json object (not an array contains one object as we expected) so the mapper in client side cannot map correctly.

Solution 1: by code


List converters = restTemplate.getMessageConverters();
              for (Object converter : converters) {
                     if (converter instanceof MappingJacksonHttpMessageConverter) {
                           MappingJacksonHttpMessageConverter jconverter = (MappingJacksonHttpMessageConverter) converter;
                           
                           final ObjectMapper mapper = new ObjectMapper();
                             mapper.configure(
                                     DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY,
                                     true);
                           jconverter.setObjectMapper(mapper);
                          
                     }
              }

Solution 2: by XML configuration:


<!-- Jackson Mapper -->
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="jacksonObjectMapper" />
    <property name="targetMethod" value="configure" />
    <property name="arguments">
        <list>
            <value type="org.codehaus.jackson.map.DeserializationConfig.Feature">FAIL_ON_UNKNOWN_PROPERTIES</value>
            <value>false</value>
        </list>
    </property>
</bean>
 
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper" ref="jacksonObjectMapper" />
            </bean>
        </list>
    </property>
</bean>

Hope that helps.

References:
http://stackoverflow.com/questions/14343477/how-do-you-globally-set-jackson-to-ignore-unknown-properties-within-spring
  

 

Friday, December 12, 2014

Jersey Test

pom.xml

<!-- Jersey -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-servlet</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-json</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <dependency>
            <groupId>com.sun.jersey.jersey-test-framework</groupId>
            <artifactId>jersey-test-framework-grizzly2</artifactId>
            <version>1.8</version>
            <scope>test</scope>
        </dependency>

Test class:

public class MyClassTest extends JerseyTest {
   
    @Override
    public AppDescriptor configure() {
        return new WebAppDescriptor.Builder("com.example.person.endpoint")
                                    .servletClass(SpringServlet.class)
                                    .contextParam("contextConfigLocation", "classpath:context/endpointIntegrationContext.xml")
                                    .contextListenerClass(ContextLoaderListener.class)
                                    .contextPath("test-project").build();
    }

    @Before
    public void setUp() {
        mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
    }

    @After
    public void tearDown() {
    }
   
    @Test
    public void testGetByUserId() throws Exception {
        RestTemplate restTemplate = new RestTemplate();
       
        Long userId = 1L;
       
        String endpoint = getBaseURI() + "test-project/person/getByUserId/{userId}";
        final Map<String, Object> urlParameter = new HashMap<String, Object>();
        urlParameter.put("userId", userId);

        HttpHeaders headers = new HttpHeaders();
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> entity = new HttpEntity<String>(headers);
       
        ResponseEntity<String> responseEntity = restTemplate.exchange(endpoint, HttpMethod.GET, entity, String.class, urlParameter);
       responseEntity.getBody()
        //...
    }

Thursday, December 11, 2014

Using Spring Data JPA

Spring Data JPA is a library / framework that adds an extra layer of abstraction on the top of our JPA provider.
DAO Structure
Using JpaRepository and Entity Manager persistence

Configuration:
 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd

        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        ">

    <!-- Enables the Spring MVC @Controller programming model -->
    <mvc:annotation-driven />
   
    <jpa:repositories base-package="com.journaldev.spring.repository"/>

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving
        up static resources in the ${webappRoot}/resources directory -->
    <mvc:resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources
        in the /WEB-INF/views directory -->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="jdbc:mysql://localhost:3306/spring-data-jpa" />
        <property name="username" value="root" />
        <property name="password" value="root" />
    </bean>
   
    <bean id="jpaVendorAdapter"
        class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="true"/>
        <property name="generateDdl" value="true"/>
        <property name="database" value="MYSQL"/>
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
        <!-- spring based scanning for entity classes-->
        <property name="packagesToScan" value="com.journaldev.spring.model"/>
    </bean>

    <bean id="personDAO" class="com.journaldev.spring.dao.PersonDAOImpl">
        <property name="em" ref="entityManagerFactory" />
    </bean>
    <bean id="personService" class="com.journaldev.spring.service.PersonServiceImpl">
        <property name="personDAO" ref="personDAO"></property>
    </bean>
   
    <context:component-scan base-package="com.journaldev.spring" />
   
    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>



Usage:

import org.springframework.data.jpa.repository.JpaRepository;
import com.journaldev.spring.model.Person;
public interface PersonRepository extends JpaRepository<Person, Integer> {

}


Add to where to use:
@Autowired
private PersonRepository personRepository;

To add function to JpaRepository, we have 3 ways:
* Declare method name by combine keyword and fieldName
public List<Person> findByLastName(String lastName);

* Using NamedQuery

@Entity
@NamedQuery(name = "Person.findByName", query = "SELECT p FROM Person p WHERE LOWER(p.lastName) = LOWER(?1)")
@Table(name = "persons")
public class Person {
     
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
Then add method which name match namedQuery name:
public List<Person> findByName(String lastName);
* Using @Query at method definition

@Query("SELECT p FROM Person p WHERE LOWER(p.lastName) = LOWER(:lastName)")
    public List<Person> find(@Param("lastName") String lastName);

Entity Manager

 @PersistenceContext
    private EntityManager em;

 
 @Override
    public List<Person> findByCountry(String country) {
        List<Person> results = em.createNamedQuery("findByCountry").setParameter(1, country).getResultList();
        return results;
    }


EntityManager allow to run native Sql by em.createNativeQuery(String sqlString).

References:
http://www.petrikainulainen.net/spring-data-jpa-tutorial/