Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

7/20/2015

Ehcache Tutorial: Dynamically configuration and Cache Abstraction(Since Spring 3.1)

There are basically two ways to config Ehcache in java project.

1. Dynamically configuration
2. Through XML

Before getting started, we need to add the dependency of Ehcache. For example, if use maven, add below dependency into pom.xml:

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.0</version>
</dependency>

1. Dynamically configuration

More flexible than XML configuration. But instead, you need to write and manage more code.

Cache Initialization:

public abstract class CommonDao{

    @Value("${cache.enable:true}")
    protected boolean cacheEnable;

    @Value("${cache.timetolive:21600}")
    private int cacheTimeToLive;
    
    @Value("${cache.timetoidle:21600}")
    private int cacheTimeToIdle;
    
    protected CacheManager cacheManager;
    
    protected static final String userCacheName = "userCache";
    protected static final String orgCacheName = "orgCache";

    @PostConstruct
    void initCache(){
        Configuration config = new Configuration();
        CacheConfiguration defaultCacheConfiguration = new CacheConfiguration();
        defaultCacheConfiguration.setEternal(false);
        defaultCacheConfiguration.setTimeToIdleSeconds(cacheTimeToIdle);
        defaultCacheConfiguration.setTimeToLiveSeconds(cacheTimeToLive);
        config.addDefaultCache(defaultCacheConfiguration);
        cacheManager = CacheManager.create(config);
        cacheManager.addCacheIfAbsent(userCacheName);
        cacheManager.addCacheIfAbsent(orgCacheName);
    }
    
    protected void putCacheElement(String cacheName, String key, Object value){
        
        Cache cache = null;
        if(BooleanUtils.isTrue(cacheEnable)){
            cache = cacheManager.getCache(cacheName);
            if(cache != null){
                cache.put(new Element(key, value));
            }
        }
    }
    
    protected void putCacheElement(Cache cache, String key, Object value){
        
        if(BooleanUtils.isTrue(cacheEnable)){
            if(cache != null){
                cache.put(new Element(key, value));
            }
        }
    }
    
    protected Object getCacheElement(String cacheName, String key){
        
        Cache cache = null;
        if(BooleanUtils.isTrue(cacheEnable)){
            cache = cacheManager.getCache(cacheName);
            if(cache != null){
                Element element = cache.get(key);
                return element == null ? null : element.getObjectValue();
            }
        }
        return null;
    }
    
    protected Object getCacheElement(Cache cache, String key){
        
        if(BooleanUtils.isTrue(cacheEnable)){
            if(cache != null){
                Element element = cache.get(key);
                return element == null ? null : element.getObjectValue();
            }
        }
        return null;
    }
    
    protected void removeCacheElement(String cacheName, String key){
        
        Cache cache = null;
        if(BooleanUtils.isTrue(cacheEnable)){
            cache = cacheManager.getCache(cacheName);
            if(cache != null){
                cache.remove(key);
            }
        }
    }
    
    protected void removeCacheElement(Cache cache, String key){
        
        if(BooleanUtils.isTrue(cacheEnable)){
            if(cache != null){
                cache.remove(key);
            }
        }
    }
    
    protected CacheManager getCacheManager(){
        return cacheManager;
    }
}

Dynamically update:

If in the system, you have the requirement to run time update the caching configuration:

Cache cache = dao.getCacheManager().getCache("userCache"); 
CacheConfiguration config = cache.getCacheConfiguration(); 
config.setTimeToIdleSeconds(60); 
config.setTimeToLiveSeconds(120); 
config.setmaxEntriesLocalHeap(10000); 
config.setmaxEntriesLocalDisk(1000000);

Reference:
http://ehcache.org/generated/2.10.0/html/ehc-all/index.html#page/Ehcache_Documentation_Set/co-cfgbasics_dynamically_changing_cache_config.html#wwconnect_header

2. XML Configuration

