Wednesday, March 7, 2012

Resolve circular dependency in Spring

It is discussed clearly in Managing Circular Dependencies in Spring.

We used to deal with it in init() method. For example, A<->B, inject B into A, and in A's init(), call B.setA(this). This approach has two drawbacks. Not only the interface of B must expose an additional setA method; but also *this* refers to the raw instance of A, rather than a proxied (wrapped) instance of A. That means, if the method of A requires AOP proxy such as transaction interceptor, you will get Hibernate no session bounded exception. Remember, the Spring bean (applicationContext.getBean("xxx")) provides us both dependency injection and AOP proxy.

The article describes two solutions:
1. Inject ApplicationContext to one bean through ApplicationContextAware interface and look up the peer bean
2. Use a BeanPostProcessor to wire up the beans after they are instantiated. This is preferred since it allows the container to handle this, rather than the bean itself.

The implementation in the above post seems to be problematic. I always run into BeanCurrentlyInCreationException. I revised it as follows, basically, the passed in initialized bean should be target bean, and we know both beans are ready at this point. Also, I added support for proxy and factory bean.

<bean id="circularDependencyBeanPostProcessor" class="CircularDependencyBeanPostProcessor">
  <property name="config">
   <map>
    <entry key="templateManager">  
     <props>
      <prop key="policyDomainManager">templateManager</prop>  
     </props>
    </entry>
   </map>
  </property>
 </bean>
public Object postProcessAfterInitialization(Object targetBean, String beanName) {
  if (config == null) {
   return targetBean;
  }
  Map dependentConfig = (Map) config.get(beanName);
  if (dependentConfig != null) {
   try {
    if (targetBean instanceof FactoryBean) {
     targetBean = ((FactoryBean) targetBean).getObject();
    }
    
    for (Object sourceBeanName : dependentConfig.keySet()) {
     Object sourceBean = factory.getBean((String) sourceBeanName);
     
     // Jdk dynamic proxy is interface based, generally we don't want
     // to expose those set methods such as setPolicyDomainMgr()
     // in the interface. In this case, we inject the dependent bean
     // into its target object instead.
     if (AopUtils.isJdkDynamicProxy(sourceBean)) {
      sourceBean = ((Advised) sourceBean).getTargetSource().getTarget();
     }
     String propertyName = (String)dependentConfig.get(sourceBeanName);
    
     BeanInfo beanInfo = Introspector.getBeanInfo(sourceBean.getClass());
     PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
     if (propertyDescriptors != null) {
      for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
       if (propertyName.equals(propertyDescriptor.getName())) {
        Method setter = propertyDescriptor.getWriteMethod();
        setter.invoke(sourceBean, targetBean);
        break;
       }
      }
     }
    }

   } catch (IntrospectionException ie) {
    log.error("IntrospectionException", ie);
   } catch (Exception e) {
    log.error(e);
   }

  }
  return targetBean;
 }

Monday, February 6, 2012

UTF-8 encoding

On php UI, both fields (location, zone) support utf-8 characters. The user could type and save. What surprised me is that in mysql db, zone is defined as a varchar (latin1) column, and location is defined as a varchar (utf8). How can this work?

I set both zone and location to ‘测试’ and save. Below is the values stored in the DB. It is interesting that the zone field actually store the encoded utf8 string (each character takes 3 bytes) in a latin-1 column, whereas location field is a double encoded utf8 string which is unnecessary (it is because the connection setting is latin-1).

This is because the UI page uses utf-8 characters. It could be store blindly into a latin1 column.
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>

[Explanation for location]
The data is in utf8, the connection settings are in latin1. The table is in utf8. So, MySQL converts each of C3 and A9 (which it was told was latin1) to utf8, leading to 4 bytes in the table: C3 83 C2 A9. I call this double-encoding. The problem was caused by lying (usually accidentally) to MySQL about what encoding was in the application's data.

[Explanation for zone]
The data was loaded in an old system in the following manner. The application got utf8 bytes and blindly stored them in a latin1 column.

Reference: MySQL Charset/Collate

Tuesday, November 29, 2011

Signed Jars and Certificate

1. Public/Private key Pair
It is used in two scenarios:
1) Encryption: encrypt secure content by public key of the opposite side, e.g., SSL handshake, client (browser) encrypts a random symmetric encryption key with web server's public key, web server will decrypt it with its own private key and get the symmetirc key, thereafter, they send/receive message en/deccrypted by using the symmetic key;
2) Digital Signing: encrypt the message by your private key, to certify the message (*unsecure*) coming from you. The receiver will decrypt it with your public key.

2. Certificate
Naturally, the question arises. How to broadcast your public key? The answer is: certificate. The certificate contains the reference to the issuer, the public key of the owner of this certificate, the dates of validity of this certificate and the signature of the certificate to ensure this certificate hasen't been tampered with. Usually your browser or application has already loaded the root certificate of well known Certification Authorities (CA) or root CA Certificates. The CA maintains a list of all signed certificates as well as a list of revoked certificates. A certificate is insecure until it is signed (**signed by a CA certificate, in the other words, encrypted by a CA authority's private key), as only a signed certificate cannot be modified. You can sign a certificate using itself, it is called a self signed certificate. All root CA certificates are self signed.

The certificate has all the elements to send an encrypted message to the owner (using the public key) or to verify a message signed by the author of this certificate.

3) Signed Jars
When jarsigner is used to sign a JAR file, the output signed JAR file is exactly the same as the input JAR file, except that it has two additional files placed in the META-INF directory:

- a signature file, with a .SF extension, (**digest value for the three lines in the manifest file for the source file)
- a signature block file, with a .DSA, .RSA, or .EC extension. (** signature of .SF, we actually sign the signature(digest) of signature)

The .SF file is signed and the signature is placed in the signature block file. This file also contains, encoded inside it, the certificate or certificate chain from the keystore which authenticates the public key corresponding to the private key used for signing.

SSL Certificates HOWTO
jarsigner - JAR Signing and Verification Tool

Tuesday, November 15, 2011

Rethrown exception disregarded

public void badmethod() throws Exception {
  boolean error = false;
  try {
   throw new Exception();
  } catch (Exception  e) {
   error = true;
   throw e;
  } finally {
   if (error) return;
  }
 }
 
 public void testbadmethod() {
  try {
   badmethod();
   System.out.println("WRONG");
  } catch (Exception ae) {
   System.out.println("RIGHT");
  }
 }
It prints out "WRONG". i.e., with return statement in finally caluse, the rethrown exception is swallowed.