1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.jdtaus.core.container.mojo;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.StringWriter;
27 import java.lang.reflect.Method;
28 import java.util.Collection;
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.LinkedList;
32 import java.util.Locale;
33 import java.util.Set;
34 import java.util.zip.GZIPInputStream;
35 import javax.xml.bind.JAXBException;
36 import org.apache.bcel.classfile.Attribute;
37 import org.apache.bcel.classfile.ClassParser;
38 import org.apache.bcel.classfile.Constant;
39 import org.apache.bcel.classfile.ConstantUtf8;
40 import org.apache.bcel.classfile.JavaClass;
41 import org.apache.bcel.classfile.Unknown;
42 import org.apache.maven.plugin.MojoExecutionException;
43 import org.apache.maven.plugin.MojoFailureException;
44 import org.jdtaus.core.container.ContainerError;
45 import org.jdtaus.core.container.ContextError;
46 import org.jdtaus.core.container.Dependencies;
47 import org.jdtaus.core.container.Dependency;
48 import org.jdtaus.core.container.Implementation;
49 import org.jdtaus.core.container.Implementations;
50 import org.jdtaus.core.container.MissingDependencyException;
51 import org.jdtaus.core.container.MissingImplementationException;
52 import org.jdtaus.core.container.MissingMessageException;
53 import org.jdtaus.core.container.MissingPropertyException;
54 import org.jdtaus.core.container.MissingSpecificationException;
55 import org.jdtaus.core.container.Model;
56 import org.jdtaus.core.container.ModelError;
57 import org.jdtaus.core.container.ModelFactory;
58 import org.jdtaus.core.container.Module;
59 import org.jdtaus.core.container.Modules;
60 import org.jdtaus.core.container.Property;
61 import org.jdtaus.core.container.Specification;
62 import org.jdtaus.core.container.Specifications;
63 import org.jdtaus.core.container.mojo.model.container.DependencyElement;
64 import org.jdtaus.core.container.mojo.model.container.ImplementationElement;
65 import org.jdtaus.core.container.mojo.model.container.MessageElement;
66 import org.jdtaus.core.container.mojo.model.container.ModelObject;
67 import org.jdtaus.core.container.mojo.model.container.ModuleElement;
68 import org.jdtaus.core.container.mojo.model.container.Multiplicity;
69 import org.jdtaus.core.container.mojo.model.container.PropertyElement;
70 import org.jdtaus.core.container.mojo.model.container.SpecificationElement;
71 import org.jdtaus.core.container.mojo.model.container.SpecificationsElement;
72
73
74
75
76
77
78
79
80
81
82 public class VerifyModelMojo extends AbstractContainerMojo
83 {
84
85
86
87 private boolean validModel;
88
89
90 public VerifyModelMojo()
91 {
92 super();
93 }
94
95 public void execute() throws MojoExecutionException, MojoFailureException
96 {
97
98 final ClassLoader mavenLoader =
99 Thread.currentThread().getContextClassLoader();
100
101 try
102 {
103 Thread.currentThread().setContextClassLoader(
104 this.getClassLoader( mavenLoader ) );
105
106 enableThreadContextClassLoader();
107
108 this.validModel = true;
109 this.assertValidModel( ModelFactory.getModel() );
110
111 if ( this.validModel )
112 {
113 this.getLog().info( VerifyModelMojoBundle.getInstance().
114 getValidModelMessage( Locale.getDefault() ) );
115
116 }
117 else
118 {
119 throw new MojoExecutionException(
120 VerifyModelMojoBundle.getInstance().
121 getModelViolationsMessage( Locale.getDefault() ) );
122
123 }
124 }
125 catch ( final ContextError e )
126 {
127 throw new MojoExecutionException( e.getMessage(), e );
128 }
129 catch ( final ContainerError e )
130 {
131 throw new MojoExecutionException( e.getMessage(), e );
132 }
133 catch ( final ModelError e )
134 {
135 throw new MojoExecutionException( e.getMessage(), e );
136 }
137 catch ( final Exception e )
138 {
139 throw new MojoExecutionException( e.getMessage(), e );
140 }
141 finally
142 {
143 disableThreadContextClassLoader();
144 Thread.currentThread().setContextClassLoader( mavenLoader );
145 }
146 }
147
148
149
150
151 protected ClassLoader getClassLoader( final ClassLoader parent )
152 throws Exception
153 {
154 return this.getRuntimeClassLoader( parent );
155 }
156
157 private void assertValidModel( final Model model )
158 throws IOException, ClassNotFoundException, JAXBException
159 {
160 final Specifications specs = model.getModules().getSpecifications();
161 for ( int i = specs.size() - 1; i >= 0; i-- )
162 {
163 final Specification spec = specs.getSpecification( i );
164 final Class specClass =
165 this.assertClassAvailable( spec.getIdentifier() );
166
167 if ( specClass != null )
168 {
169 this.assertCompatibleModel( spec, specClass );
170 }
171 }
172
173 final Implementations impls = model.getModules().getImplementations();
174 for ( int j = impls.size() - 1; j >= 0; j-- )
175 {
176 final Implementation impl = impls.getImplementation( j );
177 final Class clazz =
178 this.assertClassAvailable( impl.getIdentifier() );
179
180 if ( clazz != null )
181 {
182 this.assertImplementsAllSpecifications(
183 impl, model.getModules(), clazz );
184
185 this.assertCompatibleModel( model, impl, clazz );
186 }
187 }
188
189
190 final Dependencies unresolved = this.getUnresolvedDependencies( model );
191 final Set renderedSpecifications = new HashSet();
192
193 if ( unresolved.size() > 0 )
194 {
195 this.validModel = false;
196
197 this.getLog().error(
198 VerifyModelMojoBundle.getInstance().
199 getUnresolvedDependenciesMessage( Locale.getDefault() ) );
200
201 for ( int i = unresolved.size() - 1; i >= 0; i-- )
202 {
203 final Dependency dep = unresolved.getDependency( i );
204
205 if ( !renderedSpecifications.contains(
206 dep.getSpecification().getIdentifier() ) )
207 {
208 this.getLog().error(
209 " " + VerifyModelMojoBundle.getInstance().
210 getUnresolvedDependencyMessage(
211 Locale.getDefault(),
212 dep.getSpecification().getIdentifier(),
213 dep.getSpecification().getModuleName(),
214 dep.getSpecification().getVersion() ) );
215
216 renderedSpecifications.add(
217 dep.getSpecification().getIdentifier() );
218
219 }
220 }
221 }
222 }
223
224 private Class assertClassAvailable( final String className )
225 {
226 Class clazz = null;
227
228 try
229 {
230 clazz = Class.forName( className, true, Thread.currentThread().
231 getContextClassLoader() );
232
233 }
234 catch ( final ClassNotFoundException e )
235 {
236 this.validModel = false;
237
238 this.getLog().error(
239 VerifyModelMojoBundle.getInstance().
240 getClassNotFoundMessage( Locale.getDefault(), e.getMessage() ) );
241
242 clazz = null;
243 }
244
245 return clazz;
246 }
247
248 private void assertImplementsAllSpecifications(
249 final Implementation impl, final Modules modules, final Class clazz )
250 {
251 final Set allInterfaces = new HashSet();
252 this.getAllImplementedInterfaces( clazz, allInterfaces );
253 final Class[] interfaces = (Class[]) allInterfaces.toArray(
254 new Class[ allInterfaces.size() ] );
255
256 if ( impl.getImplementedSpecifications().size() > 0 )
257 {
258 for ( int i = interfaces.length - 1; i >= 0; i-- )
259 {
260 try
261 {
262 modules.getSpecification( interfaces[i].getName() ).
263 getImplementation( impl.getName() );
264
265 }
266 catch ( final MissingImplementationException e )
267 {
268 this.validModel = false;
269
270 this.getLog().error(
271 VerifyModelMojoBundle.getInstance().
272 getMissingImplementedSpecificationMessage(
273 Locale.getDefault(), impl.getIdentifier(),
274 interfaces[i].getName() ) );
275
276 }
277 catch ( final MissingSpecificationException e )
278 {
279
280
281 if ( this.getLog().isDebugEnabled() )
282 {
283 this.getLog().debug( e.getMessage() );
284 }
285 }
286 }
287 }
288
289 for ( int i = impl.getImplementedSpecifications().size() - 1; i >= 0;
290 i-- )
291 {
292 final Specification spec = impl.getImplementedSpecifications().
293 getSpecification( i );
294
295 final Class specClass =
296 this.assertClassAvailable( spec.getIdentifier() );
297
298 boolean isImplemented =
299 spec.getIdentifier().equals( impl.getIdentifier() );
300
301 for ( int j = interfaces.length - 1; j >= 0; j-- )
302 {
303 if ( interfaces[j].getName().equals( spec.getIdentifier() ) )
304 {
305 isImplemented = true;
306 break;
307 }
308 }
309
310 if ( !isImplemented )
311 {
312 final String methodName =
313 spec.getIdentifier().replace( '.', '_' );
314
315 try
316 {
317 final Method m =
318 clazz.getMethod( methodName, new Class[ 0 ] );
319
320 if ( m.getReturnType() != specClass )
321 {
322 this.validModel = false;
323
324 this.getLog().error(
325 VerifyModelMojoBundle.getInstance().
326 getMissingInterfaceMessage(
327 Locale.getDefault(), impl.getIdentifier(),
328 spec.getIdentifier() ) );
329
330 }
331 }
332 catch ( final NoSuchMethodException e )
333 {
334 this.validModel = false;
335
336 this.getLog().error(
337 VerifyModelMojoBundle.getInstance().
338 getMissingInterfaceMessage(
339 Locale.getDefault(), impl.getIdentifier(),
340 spec.getIdentifier() ) );
341
342 }
343 }
344 }
345 }
346
347
348
349
350
351
352
353 private void getAllImplementedInterfaces( final Class clazz,
354 final Set interfaces )
355 {
356 final Class[] current = clazz.getInterfaces();
357 for ( int i = current.length - 1; i >= 0; i-- )
358 {
359 this.getAllImplementedInterfaces( current[i], interfaces );
360 interfaces.add( current[i] );
361 }
362
363 if ( clazz.getSuperclass() != null )
364 {
365 this.getAllImplementedInterfaces(
366 clazz.getSuperclass(), interfaces );
367
368 }
369 }
370
371
372
373
374
375
376
377
378 private Dependencies getUnresolvedDependencies( final Model model )
379 {
380 final String unresolvedName = "Unresolved-";
381 final Collection deps = new LinkedList();
382
383 for ( int m = model.getModules().size() - 1; m >= 0; m-- )
384 {
385 final Module mod = model.getModules().getModule( m );
386
387 for ( int i = mod.getImplementations().size() - 1; i >= 0; i-- )
388 {
389 final Implementation impl = mod.getImplementations().
390 getImplementation( i );
391
392 for ( int d = impl.getDependencies().size() - 1; d >= 0; d-- )
393 {
394 final Dependency dep = (Dependency) impl.getDependencies().
395 getDependency( d ).clone();
396
397 if ( dep.getImplementation() == null &&
398 dep.getSpecification().getMultiplicity() ==
399 Specification.MULTIPLICITY_ONE &&
400 dep.getSpecification().getImplementations().
401 size() != 1 )
402 {
403 dep.setName(
404 unresolvedName + "-" + m + "-" + i + "-" + d );
405
406 deps.add( dep );
407 }
408 }
409 }
410 }
411
412 final Dependencies dependencies = new Dependencies();
413 dependencies.setDependencies(
414 (Dependency[]) deps.toArray( new Dependency[ deps.size() ] ) );
415
416 return dependencies;
417 }
418
419 private void assertCompatibleModel( final Model model,
420 final Implementation impl,
421 final Class clazz )
422 throws IOException, ClassNotFoundException, JAXBException
423 {
424 final ModuleElement committedModule =
425 this.extractImplementation( clazz );
426
427 if ( committedModule != null )
428 {
429 ImplementationElement committedImpl = null;
430 if ( committedModule.getImplementations() != null )
431 {
432 for ( final Iterator it = committedModule.getImplementations().
433 getImplementation().iterator(); it.hasNext(); )
434 {
435 final ImplementationElement i =
436 (ImplementationElement) it.next();
437
438 if ( i.getIdentifier().equals( impl.getIdentifier() ) )
439 {
440 committedImpl = i;
441 break;
442 }
443 }
444 }
445
446 if ( committedImpl != null )
447 {
448 if ( committedImpl.getDependencies() != null )
449 {
450 for ( final Iterator it = committedImpl.getDependencies().
451 getDependency().iterator(); it.hasNext(); )
452 {
453 final DependencyElement d =
454 (DependencyElement) it.next();
455
456 try
457 {
458 final Dependency specifiedDependency =
459 impl.getDependencies().getDependency(
460 d.getName() );
461
462 final Class committedSpec = Class.forName(
463 d.getIdentifier(), true, Thread.currentThread().
464 getContextClassLoader() );
465
466 final Class specifiedSpec = Class.forName(
467 specifiedDependency.getSpecification().
468 getIdentifier(), true, Thread.currentThread().
469 getContextClassLoader() );
470
471 if ( !specifiedSpec.isAssignableFrom( committedSpec ) )
472 {
473 this.getLog().error(
474 VerifyModelMojoBundle.getInstance().
475 getIllegalSpecificationMessage(
476 Locale.getDefault(), d.getName(),
477 impl.getIdentifier(),
478 specifiedDependency.getSpecification().
479 getIdentifier(), d.getIdentifier() ) );
480
481 this.validModel = false;
482 }
483 }
484 catch ( final MissingDependencyException e )
485 {
486 this.getLog().error(
487 VerifyModelMojoBundle.getInstance().
488 getMissingCommittedDependencyMessage(
489 Locale.getDefault(), d.getName(),
490 impl.getIdentifier() ) );
491
492 this.validModel = false;
493 }
494 }
495 }
496
497 if ( committedImpl.getProperties() != null )
498 {
499 for ( final Iterator it = committedImpl.getProperties().
500 getProperty().iterator(); it.hasNext(); )
501 {
502 final PropertyElement p = (PropertyElement) it.next();
503 try
504 {
505 final Class committedType =
506 this.getModelManager().getJavaType( p );
507
508 final Property specifiedProperty =
509 impl.getProperties().getProperty( p.getName() );
510
511 if ( !specifiedProperty.getType().
512 isAssignableFrom( committedType ) )
513 {
514 this.getLog().error(
515 VerifyModelMojoBundle.getInstance().
516 getIllegalPropertyMessage(
517 Locale.getDefault(), p.getName(),
518 impl.getIdentifier(),
519 specifiedProperty.getType().getName(),
520 committedType.getName() ) );
521
522 this.validModel = false;
523 }
524 }
525 catch ( final MissingPropertyException e )
526 {
527 this.getLog().error(
528 VerifyModelMojoBundle.getInstance().
529 getMissingCommittedPropertyMessage(
530 Locale.getDefault(), p.getName(),
531 impl.getIdentifier() ) );
532
533 this.validModel = false;
534 }
535 }
536 }
537
538 if ( committedImpl.getMessages() != null )
539 {
540 for ( final Iterator it = committedImpl.getMessages().
541 getMessage().iterator(); it.hasNext(); )
542 {
543 final MessageElement m = (MessageElement) it.next();
544 try
545 {
546 impl.getMessages().getMessage( m.getName() );
547 }
548 catch ( final MissingMessageException e )
549 {
550 this.getLog().error(
551 VerifyModelMojoBundle.getInstance().
552 getMissingCommittedMessageMessage(
553 Locale.getDefault(), m.getName(),
554 impl.getIdentifier() ) );
555
556 this.validModel = false;
557 }
558 }
559 }
560 }
561
562 if ( committedModule.getSpecifications() != null )
563 {
564 for ( final Iterator it = committedModule.getSpecifications().
565 getSpecification().iterator(); it.hasNext(); )
566 {
567 final SpecificationElement s = (SpecificationElement) it.next();
568
569 try
570 {
571 final Specification spec = model.getModules().
572 getSpecification( s.getIdentifier() );
573
574 final Multiplicity specifiedMultiplicity =
575 this.getModelManager().getMultiplicity( spec );
576
577 if ( !this.getModelManager().getMultiplicity( spec ).
578 equals( s.getMultiplicity() ) )
579 {
580 this.getLog().error( VerifyModelMojoBundle.getInstance().
581 getIllegalMultiplicityMessage(
582 Locale.getDefault(), s.getIdentifier(),
583 specifiedMultiplicity.getValue(),
584 s.getMultiplicity().getValue() ) );
585
586 this.validModel = false;
587 }
588 }
589 catch ( final MissingSpecificationException e )
590 {
591 this.getLog().debug( e.getMessage() );
592 }
593 }
594 }
595 }
596 else
597 {
598 this.getLog().debug( VerifyModelMojoBundle.getInstance().
599 getUncommittedMessage( Locale.getDefault(),
600 impl.getIdentifier() ) );
601
602 }
603 }
604
605 private void assertCompatibleModel( final Specification spec,
606 final Class clazz )
607 throws IOException, ClassNotFoundException, JAXBException
608 {
609 final SpecificationElement committedSpec =
610 this.extractSpecification( clazz );
611
612 if ( committedSpec != null )
613 {
614 final Multiplicity specifiedMultiplicity =
615 this.getModelManager().getMultiplicity( spec );
616
617 if ( !specifiedMultiplicity.equals(
618 committedSpec.getMultiplicity() ) )
619 {
620 this.getLog().error( VerifyModelMojoBundle.getInstance().
621 getIllegalMultiplicityMessage(
622 Locale.getDefault(),
623 committedSpec.getIdentifier(),
624 specifiedMultiplicity.getValue(),
625 committedSpec.getMultiplicity().getValue() ) );
626
627 this.validModel = false;
628 }
629 }
630 else
631 {
632 this.getLog().debug( VerifyModelMojoBundle.getInstance().
633 getUncommittedMessage( Locale.getDefault(),
634 spec.getIdentifier() ) );
635
636 }
637 }
638
639 private ModuleElement extractImplementation( final Class clazz )
640 throws IOException, ClassNotFoundException, JAXBException
641 {
642 return (ModuleElement) this.extractModelObject(
643 clazz, Module.class.getName() );
644
645 }
646
647 private SpecificationElement extractSpecification( final Class clazz )
648 throws IOException, ClassNotFoundException, JAXBException
649 {
650 return (SpecificationElement) this.extractModelObject(
651 clazz, Specification.class.getName() );
652
653 }
654
655 private SpecificationsElement extractSpecifications( final Class clazz )
656 throws IOException, ClassNotFoundException, JAXBException
657 {
658 return (SpecificationsElement) this.extractModelObject(
659 clazz, Specifications.class.getName() );
660
661 }
662
663 private ModelObject extractModelObject( final Class clazz,
664 final String attributeName )
665 throws IOException, ClassNotFoundException, JAXBException
666 {
667 byte[] data = null;
668 ModelObject e = null;
669
670 final String classLocation =
671 clazz.getName().replace( '.', '/' ) + ".class";
672
673 final InputStream classFile =
674 Thread.currentThread().getContextClassLoader().
675 getResourceAsStream( classLocation );
676
677 final ClassParser parser =
678 new ClassParser( classFile, classLocation );
679
680 final JavaClass javaClass = parser.parse();
681 final Attribute[] attributes = javaClass.getAttributes();
682
683 for ( int i = attributes.length - 1; i >= 0; i-- )
684 {
685 final Constant constant = javaClass.getConstantPool().
686 getConstant( attributes[i].getNameIndex() );
687
688 if ( constant instanceof ConstantUtf8 )
689 {
690 if ( attributeName.equals(
691 ( (ConstantUtf8) constant ).getBytes() ) )
692 {
693 if ( attributes[i] instanceof Unknown )
694 {
695 data = ( (Unknown) attributes[i] ).getBytes();
696 break;
697 }
698 }
699 }
700 }
701
702 if ( data != null )
703 {
704 e = (ModelObject) this.getModelManager().getContainerUnmarshaller().
705 unmarshal( new GZIPInputStream( new ByteArrayInputStream(
706 data ) ) );
707
708 if ( this.getLog().isDebugEnabled() )
709 {
710 final StringWriter writer = new StringWriter();
711 this.getModelManager().getContainerMarshaller().
712 marshal( e, writer );
713
714 this.getLog().debug( writer.toString() );
715 }
716 }
717
718 return e;
719 }
720
721
722 }