a.  Config the ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect">
    <defaultCache
        eternal="false"
        maxElementsInMemory="1000"
        overflowToDisk="false"
        diskPersistent="false"
        timeToIdleSeconds="3600"
        timeToLiveSeconds="3600"
        memoryStoreEvictionPolicy="LRU" />
    <cache
        name="userCache"
        eternal="false"
        maxElementsInMemory="200"
        overflowToDisk="false"
        diskPersistent="false"
        timeToIdleSeconds="3600"
        timeToLiveSeconds="3600"
        memoryStoreEvictionPolicy="LRU" />
    <cache
        name="orgCache"
        eternal="false"
        maxElementsInMemory="200"
        overflowToDisk="false"
        diskPersistent="false"
        timeToIdleSeconds="3600"
        timeToLiveSeconds="3600"
        memoryStoreEvictionPolicy="LRU" />
</ehcache>

In above example, we configured two cache named "userCache" and "orgCache".
The file can be put in classpath or any location.


Tip:

If the system is developed using Spring, there is another way to configure the cache, which is more preferable. Example below.


b. Create spring context file for Ehcache and added it into spring context.

<?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:cache="http://www.springframework.org/schema/cache"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">

    <cache:annotation-driven cache-manager="cacheManager" />

    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache" />

    <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="classpath:ehcache.xml" />
        
    <bean id="realCacheManager" factory-bean="cacheManager" factory-method="getCacheManager" />
    
    <!-- If cache is not configured in ehcache.xml, can also be created here -->
    <bean id="userCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="realCacheManager" />
        <property name="eternal" value="false" />
        <property name="maxElementsInMemory" value="${user_cache_max_elements_in_memory}" />
        <property name="overflowToDisk" value="false" />
        <property name="diskPersistent" value="false" />
        <property name="timeToIdle" value="${user_cache_time_to_idle}" />
        <property name="timeToLive" value="${user_cache_time_to_live}" />
        <property name="memoryStoreEvictionPolicy" value="LRU" />
    </bean>

    <bean id="orgCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="realCacheManager" />
        <property name="eternal" value="false" />
        <property name="maxElementsInMemory" value="${org_cache_max_elements_in_memory}" />
        <property name="overflowToDisk" value="false" />
        <property name="diskPersistent" value="false" />
        <property name="timeToIdle" value="${org_cache_time_to_idle}" />
        <property name="timeToLive" value="${org_cache_time_to_live}" />
        <property name="memoryStoreEvictionPolicy" value="LRU" />
    </bean>
</beans>

Reference:
http://ehcache.org/generated/2.10.0/html/ehc-all/#page/Ehcache_Documentation_Set%2Fco-cfgbasics_xml_configuration.html%23

c. Cache Abstraction (Since Spring 3.1)

Since 3.1, Spring added support for transparently adding caching into an existing Spring application. 
Similar to other feature in Spring, it supports annotation-based and xml-based configuration. Here we just include example for annotation-based configuration.

@Repository
public interface UserDao extends CrudRepository<User, String> {

    @Cacheable(value="userCache", key="#p0", unless="#result == null")
    Channel findByUserName(String userName);
}
@Repository
public interface OrganizationDao extends CrudRepository<Organization, String> {

    @Cacheable(value="orgCache", key="#p0", unless="#result == null")
    Organization findByName(String name);

    @CacheEvict(value="orgCache", key="#p0")
    Long deleteByName(String name);
}
Tips:

1. The key in above example is using p0 to represent the first param of the method. This is in case:

"Name of any of the method argument. If for some reason the names are not available (ex: no debug information), the argument names are also available under the a<#arg> where #arg stands for the argument index (starting from 0)."

Details on how to customize the configuration will not be included here in this tutorial, because you could almost find everything in the official document. Just do a little bit research based on your own requirement.

Spring expression language can also be used in the configuration.

Reference:


Good luck!


4/24/2015

Runtime Setting of SSL Params when invoking web services(apache cxf client)

By default, when we config the SSL Key for WS call, we use below system parameters:

