Source code: org/mobicents/slee/container/deployment/SbbVerifier.java
1 /***************************************************
2 * *
3 * Mobicents: The Open Source JSLEE Platform *
4 * *
5 * Distributable under LGPL license. *
6 * See terms of license at gnu.org. *
7 * *
8 ***************************************************/
9 /*
10 * SbbVerifier.java
11 *
12 * Created on Jul 26, 2004
13 *
14 */
15 package org.mobicents.slee.container.deployment;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.Map;
22 import java.util.Set;
23
24 import javassist.ClassPool;
25 import javassist.CtClass;
26 import javassist.CtField;
27 import javassist.CtMethod;
28 import javassist.Modifier;
29 import javassist.NotFoundException;
30
31 import javax.slee.ActivityContextInterface;
32 import javax.slee.Sbb;
33 import javax.slee.management.SbbDescriptor;
34
35 import org.jboss.logging.Logger;
36 import org.mobicents.slee.container.SleeContainer;
37 import org.mobicents.slee.container.management.CMPField;
38 import org.mobicents.slee.container.management.ComponentKey;
39 import org.mobicents.slee.container.management.DeployableUnitIDImpl;
40 import org.mobicents.slee.container.management.EventTypeDescriptorImpl;
41 import org.mobicents.slee.container.management.EventTypeIDImpl;
42 import org.mobicents.slee.container.management.GetChildRelationMethod;
43 import org.mobicents.slee.container.management.ProfileCMPMethod;
44 import org.mobicents.slee.container.management.SbbDescriptorImpl;
45 import org.mobicents.slee.container.management.SbbEventEntry;
46
47 /**
48 * Verify that a sbb abstract class provided by a sbb developer is following a set of constraints.
49 * <BR>This verifier checks that the sbb developer developed the Sbb Abstract class
50 * following the slee specification requirements.<BR>
51 * <BR>It verifies also that the Sbb Abstract class and the definitions provided
52 * by the sbb developer in the deployment descriptor are matching<BR>
53 * It verifies also the sbb concrete class generated by the slee runtime to check
54 * the generated byte code integrity.
55 *
56 * @author DERUELLE Jean <a href="mailto:jean.deruelle@gmail.com">jean.deruelle@gmail.com</a>
57 *
58 */
59 public class SbbVerifier {
60 public final static String DEPLOYMENT_PATH = SleeContainer.DEPLOY_PATH;
61
62
63 /**
64 * the set of constraints defined by the slee specification
65 * on a sbb abstract class
66 */
67 //private List constraints=null;
68 /**
69 * deployment descriptor used to verified that the Sbb Abstract class and
70 * the definitions in the deployment descriptor are matching
71 */
72 private SbbDescriptorImpl sbbDeploymentDescriptor=null;
73 /**
74 * Path where to find the classes
75 */
76 private static String deployPath=null;
77
78
79 /**
80 * Pool to generate or read classes with javassist
81 */
82 private ClassPool pool = null;
83 /**
84 * Logger to logg information
85 */
86 private static Logger logger=null;
87
88
89 private String errorString;
90
91 private static boolean firstTime = true;
92
93
94 /** the class holder for javax.slee.Sbb */
95 private CtClass sbbAbstractClass;
96
97 static{
98 logger = Logger.getLogger(SbbVerifier.class);
99
100 }
101
102 /**
103 *
104 */
105 public SbbVerifier(SbbDescriptor sbbDescriptor) {
106
107 sbbDeploymentDescriptor=(SbbDescriptorImpl)sbbDescriptor;
108 pool=((DeployableUnitIDImpl) (sbbDescriptor
109 .getDeployableUnit())).getDUDeployer().getClassPool();
110 try {
111 sbbAbstractClass = pool.get(Sbb.class.getName());
112 } catch (NotFoundException e) {
113 String s = "Cannot find class ! while verifying ";
114 logger.fatal(e);
115 throw new RuntimeException (s,e);
116 }
117 }
118
119 /**
120 * Verify that a sbb abstract class provided by a sbb developer is following
121 * a set of constraints.
122 * @param sbbAbstractClassName name of the sbb abstract class provided by the user
123 * @return true is the sbb abstract class is safe
124 */
125 public boolean verifySbbAbstractClass(String sbbAbstractClassName, SleeContainer serviceContainer){
126
127 try{
128
129 // FIXME: this is obsolete, we don't want the class to be defined before it is inspected and enhanced
130 // logger.info("Verifying "+ profileTransientStateClass(sbbAbstractClassName).getName());
131 // CtClass ctClass=pool.get(sbbAbstractClassName);
132
133 /*
134 * Load the abstract class definition in memory, but do not make it visible via the classloader yet
135 */
136 logger.info("Verifying "+ sbbAbstractClassName);
137 ClassLoader cl = (ClassLoader)Thread.currentThread().getContextClassLoader();
138 String classRsrcName = sbbAbstractClassName.replace('.', '/') + ".class";
139 InputStream sbbAbstractClassIS = cl.getResourceAsStream(classRsrcName);
140 CtClass ctClass = pool.makeClass(sbbAbstractClassIS);
141
142 if(!checkSbbAbstractClassConstraints(ctClass)){
143 logger.error("SbbAbstractClass Constraints were not successfully verified");
144 return false;
145 }
146 if(!checkSbbAgainstDeploymentDescriptor(ctClass)){
147 logger.error("Sbb and deployment descriptor are not matching");
148 return false;
149 }
150 if ( ! this.checkEventHandlerMethods(ctClass,serviceContainer)){
151 logger.error("EventHandler Methods were not successfully verified");
152 return false;
153 }
154 }
155 catch(IOException ioe){
156 logger.info("Sbb Abstract Class validation failed for: " + sbbAbstractClassName, ioe);
157 return false;
158 }
159 logger.info(sbbAbstractClassName+" is safe");
160 return true;
161 }
162
163 /**
164 * Verify the sbb concrete class generated by the slee runtime to check
165 * the generated byte code integrity.
166 * @param sbbConcreteClassName name of the sbb abstract class provided by the user
167 * @return true is the sbb concrete class is safe
168 */
169 public boolean verifySbbConcreteClass(String sbbConcreteClassName){
170 return false;
171 }
172
173 /**
174 * Check the constraints defined by the slee specification final release 1.0
175 * on an Sbb Abstract Class :
176 * The class must implement, directly or indirectly, the javax.slee.Sbb interface.
177 * · The class must be defined as public and must be abstract.
178 * · The class must not define the finalize method
179 * · The SBB Developer must provide a public constructor that takes no arguments.
180 * @param sbbAbstractClass class, provided by the sbb developer, to check
181 * @return true if the class is safe
182 */
183 protected boolean checkSbbAbstractClassConstraints(CtClass sbbAbstractClass){
184 int modifiers=sbbAbstractClass.getModifiers();
185 //check that the class modifiers contain abstratc and public
186 if(!Modifier.isAbstract(modifiers) || !Modifier.isPublic(modifiers)){
187 logger.error("The class is nor abstract neither public");
188 return false;
189 }
190 //check that the finalize method is not present in the class
191 CtMethod[] methods=sbbAbstractClass.getDeclaredMethods();
192 if(methods!=null){
193 for(int i=0;i<methods.length;i++){
194 CtMethod method = methods[i];
195 if(method.getName().equalsIgnoreCase("finalize")){
196 logger.error("finalize method is present in the sbb abstract class "+
197 sbbAbstractClass.getName());
198 return false;
199 }
200 if ( methods[i].getName().startsWith("ejb") ) {
201 logger.debug("invalid method name detected " + methods[i].getName());
202 return false;
203 }
204
205 if ( methods[i].getName().startsWith("sbb") ) {
206 if ( logger.isDebugEnabled())
207 logger.debug("checking method " + methods[i].getName());
208 CtMethod[] abstractClassMethods = this.sbbAbstractClass.getDeclaredMethods();
209 int k;
210 for ( k = 0; k < abstractClassMethods.length; k ++ ) {
211 CtMethod ctMethod = abstractClassMethods[k];
212 if ( ctMethod.getName().equals(methods[i].getName())) break;
213 }
214 // Not an abstract method so it is invalid.
215 if ( k == abstractClassMethods.length) {
216 logger.error("invalid method name determined " + methods[i].getName());
217 return false;
218 }
219 }
220 }
221 }
222 else{
223 logger.error("there is no abstract methods inthis abstract Class : "+sbbAbstractClass.getName());
224 return false;
225 }
226 //check that the method implements the Sbb class either directly or by inheritance
227 try{
228 boolean implementSbbLinkFound=false;
229 implementSbbLinkFound=
230 checkInterfaces(sbbAbstractClass.getInterfaces(),"javax.slee.Sbb");
231 CtClass superClass=sbbAbstractClass.getSuperclass();
232 while(superClass!=null && !implementSbbLinkFound){
233 if(superClass.getName().equalsIgnoreCase("javax.slee.Sbb"))
234 implementSbbLinkFound=true;
235 else{
236 implementSbbLinkFound=
237 checkInterfaces(superClass.getInterfaces(),"javax.slee.Sbb");
238 superClass=superClass.getSuperclass();
239 }
240 }
241 if(!implementSbbLinkFound){
242 logger.error("sbb abstract class "+
243 sbbAbstractClass.getName()+" doesn't implements the javax.slee.Sbb class either directly or by inheritance");
244 return false;
245 }
246 }
247 catch(NotFoundException nfe){
248 nfe.printStackTrace();
249 return false;
250 }
251 //check that the class has a public constructor without any arguments
252 /**CtConstructor[] constructors=sbbAbstractClass.getConstructors();
253 boolean defaultConstructorFound=false;
254 if(constructors!=null){
255 try{
256 for(int i=0;i<constructors.length;i++){
257 constructors[i].getParameterTypes();
258 }
259 }
260 catch(NotFoundException nfe){
261 defaultConstructorFound=true;
262 }
263 }
264 else
265 return false;
266
267 if(!defaultConstructorFound)
268 return false;**/
269 //check that the field names do not start with sbb or ejb
270 CtField[] ctFields=sbbAbstractClass.getFields();
271 for(int i=0;i<ctFields.length;i++){
272 if(ctFields[i].getName().startsWith("sbb") ||
273 ctFields[i].getName().startsWith("ejb")){
274 logger.error("the sbb abstract class "+
275 sbbAbstractClass.getName()+" has a field starting with sbb or ejb: "+
276 ctFields[i].getName());
277 return false;
278 }
279 }
280
281
282
283
284
285 return true;
286 }
287
288 /**
289 * Check if among the interfaces one is the class searched
290 * @param interfaces the interfaces
291 * @param interfaceSearched the interface to look for
292 * return true if among the interfaces one is the class searched
293 */
294 private boolean checkInterfaces(CtClass[] interfaces,String interfaceSearched) {
295 if(interfaces==null){
296 logger.debug("no interfaces");
297 return false;
298 }
299 for(int i=0;i<interfaces.length;i++){
300 if(interfaces[i].getName().equalsIgnoreCase(interfaceSearched)){
301 return true;
302 }
303 }
304 logger.debug("interfaces are zero length");
305 return false;
306 }
307
308 /**
309 * Check that the sbb abstract class correclty implements what is defined
310 * in the deployment descriptor
311 * For each method defined by the SBB Developer, there must be a matching method in
312 * the SBB abstract class. The matching method must have:
313 * o The same name.
314 * o The same number of arguments, and same argument and return types.
315 * o The same set of exceptions in the throws clause.
316 * param sbbAbstractClass the sbb abstract class to check
317 * @return true if the sbb abstract class correclty implements what is defined
318 * in the deployment descriptor
319 */
320 protected boolean checkSbbAgainstDeploymentDescriptor(CtClass sbbAbstractClass){
321 logger.debug("checkSbbAgainstDeploymentDescriptor started");
322 Map abstractMethods=ClassUtils.getAbstractMethodsFromClass(sbbAbstractClass);
323 Map superClassesAbstractMethods = ClassUtils.getSuperClassesAbstractMethodsFromClass(sbbAbstractClass);
324 logger.debug("checkSbbAgainstDeploymentDescriptor abstract methods retrieved");
325 //Check CMP fields
326 CMPField[] cmpFields=
327 sbbDeploymentDescriptor.getCMPFields();
328 logger.debug("checkSbbAgainstDeploymentDescriptor CMP Fields retrieved ");
329 if(cmpFields!=null){
330 if(!checkCMPFieldsAgainstDeploymentDescripor(abstractMethods,cmpFields,sbbAbstractClass)
331 && !checkCMPFieldsAgainstDeploymentDescripor(superClassesAbstractMethods,cmpFields,sbbAbstractClass)){
332 logger.error("CMP fields are not safe");
333 return false;
334 }
335 }
336 logger.debug("checkSbbAgainstDeploymentDescriptor CMP Fields ok");
337 //Check the presence of the get child relation methods
338 GetChildRelationMethod[] getChildRelationMethods=
339 sbbDeploymentDescriptor.getChildRelationMethods();
340 if(getChildRelationMethods!=null){
341 for(int i=0;i<getChildRelationMethods.length;i++){
342 String methodName=getChildRelationMethods[i].getMethodName();
343 CtMethod getChildRelationMethod=(CtMethod)abstractMethods.get(methodName);
344 if(getChildRelationMethod==null){
345 getChildRelationMethod = (CtMethod)superClassesAbstractMethods.get(methodName);
346 if(getChildRelationMethod==null){
347
348 logger.error("integrity compromised on sbbAbstractClass "+
349 sbbAbstractClass.getName()+" GetChildRelationMethod "+
350 methodName+" defined in the descriptor is missing");
351 return false;
352 }
353 }
354 //The method has been verified so it is removed from the abstract method map
355 abstractMethods.remove(methodName);
356 }
357 }
358 logger.debug("get child relation methods ok");
359
360 if (!checkProfileCMPMethods(sbbAbstractClass, abstractMethods, superClassesAbstractMethods))
361 return false;
362
363 //Check the presence of the activity context interface narrow method
364 Class activityContextInterface=
365 sbbDeploymentDescriptor.getActivityContextInterface();
366 if(activityContextInterface!=null){
367 String activityContextInterfaceName=activityContextInterface.getName();
368 logger.debug(activityContextInterface.getName());
369 CtMethod narrowMethod=(CtMethod)abstractMethods.get("asSbbActivityContextInterface");
370 if(narrowMethod==null){
371 narrowMethod =(CtMethod)superClassesAbstractMethods.get("asSbbActivityContextInterface");
372 if(narrowMethod==null){
373 logger.error("integrity compromised on sbbAbstractClass "+
374 sbbAbstractClass.getName()+
375 " narrow method asSbbActivityContextInterface with the return type"+
376 activityContextInterfaceName+" defined in the descriptor is missing");
377 return false;
378 }
379 }
380 try {
381 if(!narrowMethod.getReturnType().getName().equals(activityContextInterfaceName)){
382 logger.error("integrity compromised on sbbAbstractClass "+
383 sbbAbstractClass.getName()+
384 " narrow method asSbbActivityContextInterface with the return type"+
385 activityContextInterfaceName+" has in the abstract method a return type different "+
386 narrowMethod.getReturnType().getName());
387 return false;
388 }
389 } catch (NotFoundException e) {
390 logger.error("integrity compromised on sbbAbstractClass "+
391 sbbAbstractClass.getName()+
392 " narrow method asSbbActivityContextInterface with the return type"+
393 activityContextInterfaceName+" has a no return type");
394 }
395 //The method has been verified so it is removed from the abstract method map
396 abstractMethods.remove("asSbbActivityContextInterface");
397 }
398 logger.debug("asSbbActivityContextInterface ok");
399 //Check the presence of fire Event methods
400 //FIXME need to do more checking on the fire event methods
401 HashSet sbbEventEntries=
402 sbbDeploymentDescriptor.getSbbEventEntries();
403
404 if(sbbEventEntries!=null){
405 Iterator it=sbbEventEntries.iterator();
406 //firedEvents
407 while(it.hasNext()){
408 SbbEventEntry sbbEventEntry=(SbbEventEntry)it.next();
409 String methodName="fire"+sbbEventEntry.getEventName();
410 CtMethod fireEventMethod=(CtMethod)abstractMethods.get(methodName);
411 if(fireEventMethod!=null){
412 //The method has been verified so it is removed from the abstract method map
413 abstractMethods.remove(methodName);
414 /*logger.error("integrity compromised on sbbAbstractClass "+
415 sbbAbstractClass.getName()+" ProfileCMPMethod "+
416 methodName+" defined in the descriptor is missing");
417 return false;*/
418 }
419 }
420 }
421 logger.debug("sbbEventEntries ok");
422 //TODO check the other methods declared in the descriptor
423 //sbb local interface
424 //Usage parameter method is generated by us.
425 CtMethod getDefaultSbbUsageParameterSetMethod = (CtMethod)abstractMethods.get("getDefaultSbbUsageParameterSet");
426 if ( getDefaultSbbUsageParameterSetMethod != null ) {
427 logger.debug("getDefaultUsageParameterSet abstract method found in the SBB.");
428 String usageParameterInterfaceName = this.sbbDeploymentDescriptor.getUsageParametersInterface();
429 if (usageParameterInterfaceName == null){
430 logger.error("No Usage parameter found in the descriptor corresponding to the getDefaultSbbUsageParameterSet defined in the SBB!");
431 return false;
432 }
433
434 try {
435 String returnType = getDefaultSbbUsageParameterSetMethod.getReturnType().getName();
436 logger.debug("RETURN TYPE: " + returnType + " INTERFACE NAME: " + usageParameterInterfaceName);
437 if (returnType.compareTo(usageParameterInterfaceName) != 0) {
438 logger.error("The return type of getDefaultSbbUsageParameterSet defined in the SBB does not match the interface name in the descriptor!");
439 return false;
440 }
441 } catch (NotFoundException e) {
442 // TODO Auto-generated catch block
443 e.printStackTrace();
444 }
445
446 CtClass[] params = null ;
447 try {
448 params = getDefaultSbbUsageParameterSetMethod.getParameterTypes();
449 } catch (NotFoundException ex ) {
450
451 }
452 if (params != null && params.length != 0 ) {
453 logger.error("Unexpected parameter found" + params[0].getName());
454 return false;
455 }
456 abstractMethods.remove("getDefaultSbbUsageParameterSet");
457 }
458 logger.debug("getDefaultSbbUsageParameterSet ok");
459 //Named Usage Parameter method is generated by us.
460 CtMethod getSbbUsageParameterSet = (CtMethod) abstractMethods.get("getSbbUsageParameterSet");
461 if ( getSbbUsageParameterSet != null ) {
462 CtClass[] params = null;
463 try {
464 params = getSbbUsageParameterSet.getParameterTypes();
465 if ( params.length != 1 ){
466 logger.error("too many args!");
467 return false;
468 }
469 if ( ! (params[0].getName().equals(String.class.getName()))) {
470 logger.error("Arg type must be String!");
471 return false;
472 }
473 }catch (NotFoundException ex) {
474 logger.error("Expected parameter not found");
475 return false;
476 }
477 abstractMethods.remove("getSbbUsageParameterSet");
478 }
479 logger.debug("getSbbUsageParameterSet ok");
480 //Check if some methods have not been verfied
481 Iterator it=abstractMethods.keySet().iterator();
482 while(it.hasNext()){
483 logger.error("abstract method left: "+ it.next());
484
485 }
486 if(abstractMethods.size()!=0){
487 logger.error("Some methods have not been verified against the sbb descriptor" +
488 ", maybe these methods have not been described in the descriptor and so are not allowed");
489 return false;
490 }
491 abstractMethods=null;
492 logger.debug("SbbAbstractClass "+sbbAbstractClass.getName()+" follows the descriptor");
493 return true;
494 }
495 /**
496 * @param sbbAbstractClass
497 * @param abstractMethods
498 * @param superClassesAbstractMethods
499 * @return
500 */
501 private boolean checkProfileCMPMethods(CtClass sbbAbstractClass, Map abstractMethods, Map superClassesAbstractMethods) {
502 //Check the presence of the profile CMP methods
503 ProfileCMPMethod[] profileCMPMethods=
504 sbbDeploymentDescriptor.getProfileCMPMethods();
505 if(profileCMPMethods!=null){
506 for(int i=0;i<profileCMPMethods.length;i++){
507 String methodName=profileCMPMethods[i].getProfileCMPMethod();
508 CtMethod profileCMPMethod=(CtMethod)abstractMethods.get(methodName);
509 if(profileCMPMethod==null){
510 profileCMPMethod = (CtMethod)superClassesAbstractMethods.get(methodName);
511 if(profileCMPMethod == null){
512 logger.error("integrity compromised on sbbAbstractClass "+
513 sbbAbstractClass.getName()+" ProfileCMPMethod "+
514 methodName+" defined in the descriptor is missing");
515 return false;
516 }
517 }
518 else{
519 if(profileCMPMethod.getName().startsWith("sbb") ||
520 profileCMPMethod.getName().startsWith("ejb")){
521 logger.error("integrity compromised on sbbAbstractClass "+
522 sbbAbstractClass.getName()+" ProfileCMPMethod "+
523 methodName+" should not starts with sbb or ejb in its name");
524 return false;
525 }
526 CtClass[] parameters;
527 try {
528 parameters = profileCMPMethod.getParameterTypes();
529 if(parameters.length!=1){
530 logger.error("integrity compromised on sbbAbstractClass "+
531 sbbAbstractClass.getName()+" ProfileCMPMethod "+
532 methodName+" should have one and only argument " +
533 "of type javax.slee.profile.ProfileID");
534 return false;
535 }
536 else{
537 if(!parameters[0].getName().equals("javax.slee.profile.ProfileID")){
538 logger.error("integrity compromised on sbbAbstractClass "+
539 sbbAbstractClass.getName()+" ProfileCMPMethod "+
540 methodName+" should have one and only argument " +
541 "of type javax.slee.profile.ProfileID");
542 return false;
543 }
544 }
545 } catch (NotFoundException e) {
546 logger.error("integrity compromised on sbbAbstractClass "+
547 sbbAbstractClass.getName()+" ProfileCMPMethod "+
548 methodName+" should have one argument of type javax.slee.profile.ProfileID");
549 return false;
550 }
551 try {
552 CtClass[] exceptions= profileCMPMethod.getExceptionTypes();
553 if(exceptions.length<2){
554 logger.error("integrity compromised on sbbAbstractClass "+
555 sbbAbstractClass.getName()+" ProfileCMPMethod "+
556 methodName+" should have both exceptions " +
557 "of type javax.slee.profile.UnrecognizedProfileNameException and "+
558 "javax.slee.profile.UnrecognizedProfileTableNameException declared thrown");
559 return false;
560 }
561 else{
562 boolean profileNameExceptionThrown=false;
563 boolean profileTableNameExceptionThrown=false;
564 int j=0;
565 while(j<exceptions.length &&
566 (!profileNameExceptionThrown || !profileTableNameExceptionThrown)){
567 if(exceptions[j].getName().equals(
568 "javax.slee.profile.UnrecognizedProfileNameException"))
569 profileNameExceptionThrown=true;
570 if(exceptions[j].getName().equals(
571 "javax.slee.profile.UnrecognizedProfileNameException"))
572 profileTableNameExceptionThrown=true;
573 j++;
574 }
575 if(!profileNameExceptionThrown){
576 logger.error("integrity compromised on sbbAbstractClass "+
577 sbbAbstractClass.getName()+" ProfileCMPMethod "+
578 methodName+" should have this exception " +
579 "of type javax.slee.profile.UnrecognizedProfileNameException "+
580 "declared thrown");
581 return false;
582 }
583 if(!profileTableNameExceptionThrown){
584 logger.error("integrity compromised on sbbAbstractClass "+
585 sbbAbstractClass.getName()+" ProfileCMPMethod "+
586 methodName+" should have this exception " +
587 "of type javax.slee.profile.UnrecognizedProfileTableNameException "+
588 "declared thrown");
589 return false;
590 }
591 }
592 } catch (NotFoundException e) {
593 logger.error("integrity compromised on sbbAbstractClass "+
594 sbbAbstractClass.getName()+" ProfileCMPMethod "+
595 methodName+" should have both exceptions " +
596 "of type javax.slee.profile.UnrecognizedProfileNameException and "+
597 "javax.slee.profile.UnrecognizedProfileTableNameException declared thrown");
598 return false;
599 }
600 ComponentKey componentKey=profileCMPMethods[i].getProfileSpecKey();
601 //TODO check that the return type is equals to the profileCMP interface
602 //specified in the profile descriptor deployment
603 }
604 //The method has been verified so it is removed from the abstract method map
605 abstractMethods.remove(methodName);
606 }
607 }
608 logger.debug("profiles CMP methods ok");
609 return true;
610 }
611
612 /**
613 * Check that for the CMP fields defined in the sbbDeployment descriptor
614 * there is at least one accessor.
615 * If the CMP field has a getter :
616 * the getter should have a return type
617 * the getter should not have any parameters
618 * If the CMP field has a setter :
619 * the getter should not have a return type
620 * the getter should have one parameter
621 * @param abstractMethods the abstract Method of the abstract class
622 * @param cmpFields the CMP Fields to check
623 * @param sbbAbstractClass the sbb abstract class
624 * @return true if the CMP fields follow the constraints false otherwise
625 */
626 private boolean checkCMPFieldsAgainstDeploymentDescripor(Map abstractMethods,CMPField[] cmpFields,CtClass sbbAbstractClass) {
627 for(int i=0;i<cmpFields.length;i++){
628 String fieldName=cmpFields[i].getFieldName();
629 //Set the first char of the accessor to UpperCase to follow the javabean requirements
630 fieldName=fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
631 CtMethod setterAccessor=(CtMethod)abstractMethods.get("set"+fieldName);
632 CtMethod getterAccessor=(CtMethod)abstractMethods.get("get"+fieldName);
633 //check that the CMP field has at least one accessor
634 if(setterAccessor==null && getterAccessor==null){
635 logger.error("integrity compromised on sbbAbstractClass "+
636 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
637 " => accessor missing");
638 return false;
639 }
640 if(getterAccessor!=null){
641 //check that the getter accessor has a return type
642 try{
643 CtClass returnType=getterAccessor.getReturnType();
644 if(returnType.getName().equalsIgnoreCase("void")){
645 logger.error("integrity compromised on sbbAbstractClass "+
646 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
647 " => getter accessor has no return type");
648 return false;
649 }
650 }
651 catch(NotFoundException nfe){
652 logger.error("integrity compromised on sbbAbstractClass "+
653 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
654 " => getter accessor has no return type");
655 return false;
656 }
657 //check that the getter accessor has no parameters
658 try{
659 CtClass[] parameterTypes=getterAccessor.getParameterTypes();
660 if(parameterTypes!=null && parameterTypes.length>0){
661 logger.error("integrity compromised on sbbAbstractClass "+
662 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
663 " => getter accessor has some parameters");
664 return false;
665 }
666 }
667 catch(NotFoundException nfe){}
668 //The method has been verified so it is removed from the abstract method map
669 abstractMethods.remove(getterAccessor.getName());
670 }
671 if(setterAccessor!=null){
672 //check that the setter accessor has no return type
673 try{
674 CtClass returnType=setterAccessor.getReturnType();
675 if(!returnType.getName().equalsIgnoreCase("void")){
676 logger.error("integrity compromised on sbbAbstractClass "+
677 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
678 " => setter accessor has a return type "+returnType.getName());
679 return false;
680 }
681 }
682 catch(NotFoundException nfe){}
683 //check that the setter accessor has one parameter
684 try{
685 CtClass[] parameterTypes=setterAccessor.getParameterTypes();
686 if(parameterTypes.length!=1){
687 logger.error("integrity compromised on sbbAbstractClass "+
688 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
689 " => setter accessor has the wrong number of parameters");
690 return false;
691 }
692 }
693 catch(NotFoundException nfe){
694 logger.error("integrity compromised on sbbAbstractClass "+
695 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
696 " => setter accessor has no parameters");
697 return false;
698 }
699
700 try {
701 //check that getter return type == setter parameter type == xml type
702 CtClass getterReturnType = getterAccessor.getReturnType();
703 CtClass[] setterParamTypes = setterAccessor.getParameterTypes();
704
705 CtClass setterParamType = setterParamTypes[0];
706 if (!getterReturnType.equals(setterParamType)) {
707 logger.error("integrity compromised on sbbAbstractClass "+
708 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
709 " => getter return type is not same as setter parameter type");
710 return false;
711 }
712
713 if (cmpFields[i].getSbbComponentKey() != null) {
714
715 try {
716 //Then the getter return type, setter param type should be SbbLocalObject
717 logger.debug("Getter return type is: " + getterReturnType.getName());
718
719 //FIXME - This is a bit slow
720
721 Class cl = Thread.currentThread().getContextClassLoader().loadClass(getterReturnType.getName());
722 Class sbbLOClass = Thread.currentThread().getContextClassLoader().
723 loadClass("javax.slee.SbbLocalObject");
724
725 if (!sbbLOClass.isAssignableFrom(cl)) {
726 logger.error("integrity compromised on sbbAbstractClass "+
727 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
728 " => getter and setter types for an sbb ref must be SbbLocalObject");
729 return false;
730 }
731 } catch (Exception e) {
732 logger.error("Failed check ref param", e);
733 return false;
734 }
735 }
736 }
737 catch(NotFoundException nfe){
738 logger.error("integrity compromised on sbbAbstractClass "+
739 sbbAbstractClass.getName()+" on CMP Field "+fieldName+
740 " => getter/setter accessor has no parameters/return type");
741 return false;
742 }
743
744 //The method has been verified so it is removed from the abstract method map
745 abstractMethods.remove(setterAccessor.getName());
746 }
747 }
748 return true;
749 }
750
751 /**
752 * Check the event handler method signatures. The SBB developer must implement these. These must
753 * be recognized events in the slee else the Sbb is not valid.
754 *
755 * @param sbbAbstractClass -- The abstract class to check.
756 * @param serviceContainer -- service container in which the event descriptors are installed.
757 */
758 private boolean checkEventHandlerMethods
759 (CtClass sbbAbstractClass, SleeContainer serviceContainer) {
760
761 HashSet sbbEventEntries = this.sbbDeploymentDescriptor.getSbbEventEntries();
762
763 for ( Iterator it = sbbEventEntries.iterator(); it.hasNext(); ) {
764 SbbEventEntry sbbEventEntry = (SbbEventEntry) it.next();
765 String eventName = sbbEventEntry.getEventName();
766 // Dont need a method for FIRED only methods.
767 if ( sbbEventEntry.getEventDirection() == SbbEventEntry.FIRED ) continue;
768
769 ComponentKey ckey = sbbEventEntry.getEventTypeRefKey();
770 EventTypeIDImpl eventTypeID = serviceContainer.getEventType(ckey);
771 // Make sure that the slee knows about this event.
772 if ( eventTypeID == null){
773 logger.debug("event type id "+ eventName +" is unknown to the SLEE!");
774 return false;
775 }
776 String methodName = "on"+sbbEventEntry.getEventName();
777 EventTypeDescriptorImpl eventTypeDesc = serviceContainer.getEventDescriptor(eventTypeID);
778 String eventClass = eventTypeDesc.getEventClassName();
779 // Check if we have a method of the required name.
780 Set methodSet = ClassUtils.getPublicMethods(sbbAbstractClass);
781 //CtMethod[] methods = sbbAbstractClass.getMethods();
782
783 CtMethod[] methods = new CtMethod[methodSet.size()];
784 methodSet.toArray(methods);
785
786 int i ;
787 for ( i = 0; i < methods.length; i ++ ) {
788 if (methods[i].getName().equals(methodName)) break;
789 }
790
791 if ( i == methods.length ){
792 logger.debug("no methods to check against "+ methodName);
793 return false;
794 }
795 try {
796 if ( ((CtMethod) methods[i]).getReturnType() != CtClass.voidType ) {
797 this.errorString = "event handler must have void return type";
798 logger.debug(errorString);
799 return false;
800 }
801 CtClass[] parameters = ((CtMethod) methods[i]).getParameterTypes();
802 if ( parameters.length != 2 ) {
803 this.errorString = "bad method signature ( wrong number of params!)";
804 logger.debug(errorString);
805 return false;
806 }
807 CtClass param = parameters[0];
808
809 if ( ! param.getName().equals(eventClass) ) {
810 this.errorString = "bad event handler method signature expected " + eventClass;
811 logger.debug( errorString );
812 return false;
813 }
814 param = parameters[1];
815
816
817 if ( !param.getName().equals(ActivityContextInterface.class.getName())) {
818 this.errorString = "bad event handler method signature expected " + ActivityContextInterface.class.getName() ;
819 logger.debug( errorString );
820 return false;
821 }
822 } catch ( Exception ex ) {
823 ex.printStackTrace();
824 }
825 logger.debug("found an event handler " + ((CtMethod)methods[i]).getName());
826 }
827 return true;
828
829 }
830 }