View Javadoc

1    /****************************************************************************
2    * Copyright (c) 2005, 2006, 2007, 2008, 2009 Imola Informatica.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the LGPL License v2.1
5    * which accompanies this distribution, and is available at
6    * http://www.gnu.org/licenses/lgpl.html
7    ****************************************************************************/
8   package it.imolinfo.jbi4corba.webservice.generator.bcm;
9   
10  import it.imolinfo.jbi4corba.exception.ClassGenerationException;
11  import it.imolinfo.jbi4corba.Logger;
12  import it.imolinfo.jbi4corba.LoggerFactory;
13  import it.imolinfo.jbi4corba.webservice.generator.AnyType;
14  import it.imolinfo.jbi4corba.webservice.generator.AnyTypeUtils;
15  import it.imolinfo.jbi4corba.webservice.generator.InterfaceType;
16  import it.imolinfo.jbi4corba.webservice.generator.InterfaceTypeUtils;
17  import it.imolinfo.jbi4corba.webservice.generator.UnionType;
18  import it.imolinfo.jbi4corba.webservice.generator.UnionTypeUtils;
19  import it.imolinfo.jbi4corba.webservice.generator.TypeUtils;
20  
21  import java.lang.reflect.Modifier;
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  
26  import org.objectweb.asm.AnnotationVisitor;
27  import org.objectweb.asm.ClassAdapter;
28  import org.objectweb.asm.ClassVisitor;
29  import org.objectweb.asm.ClassWriter;
30  import org.objectweb.asm.FieldVisitor;
31  import org.objectweb.asm.MethodVisitor;
32  import org.objectweb.asm.Opcodes;
33  import org.objectweb.asm.Type;
34  import org.objectweb.asm.util.TraceMethodVisitor;
35  
36  /**
37   * bytecode manipulation.
38   *
39   * For each Object visited we modify the bytecode as following:
40   *
41   * 1) for each public or protected member we add the getter and setter method.
42   * 2) if the class is 'abstract' we remove this keyword.
43   * 3) we add/modify a default constructor where we istantiate the array
44   *    (if the class contains one or more array) to avoid NullPointerException.
45   * 4) We add the jaxb Annotations
46   *
47   */
48  public class IdlToWsdlAdapter extends ClassAdapter {
49  
50    /**
51     * Logger.
52     */
53    private static final Logger LOG
54            = LoggerFactory.getLogger(IdlToWsdlAdapter.class);
55    
56    public static final String JAXB_XML_ACCESSOR_TYPE  = "Ljavax/xml/bind/annotation/XmlAccessorType;";
57    
58    public static final String JAXB_XML_ACCESS_TYPE = "Ljavax/xml/bind/annotation/XmlAccessType;";
59    
60    public static final String JAXB_XML_ELEMENT = "Ljavax/xml/bind/annotation/XmlElement;";   
61      
62    public static final String PROPERTY_ACCESS_TYPE = "PROPERTY";
63    
64    public static final String NONE_ACCESS_TYPE = "NONE";
65    
66    public static final String FIELD_ACCESS_TYPE = "FIELD";
67    
68    protected String className = null;
69    
70    protected ClassWriter classWriter = null;
71  
72    protected Map<String, String> mapOfFields = new HashMap<String, String>();
73  
74    // Utility Object
75    private ByteCodeManipulationUtil bcmUtil = new ByteCodeManipulationUtil();
76    
77    private boolean areClassAnnotationsPresent = false;
78    
79    // True if the class is a Programmatic Exception
80    private boolean isException = false;
81  
82    private Map<String, UnionType> allUnionTypes;
83    
84    private Map<String, String> fieldsUnionTypes;
85    
86    private Map<String, InterfaceType> allInterfaceTypes;
87    
88    private Map<String, String> fieldsInterfaceTypes;
89    
90    private boolean excludeType;
91    
92    
93    
94    /**
95     * The adapater used to manipulate the code.
96     *
97     * @param   cv    The ClassVisitor used in this object.
98     * @param   cw    The ClassWriter used in this object.
99     * @param   cn    The class name to manipulate.
100    */
101 	public IdlToWsdlAdapter(ClassVisitor cv, ClassWriter cw, String cn,
102 			Map<String, UnionType> allUnTypes, Map<String, String> fUnTypes,
103 			Map<String, InterfaceType> allInTypes,Map<String, String> fIntTypes,boolean isEx,boolean excludeType) {
104     super(cv);
105 
106     classWriter = cw;
107     className = cn;
108     isException = isEx;    
109     allUnionTypes = allUnTypes;
110     fieldsUnionTypes = fUnTypes;
111     fieldsInterfaceTypes = fIntTypes;
112     allInterfaceTypes=allInTypes;
113     this.excludeType=excludeType;
114     
115 		
116     LOG.debug("CRB000604_new_GetterSetterAdapter", new Object[]{cv, cw, cn, allUnionTypes, isEx});
117   }
118 
119   /**
120    * Override.
121    * @param version  	   The method visitor
122    * @param access         The access
123    * @param name           The name
124    * @param signature      The signature
125    * @param superName      The super name
126    * @param interfaces     The interfaces
127    */
128   @Override
129   public void visit(int version,
130                     int access,
131                     String name,
132                     String signature,
133                     String superName,
134                     String [] interfaces) {
135     LOG.debug(">>>>> visit - begin");
136 
137     LOG.debug("CRB000603_VISIT", new Object[]{version, access, name, signature, superName, interfaces});
138 
139     if (Opcodes.ACC_INTERFACE == access) {
140 
141         LOG.debug("This class (" + name + ") is an interface.");
142         
143     } 
144    
145     if ((Opcodes.ACC_ABSTRACT & access) == Opcodes.ACC_ABSTRACT) {
146 
147         access = access & (~ Opcodes.ACC_ABSTRACT);
148 
149         LOG.debug("This class (" + name + ") was an abstract "
150                 + "... now is a concrete class.");
151 
152     } else {
153         LOG.debug("This class (" + name + ") is a concrete class.");
154     }
155     
156     // Remove the "final"
157     if ((Opcodes.ACC_FINAL & access) == Opcodes.ACC_FINAL) {
158         access = access & (~Opcodes.ACC_FINAL);
159         LOG.debug("Removed final from class");
160     }
161 
162     // if (superName.equals("org/omg/CORBA/UserException")) {
163     if (isException) {
164         // superName = "java/lang/Exception";       
165         LOG.debug("The class: " + name +" is an Exception");
166     } else {
167         LOG.debug("The class: " + name +" is not an Exception");
168     }    
169     
170     LOG.debug("<<<<< visit - end");
171         
172     super.visit(version, access, name, signature, superName, interfaces);
173     
174     addAnnotation();  
175   }
176   
177   /**Visit
178    * Adds the @XmlAccessorType(XmlAccessType.PROPERTY) jaxb annotation.
179    * See CRB-154
180    * @param name
181    */
182   private void addAnnotation() {
183       if (!areClassAnnotationsPresent) {
184           
185           // Adds the XMLAccessorTypeAnnotation
186           AnnotationVisitor av = null;          
187           
188           // We annotate the classes with field access type
189           av = cv.visitAnnotation(JAXB_XML_ACCESSOR_TYPE, true);
190           //the Annotations was changed for generate WSDL with Union Type
191           av.visitEnum("value", JAXB_XML_ACCESS_TYPE, FIELD_ACCESS_TYPE);          
192           
193           if (av != null) {
194               av.visitEnd();
195           }                
196           
197           areClassAnnotationsPresent = true;
198       }
199   }
200 
201   /**
202    * Override.
203    * @param access         The access
204    * @param name           The name
205    * @param desc           The description
206    * @param signature      The signature
207    * @param exceptions     The exceptions
208    * @return               The return
209    */
210   @Override
211   public MethodVisitor visitMethod(int access,
212           String name,
213           String desc,
214           String signature,
215           String[] exceptions) {
216 
217     LOG.debug(">>>>> visitMethod - begin");
218 
219     LOG.debug("visitMethod. access="     + access
220                         + "; name="       + name
221                         + "; desc="       + desc
222                         + "; signature="  + signature
223                         + "; exceptions=" + exceptions);
224        
225     
226     // if we found the default constructor then ...
227     
228     // replace union and any types in method signature with java.lang.Object
229     try {
230     	if (!excludeType)
231         {
232     		desc = UnionTypeUtils.replaceUnionTypesInMethodSignature(desc, allUnionTypes, null);
233     		desc = AnyTypeUtils.replaceAnyTypesInMethodSignature(desc);
234         }
235 	} catch (ClassGenerationException e) {
236 		// nothing to replace
237 		LOG.debug("visitMethod - Nothing to replace:" + e.getMessage());
238 	}
239 	TraceMethodVisitor mv = null;
240     if ("<init>".equals(name)) {
241 
242         LOG.debug("default constructor modifications.");
243                
244         mv = new AppenderMethodVisitor(
245                 super.visitMethod(access, name, desc, signature, exceptions),
246                 mapOfFields,
247                 className);
248              
249         LOG.debug("<<<<< visitMethod - end. AppenderMethodVisitor=" + mv);
250        
251        
252       }
253 
254     // else
255     LOG.debug("<<<<< visitMethod - end. "
256             + "methodName=" + name + "; methodDescription=" + desc);
257     // replace attribution instructions of union and any types
258     if (!excludeType)
259     {
260 	    if (mv == null)
261 	    	mv = new ReplaceUnionsMethodVisitor( super.visitMethod(access, name, desc, signature, exceptions),allUnionTypes);
262 	    else
263 	    	mv = new ReplaceUnionsMethodVisitor( mv,allUnionTypes);
264 	    
265 	    if (mv == null)
266 	    	mv = new ReplaceAnyMethodVisitor( super.visitMethod(access, name, desc, signature, exceptions));
267 	    else
268 	    	mv = new ReplaceAnyMethodVisitor( mv);
269     }
270     else
271     {
272     	if (mv == null)
273 	    	return super.visitMethod(access, name, desc, signature, exceptions);
274     }
275     return mv;
276   }
277 
278 /**
279    * @param access      the field's access flags (see Opcodes).
280    *                    This parameter also indicates if the field is synthetic
281    *                    and/or deprecated.
282    * @param name        the field's name.
283    * @param desc        the field's descriptor (see Type).
284    * @param signature    the field's signature. May be null if the field's type
285    *                    does not use generic types.
286    * @param value        the field's initial value.
287    *                    This parameter, whitweakIdlToWsdlClassesch may be null if the field does not
288    *                    have an initial value, must be an Integer, a Float,
289    *                    a Long, a Double or a String (for int, float, long or
290    *                    String fields respectively).
291    *                    This parameter is only used for static fields.
292    *                    Its value is IGNORED for non static fields,
293    *                    which must be initialized through bytecode
294    *                    instructions in constructors or methods.
295    *
296    * @return    a visitor to visit field annotations and attributes,
297    *             or null if this class visitor is not interested
298    *             in visiting these annotations and attributes.
299    */
300   @Override
301   public FieldVisitor visitField(
302         int access,
303           String name,
304           String desc,
305           String signature,
306           Object value) {
307 
308     LOG.debug(">>>>> visitField - begin:" + desc);
309 
310     LOG.debug("visitField. access="    + access
311                         + "; name="      + name
312                         + "; desc="      + desc
313                         + "; signature=" + signature
314                         + "; value="     + value);
315     
316 	boolean isArray = TypeUtils.isArray(desc);
317 	String arrayStr = TypeUtils.getArrayDimmentionAsPrefix(desc);
318 	UnionType union =UnionTypeUtils.isUnionType(desc, isArray, allUnionTypes);
319 	InterfaceType intf = InterfaceTypeUtils.isInterfaceType(desc, isArray, allInterfaceTypes);
320 	boolean isAny = TypeUtils.getTypeFromTypeDescription(desc).equals(AnyType.CORBA_ANY_TYPE);
321         //If excludeType is true the bytecode manipulation about Type as Any,Interfacce or Union is Disable
322         
323 	if (isAny  && !excludeType) {
324 		desc = arrayStr + "Ljava/lang/Object;";
325 	}
326 	if ((union != null)  && !excludeType) {
327 		desc = arrayStr + "L" + union.getTypeName().replace('.', '/') + "Wrapper;";
328 	}
329 	
330 	if (intf != null && !excludeType) {
331 		if (isArray)
332 			desc = Type.getDescriptor(javax.xml.ws.wsaddressing.W3CEndpointReference[].class);
333 		else
334 			desc = Type.getDescriptor(javax.xml.ws.wsaddressing.W3CEndpointReference.class);
335 	}
336 
337     if (Opcodes.ACC_PUBLIC == access || Opcodes.ACC_PROTECTED == access) {
338         bcmUtil.createSetter(classWriter, className, name, desc);        
339         
340         //bcmUtil.createGetter(classWriter, className, name, desc, isException);
341         bcmUtil.createGetter(classWriter, className, name, desc, false);
342 
343         mapOfFields.put(name, desc);
344     }
345     LOG.debug("<<<<< visitField - end");
346 
347 		FieldVisitor fv = super
348 				.visitField(access, name, desc, signature, value);
349 
350 		if (union != null && !excludeType) {
351 	//		UnionTypeUtils.addUnionTypeAnnotation(fv, union, allUnionTypes);
352 			fieldsUnionTypes.put(name, union.getTypeName());
353 		}
354 
355 		//Save metadata about InterfaceType field   
356 		if (intf != null && !excludeType) {
357 			
358 			fieldsInterfaceTypes.put(name,intf.getTypeName());
359 		}
360 		if (!ignoreField(name, access))
361 		{
362 			AnnotationVisitor xmlElem = fv.visitAnnotation(JAXB_XML_ELEMENT, true);
363 			xmlElem.visit("required", true);
364 			xmlElem.visit("nillable", false);
365 			
366 			if (xmlElem != null) {
367 	      	  xmlElem.visitEnd();
368 	        }
369 		}
370 		return fv;
371 	}
372   	
373    /**
374 	 * ignoreField
375 	 * 
376 	 * @param fieldName
377 	 * @param accessModif
378 	 * @return
379 	 */
380    private static boolean ignoreField(String fieldName, int accessModif)
381 	{
382 		
383 		//treat value type case(ignore field private static String[] _truncatable_ids)
384 		if (fieldName.equals("_truncatable_ids") && Modifier.isPrivate(accessModif) 
385 				&& Modifier.isStatic(accessModif))
386 		{
387 			return true;
388 		}
389 		
390 		return false;
391 	}
392 	
393   /**
394   * XXX javadoc.
395   */
396   @Override
397   public void visitEnd() {
398     bcmUtil.createToString(classWriter);
399     bcmUtil.createEquals(classWriter);
400 
401     super.visitEnd();
402   }
403 
404 }