System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
System.setProperty("javax.net.ssl.keyStore", "keystore.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "1234");
System.setProperty("javax.net.ssl.trustStore", "cacerts");

But it is not flexible enough if the application has gateway structure and needs different SSL configuration for each different channels. So we need a workaround.

Below example is based on the client stub that generated with Apache CXF.(Recommanded)
Personally I prefer to use Apache CXF to generate client stub instead of Apache Axis. It is more flexible and more user friendly.

Maven Config to generate client stub:

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>3.0.4</version>
    <executions>
        <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
                <sourceRoot>${project.basedir}/src/main/java</sourceRoot>
                <wsdlOptions>
                    <wsdlOption>
                        <wsdl>${project.basedir}/src/main/resources/schemas/sample-ws.wsdl</wsdl>
                        <bindingFiles>
                            <bindingFile>${project.basedir}/src/main/resources/schemas/bindings/binding.xjb</bindingFile>
                        </bindingFiles>
                        <extraargs>
                            <extraarg>-impl</extraarg>
                            <extraarg>-client</extraarg>
                            <extraarg>-verbose</extraarg>
                            <extraarg>-p</extraarg>
                            <extraarg>com.sample.ws</extraarg>
                            <extraarg>-xjc-Xvalue-constructor</extraarg>
                        </extraargs>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2java</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.jvnet.jaxb2_commons</groupId>
            <artifactId>jaxb2-value-constructor</artifactId>
            <version>3.0</version>
        </dependency>
        <dependency>
            <groupId>org.jvnet.jaxb2_commons</groupId>
            <artifactId>jaxb2-basics</artifactId>
            <version>0.6.4</version>
        </dependency>
    </dependencies>
</plugin>

After the client stub is generated, if we want to make web service call, the client code is like below:
public SampleResponse authenticate(SampleRequest request) {
    
    SampleServiceInterface port = this.getPort();
    return port.authenticate(request);
}

public SampleServiceInterface getPort() {

    SampleServiceInterfaceService ss = new SampleServiceInterfaceService();
    SampleServiceInterface port = ss.getSampleServiceAPI();
    
    return port;
}

To customize the SSL configuration, we need to write the customized SSLSocketFactory. To implement this, we can create one SSLSocketFactoryGenerator, like below:

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.lang.StringUtils;


public class SSLSocketFactoryGenerator {

    
    private byte[] keyStore = null;
    private byte[] trustStore = null;
    
    private String alias = null;
    private String keyStoreType = null;
    private String keyStorePassword = null;
    
    private String trustStoreType = null;
    private String trustStorePassword = null;

    public SSLSocketFactoryGenerator(ClientConfig config) {
        
        this.alias = config.getKeyAlias();
        this.keyStore = config.getKeyStoreBytes();
        this.trustStore = config.getTrustStoreBytes();
        this.keyStoreType = config.getKeyStoreType();
        this.keyStorePassword = config.getKeystorePassword();
        this.trustStoreType = config.getTrustStoreType();
        this.trustStorePassword = config.getTruststorePassword();
    }

    public SSLSocketFactory getSSLSocketFactory() throws IOException,
            GeneralSecurityException {

        KeyManager[] keyManagers = getKeyManagers();
        TrustManager[] trustManagers = getTrustManagers();

        SSLContext context = SSLContext.getInstance("SSL");
        context.init(keyManagers, trustManagers, null);

        SSLSocketFactory ssf = context.getSocketFactory();
        return ssf;
    }

    public String getAlias() {
        return alias;
    }

    public void setAlias(String alias) {
        this.alias = alias;
    }

    public byte[] getKeyStore() {
        return keyStore;
    }

    public void setKeyStore(byte[] keyStore) {
        this.keyStore = keyStore;
    }

    public byte[] getTrustStore() {
        return trustStore;
    }

    public void setTrustStore(byte[] trustStore) {
        this.trustStore = trustStore;
    }

    public String getKeyStoreType() {
        return keyStoreType;
    }

    public void setKeyStoreType(String keyStoreType) {
        this.keyStoreType = keyStoreType;
    }

    public String getKeyStorePassword() {
        return keyStorePassword;
    }

    public void setKeyStorePassword(String keyStorePassword) {
        this.keyStorePassword = keyStorePassword;
    }

    public String getTrustStoreType() {
        return trustStoreType;
    }

    public void setTrustStoreType(String trustStoreType) {
        this.trustStoreType = trustStoreType;
    }

    public String getTrustStorePassword() {
        return trustStorePassword;
    }

    public void setTrustStorePassword(String trustStorePassword) {
        this.trustStorePassword = trustStorePassword;
    }

    private KeyManager[] getKeyManagers() throws IOException,
            GeneralSecurityException {

        String alg = KeyManagerFactory.getDefaultAlgorithm();
        KeyManagerFactory kmFact = KeyManagerFactory.getInstance(alg);

        InputStream fis = new ByteArrayInputStream(getKeyStore());
        
        KeyStore ks = KeyStore.getInstance(getKeyStoreType());
        
        ks.load(fis, getKeyStorePassword().toCharArray());
        fis.close();

        kmFact.init(ks, StringUtils.isEmpty(getKeyStorePassword())?null:getKeyStorePassword().toCharArray());

        KeyManager[] kms = kmFact.getKeyManagers();
        return kms;
    }

    protected TrustManager[] getTrustManagers() throws IOException,
            GeneralSecurityException {

        String alg = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmFact = TrustManagerFactory.getInstance(alg);

        InputStream fis = new ByteArrayInputStream(getTrustStore());
        KeyStore ks = KeyStore.getInstance(getTrustStoreType());
        ks.load(fis, StringUtils.isEmpty(getTrustStorePassword())?null:getTrustStorePassword().toCharArray());
        fis.close();

        tmFact.init(ks);

        TrustManager[] tms = tmFact.getTrustManagers();
        return tms;
    }
}

This is a quite basic sample, for different scenarios, it should be quite easy to make complementary or revision. In above sample, we can create customized SSLSocketFactory by passing in different configuration data(ClientConfig.java).

In this case, we also  need to revise the previous getPort function to use this customized SSLSocketFactory.
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.naming.ConfigurationException;
import javax.xml.ws.BindingProvider;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

public class SampleServiceImpl implements SampleService {

    private static final Logger logger = Logger.getLogger(SampleServiceImpl.class);

    private static final String URI = "/auth";

    protected ClientConfig clientConfig;

    public SampleServiceImpl() throws ConfigurationException, IOException {
        super();
    }

    void loadDefaultIfEmptyClientConfig() throws IOException, ConfigurationException {
        if (this.getClientConfig() != null)
            return;

        Properties properties = new Properties();
        properties.load(this.getClass().getClassLoader().getResourceAsStream("config/sample.properties"));
        setClientConfig(new ClientConfig(properties));
    }

    public SampleServiceImpl(Properties properties) throws ConfigurationException, IOException {
        super();
        this.setClientConfig(new ClientConfig(properties));
    }
    
    public SampleServiceImpl(ClientConfig clientConfig) throws ConfigurationException {
        super();
        this.setClientConfig(clientConfig);
    }

    public SampleServiceInterface getPort(String relUrl) {

        SampleServiceInterfaceService ss = new SampleServiceInterfaceService();
        SampleServiceInterface port = ss.getSampleServiceAPI();
        
        BindingProvider bindingProvider = (BindingProvider) port; 
        try {
            bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", 
                    new SSLSocketFactoryGenerator(clientConfig).getSSLSocketFactory());
            
            if(StringUtils.isNotEmpty(relUrl)){
                bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, String.format("%s%s", this.clientConfig.getServiceUrl(), relUrl));
            }
        } catch (IOException e) {
            logger.error("Error happened when initializing SSLFactory.", e);
            throw new IllegalArgumentException(e);
        } catch (GeneralSecurityException e) {
            logger.error("Error happened when initializing SSLFactory.", e);
            throw new IllegalArgumentException(e);
        } 
        return port;
    }
    
    public ClientConfig getClientConfig() {
        return clientConfig;
    }

    public void setClientConfig(ClientConfig clientConfig) throws ConfigurationException {

        this.clientConfig = clientConfig;
    }
    
    @Override
    public SampleResponse authenticate(SampleRequest request) {
    
        SampleServiceInterface port = this.getPort();
        return port.authenticate(request);
    }

}
In this case, for each different channels that need different SSL configuration. We can create different service.




