/**
*
*/
package org.ebayopensource.turmeric.tools.codegen.external;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.ebayopensource.turmeric.runtime.common.impl.utils.CallTrackingLogger;
import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JVar;
/**
* @author rkulandaivel
*
* This class sorts the contents of JDefinedClass.
* It access the datastructures of JDefinedClass through reflection and does the sorting.
*/
public class ObjectFactoryClassContentsSorter {
private static CallTrackingLogger s_logger = LogManager.getInstance(AxisJavaWSDLGeneratorImpl.class);
private static final ObjectFactoryClassContentsSorter s_instance = new ObjectFactoryClassContentsSorter();
private volatile boolean intialized = false;
private Field m_annotationsField = null;
private Field m_constructorsField = null;
private Field m_annotationsFieldOfJMethod = null;
private Field m_annotationsFieldOfJFieldVar = null;
private Field m_classesField = null;
private Field m_fieldsField = null;
private ObjectFactoryClassContentsSorter(){
}
public static final ObjectFactoryClassContentsSorter getInstance(){
if( !s_instance.intialized ){
synchronized (ObjectFactoryClassContentsSorter.class) {
if( !s_instance.intialized ){
s_instance.init();
s_instance.intialized = true;
}
}
}
return s_instance;
}
@SuppressWarnings("rawtypes")
public void init(){
Class jDefinedClazz = JDefinedClass.class;
Class jMethodClazz = JMethod.class;
try {
m_annotationsField = jDefinedClazz.getDeclaredField("annotations");
m_constructorsField = jDefinedClazz.getDeclaredField("constructors");
m_annotationsFieldOfJMethod = jMethodClazz.getDeclaredField("annotations");
m_classesField = jDefinedClazz.getDeclaredField("classes");
m_fieldsField = jDefinedClazz.getDeclaredField("fields");
m_annotationsFieldOfJFieldVar = JVar.class.getDeclaredField("annotations");
m_annotationsField.setAccessible(true);
m_constructorsField.setAccessible(true);
m_annotationsFieldOfJMethod.setAccessible(true);
m_classesField.setAccessible(true);
m_fieldsField.setAccessible(true);
m_annotationsFieldOfJFieldVar.setAccessible(true);
} catch (SecurityException e) {
throw new RuntimeException("Exception while retriveing the fields of com.sun.codemodel.JDefinedClass through reflection", e);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Exception while retriveing the fields of com.sun.codemodel.JDefinedClass through reflection", e);
}
}
private Object getReflectionValue( Field field, Object instanceObj){
Object val = null;
try {
val = field.get(instanceObj);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Exception while retriveing the value for field " + field.getName() + " through reflection", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Exception while retriveing the value for field " + field.getName() + " through reflection", e);
}
return val;
}
private void sortAnnotations(List<JAnnotationUse> anotations){
Collections.sort( anotations, JClassContentsComparatorProvider.getAnnotationUseComparatorInstance() );
}
@SuppressWarnings("unchecked")
private void sortAnnotations(JDefinedClass jDefinedClazzObj){
s_logger.log(Level.INFO, "Sorting the Annotations - Start");
List<JAnnotationUse> annotations = (List<JAnnotationUse>) getReflectionValue( m_annotationsField, jDefinedClazzObj);
if(annotations != null){
sortAnnotations(annotations);
}
s_logger.log(Level.INFO, "Sorting the Annotations - End");
}
@SuppressWarnings("unused")
private void sortInterfaces(JDefinedClass jDefinedClazzObj){
//no implementation
//the interfaces field is a TreeSet. It follows natural ordering
}
@SuppressWarnings("unused")
private void sortEnumConstantsByName(JDefinedClass jDefinedClazzObj){
//no implementation
//the enumConstantsByName field is a LinkedHashMap. It should be the order present in xml.
//so dont touch
}
@SuppressWarnings("unchecked")
private void sortFields(JDefinedClass jDefinedClazzObj){
//Ideally there should not be any implementation
//because the fields field is a LinkedHashMap. It should be the order present in xml.
//but as far as ObjectFactory is concerned fields need to be sorted
//because it does not have any significance of propOrder
s_logger.log(Level.INFO, "Sorting the Fields Vars - Start");
Map<String,JFieldVar> fields = (Map<String,JFieldVar>) getReflectionValue( m_fieldsField, jDefinedClazzObj);
if( fields != null) {
List<JFieldVar> fieldsList = new ArrayList<JFieldVar>( fields.size() );
Iterator<Map.Entry<String, JFieldVar>> entryIterator = fields.entrySet().iterator();
while( entryIterator.hasNext() ){
JFieldVar jFieldVar = entryIterator.next().getValue();
fieldsList.add( jFieldVar );
entryIterator.remove();
List<JAnnotationUse> annotations = (List<JAnnotationUse>) getReflectionValue( m_annotationsFieldOfJFieldVar, jFieldVar);
if(annotations != null){
sortAnnotations(annotations);
}
}
Collections.sort(fieldsList, JClassContentsComparatorProvider.getJFieldVarComparatorInstance() );
for( JFieldVar jFieldVar : fieldsList){
fields.put(jFieldVar.name(), jFieldVar);
}
}
s_logger.log(Level.INFO, "Sorting the Fields Vars - End");
}
@SuppressWarnings("unchecked")
private void sortContentsOfJMethod(List<JMethod> jMethods){
for( JMethod jmethod: jMethods){
//sorting only the annotations of a method and
// obviously no need to sort order of params, exceptions definitions
List<JAnnotationUse> annotations = (List<JAnnotationUse>) getReflectionValue( m_annotationsFieldOfJMethod, jmethod);
if(annotations != null){
sortAnnotations(annotations);
}
}
}
@SuppressWarnings("unchecked")
private void sortConstructors(JDefinedClass jDefinedClazzObj){
s_logger.log(Level.INFO, "Sorting the Constructors - Start");
List<JMethod> constructors = (List<JMethod>) getReflectionValue( m_constructorsField, jDefinedClazzObj);
if( constructors != null ){
Collections.sort( constructors, JClassContentsComparatorProvider.getSameNameJMethodsComparatorInstance() );
sortContentsOfJMethod( constructors );
}
s_logger.log(Level.INFO, "Sorting the Constructors - End");
}
private void sortMethods(JDefinedClass jDefinedClazzObj){
s_logger.log(Level.INFO, "Sorting the Methods - Start");
List<JMethod> jMethods = (List<JMethod>) jDefinedClazzObj.methods();
if( jMethods != null ){
Collections.sort( jMethods, JClassContentsComparatorProvider.getJMethodComparatorInstance() );
sortContentsOfJMethod( jMethods );
}
s_logger.log(Level.INFO, "Sorting the Methods - End");
}
@SuppressWarnings({ "unchecked", "unused" })
private void sortInnerClasses(JDefinedClass jDefinedClazzObj){
List<JDefinedClass> classes = (List<JDefinedClass>) getReflectionValue( m_classesField, jDefinedClazzObj);
if(classes != null){
//no need to sort the order of class but the contents
// (classes is a TreeMap and natural sorting is there)
for( JDefinedClass clazz : classes){
sort( clazz );
}
}
}
public void sort(JDefinedClass jDefinedClazz){
//only Annotations, Fields, Constructors and Methods
//are sorted here because ObjectFactory only use those
//others like Interfaces, InnerClass are empty
String clazzFullName = jDefinedClazz.fullName();
s_logger.log(Level.INFO, "Sorting the contents of class " + clazzFullName );
long stTime = System.currentTimeMillis();
try {
sortAnnotations(jDefinedClazz);
sortFields(jDefinedClazz);
sortConstructors(jDefinedClazz);
sortMethods(jDefinedClazz);
} catch (ClassCastException e) {
throw new RuntimeException("This error could be due to the change in the version of jars xjc/axis.", e);
}
long endTime = System.currentTimeMillis();
s_logger.log(Level.INFO, "Successfully sorted the contents of class " + clazzFullName);
s_logger.log(Level.INFO, "Times taken sorting class '"+clazzFullName+"' is "+ ((stTime-endTime)/1000) +" secs");
}
}