11/01/2013

[Date Formatting] Java Default Engine AND Joda framework

A formatting string describes how date/time values should be read and written from(to) string representation

Now we compare the two kinds of formatting engines.
Engine
Formatter
Thread-safe?
Description
Example
Java
SimpleDateFormat

NO
Standard Java date implementation. Provides lenient, error-prone and full-featured parsing and writing. It has moderate speed and is generally a good choice unless you need to work with large quantities of date/time fields. For advanced study please refer to Java SimpleDateFormat documentation.
yyyy-MM-dd HH:mm:ss
Joda
DateTimeFormat
DateTimeFormatter

YES
An improved third-party date library. Joda is stricter on input data accuracy when parsing and does not work well with time zones. It does, however, provide a 20-30% speed increase compared to standard Java. For further reading please visit the project site at http://joda-time.sourceforge.net).
Joda may be convenient for AS/400 machines.
On the other hand, Joda is unable to read time zone expressed with any number of z letters and/or at least three Z letters in a pattern.
yyyy-MM-dd HH:mm:ss


****************************
Java Default:
****************************

1.1 Date Format Pattern Syntax (Java)
Letter
Date or Time Component
Presentation
Examples
G
Era designator
Text
AD
Y
Year
Year
1996; 96
M
Month in year
Month
July; Jul; VII; 07; 7
w
Week in year
Number
27
W
Week in month
Number
2
D
Day in year
Number
189
d
Day in month
Number
10
F
Day of week in month
Number
2
E
Day in week
Text
Tuesday; Tue
a
Am/pm marker
Text
PM
H
Hour in day (0-23)
Number
0
k
Hour in day (1-24)
Number
24
K
Hour in am/pm (0-11)
Number
0
h
Hour in am/pm (1-12)
Number
12
m
Minute in hour
Number
30
s
Second in minute
Number
55
S
Millisecond
Number
970
z
Time zone
General time zone
Pacific Standard Time; PST; GMT-08:00
Z
Time zone
RFC 822 time zone
-0800
'
Escape for text/id
Delimiter
(none)
''
Single quote
Literal
'

The number of symbol letters you specify also determines the format. For example, if the "zz" pattern results in "PDT", then the "zzzz" pattern generates "Pacific Daylight Time". The following table summarizes these rules:

1.2 Rules for Date Format Usage (Java)
Presentation
Processing
Number of Pattern Letters
Form
Text
Formatting
1 - 3
short or abbreviated form, if one exists
Text
Formatting
>= 4
full form
Text
Parsing
>= 1
both forms
Year
Formatting
2
truncated to 2 digits
Year
Formatting
1 or >= 3
interpreted as Number.
Year
Parsing
1
intepreted literally
Year
Parsing
2
interpreted relative to the century within 80 years before or 20 years after the time when theSimpleDateFormat instance is created
Year
Parsing
>= 3
intepreted literally
Month
Both
1-2
interpreted as a Number
Month
Parsing
>= 3
interpreted as Text (using Roman numbers, abbreviated month name - if exists, or full month name)
Month
Formatting
3
interpreted as Text (using Roman numbers, or abbreviated month name - if exists)
Month
Formatting
>= 4
interpreted as Text (full month name)
Number
Formatting
minimum number of required digits
shorter numbers are padded with zeros
Number
Parsing
number of pattern letters is ignored (unless needed to separate two adjacent fields)
any form
General time zone
Both
1-3
short or abbreviated form, if has a name. Otherwise, GMT offset value (GMT[sign][[0]0-23]:[00-59])
General time zone
Both
>= 4
full form, , if has a name. Otherwise, GMT offset value (GMT[sign][[0]0-23]:[00-59])
General time zone
Parsing
>= 1
RFC 822 time zone form is allowed
RFC 822 time zone
Both
>= 1
RFC 822 4-digit time zone format is used ([sign][0-23][00-59])
RFC 822 time zone
Parsing
>= 1
General time zone form is allowed

Examples:

1.3 Date and Time Format Patterns and Results (Java)
Date and Time Pattern
Result
"yyyy.MM.dd G 'at' HH:mm:ss z"
2001.07.04 AD at 12:08:56 PDT
"EEE, MMM d, ''yy"
Wed, Jul 4, '01
"h:mm a"
12:08 PM
"hh 'o''clock' a, zzzz"
12 o'clock PM, Pacific Daylight Time
"K:mm a, z"
0:08 PM, PDT
"yyyyy.MMMMM.dd GGG hh:mm aaa"
02001.July.04 AD 12:08 PM
"EEE, d MMM yyyy HH:mm:ss Z"
Wed, 4 Jul 2001 12:08:56 -0700
"yyMMddHHmmssZ"
010704120856-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSZ"
2001-07-04T12:08:56.235-0700

****************************
JODA:
****************************
2.1 Date Format Pattern Syntax (Joda)
Symbol
Meaning
Presentation
Examples
G
Era designator
Text
AD
C
Century of era (>=0)
Number
20
Y
Year of era (>=0)
Year
1996
y
Year
Year
1996
x
Week of weekyear
Year
1996
M
Month of year
Month
July; Jul; 07
w
Week of year
Number
27
D
Day of year
Number
189
d
Day of month
Number
10
e
Day of week
Number
2
E
Day of week
Text
Tuesday; Tue
a
Halfday of day
Text
PM
H
Hour of day (0-23)
Number
0
k
Clockhour of day (1-24)
Number
24
K
Hour of halfday (0-11)
Number
0
h
Clockhour of halfday (1-12)
Number
12
m
Minute of hour
Number
30
s
Second of minute
Number
55
S
Fraction of second
Number
970
z
Time zone
Text
Pacific Standard Time; PST
Z
Time zone offset/id
Zone
-0800; -08:00; America/Los_Angeles
'
Escape for text/id
Delimiter
(none)
''
Single quote
Literal
'

We can see from above table, although actual format strings for Java and Joda are almost 100% compatible with each other, still there are differences. The 'F' in default java is not supported in Joda.

Basically, 'F' means 'Day of week in month', for example, '2013-11-8' is the second friday in Nov of 2013, so 'F' will get 2 as result. While 'E' means 'Day of week' only, with the same example, '2013-11-8', 'E' will get 5 as result, because it's Friday, the fifth day in the week.

The number of symbol letters you specify also determines the format. The following table summarizes these rules:

2.2 Rules for Date Format Usage (Joda)
Presentation
Processing
Number of Pattern Letters
Form
Text
Formatting
1 - 3
short or abbreviated form, if one exists
Text
Formatting
>= 4
full form
Text
Parsing
>= 1
both forms
Year
Formatting
2
truncated to 2 digits
Year
Formatting
1 or >= 3
interpreted as Number.
Year
Parsing
>= 1
intepreted literally
Month
Both
1-2
interpreted as a Number
Month
Parsing
>= 3
interpreted as Text (using Roman numbers, abbreviated month name - if exists, or full month name)
Month
Formatting
3
interpreted as Text (using Roman numbers, or abbreviated month name - if exists)
Month
Formatting
>= 4
interpreted as Text (full month name)
Number
Formatting
minimum number of required digits
shorter numbers are padded with zeros
Number
Parsing
>= 1
any form
Zone name
Formatting
1-3
short or abbreviated form
Zone name
Formatting
>= 4
full form
Time zone offset/id
Formatting
1
Offset without a colon between hours and minutes
Time zone offset/id
Formatting
2
Offset with a colon between hours and minutes
Time zone offset/id
Formatting
>= 3
Full textual form like this: "Continent/City"
Time zone offset/id
Parsing
1
Offset without a colon between hours and minutes
Time zone offset/id
Parsing
2
Offset with a colon between hours and minutes


For more details, the official docs are the best place to go.

Reference:
Micosoft: StandardDate and Time Format Strings