1 | /* |
2 | * Copyright (C) Christian Schulte, 2005-206 |
3 | * All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * |
9 | * o Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * |
12 | * o Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in |
14 | * the documentation and/or other materials provided with the |
15 | * distribution. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
18 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
19 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | * |
28 | * $JOMC: ClassFileProcessor.java 4890 2014-02-24 04:00:08Z schulte $ |
29 | * |
30 | */ |
31 | package org.jomc.tools; |
32 | |
33 | import java.io.ByteArrayInputStream; |
34 | import java.io.ByteArrayOutputStream; |
35 | import java.io.Closeable; |
36 | import java.io.File; |
37 | import java.io.FileInputStream; |
38 | import java.io.IOException; |
39 | import java.io.InputStream; |
40 | import java.io.RandomAccessFile; |
41 | import java.net.URL; |
42 | import java.nio.ByteBuffer; |
43 | import java.nio.channels.FileChannel; |
44 | import java.nio.channels.FileLock; |
45 | import java.text.MessageFormat; |
46 | import java.util.List; |
47 | import java.util.ResourceBundle; |
48 | import java.util.logging.Level; |
49 | import java.util.zip.GZIPInputStream; |
50 | import java.util.zip.GZIPOutputStream; |
51 | import javax.xml.bind.JAXBElement; |
52 | import javax.xml.bind.JAXBException; |
53 | import javax.xml.bind.Marshaller; |
54 | import javax.xml.bind.Unmarshaller; |
55 | import javax.xml.bind.util.JAXBResult; |
56 | import javax.xml.bind.util.JAXBSource; |
57 | import javax.xml.transform.Transformer; |
58 | import javax.xml.transform.TransformerException; |
59 | import javax.xml.validation.Schema; |
60 | import org.apache.bcel.classfile.Attribute; |
61 | import org.apache.bcel.classfile.ClassParser; |
62 | import org.apache.bcel.classfile.Constant; |
63 | import org.apache.bcel.classfile.ConstantPool; |
64 | import org.apache.bcel.classfile.ConstantUtf8; |
65 | import org.apache.bcel.classfile.JavaClass; |
66 | import org.apache.bcel.classfile.Unknown; |
67 | import org.jomc.model.Dependencies; |
68 | import org.jomc.model.Dependency; |
69 | import org.jomc.model.Implementation; |
70 | import org.jomc.model.Implementations; |
71 | import org.jomc.model.Message; |
72 | import org.jomc.model.Messages; |
73 | import org.jomc.model.ModelObject; |
74 | import org.jomc.model.ModelObjectException; |
75 | import org.jomc.model.Module; |
76 | import org.jomc.model.ObjectFactory; |
77 | import org.jomc.model.Properties; |
78 | import org.jomc.model.Property; |
79 | import org.jomc.model.Specification; |
80 | import org.jomc.model.SpecificationReference; |
81 | import org.jomc.model.Specifications; |
82 | import org.jomc.modlet.ModelContext; |
83 | import org.jomc.modlet.ModelException; |
84 | import org.jomc.modlet.ModelValidationReport; |
85 | import org.jomc.util.ParseException; |
86 | import org.jomc.util.TokenMgrError; |
87 | import org.jomc.util.VersionParser; |
88 | |
89 | /** |
90 | * Processes class files. |
91 | * |
92 | * <p><b>Use Cases:</b><br/><ul> |
93 | * <li>{@link #commitModelObjects(org.jomc.modlet.ModelContext, java.io.File) }</li> |
94 | * <li>{@link #commitModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) }</li> |
95 | * <li>{@link #commitModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) }</li> |
96 | * <li>{@link #commitModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) }</li> |
97 | * <li>{@link #validateModelObjects(org.jomc.modlet.ModelContext) }</li> |
98 | * <li>{@link #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext) }</li> |
99 | * <li>{@link #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext) }</li> |
100 | * <li>{@link #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext) }</li> |
101 | * <li>{@link #validateModelObjects(org.jomc.modlet.ModelContext, java.io.File) }</li> |
102 | * <li>{@link #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) }</li> |
103 | * <li>{@link #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) }</li> |
104 | * <li>{@link #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) }</li> |
105 | * <li>{@link #transformModelObjects(org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li> |
106 | * <li>{@link #transformModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li> |
107 | * <li>{@link #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li> |
108 | * <li>{@link #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li> |
109 | * </ul></p> |
110 | * |
111 | * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> |
112 | * @version $JOMC: ClassFileProcessor.java 4890 2014-02-24 04:00:08Z schulte $ |
113 | * |
114 | * @see #getModules() |
115 | */ |
116 | public class ClassFileProcessor extends JomcTool |
117 | { |
118 | |
119 | /** Empty byte array. */ |
120 | private static final byte[] NO_BYTES = |
121 | { |
122 | }; |
123 | |
124 | /** Creates a new {@code ClassFileProcessor} instance. */ |
125 | public ClassFileProcessor() |
126 | { |
127 | super(); |
128 | } |
129 | |
130 | /** |
131 | * Creates a new {@code ClassFileProcessor} instance taking a {@code ClassFileProcessor} instance to initialize the |
132 | * instance with. |
133 | * |
134 | * @param tool The instance to initialize the new instance with. |
135 | * |
136 | * @throws NullPointerException if {@code tool} is {@code null}. |
137 | * @throws IOException if copying {@code tool} fails. |
138 | */ |
139 | public ClassFileProcessor( final ClassFileProcessor tool ) throws IOException |
140 | { |
141 | super( tool ); |
142 | } |
143 | |
144 | /** |
145 | * Commits model objects of the modules of the instance to class files. |
146 | * |
147 | * @param context The model context to use for committing the model objects. |
148 | * @param classesDirectory The directory holding the class files. |
149 | * |
150 | * @throws NullPointerException if {@code context} or {@code classesDirectory} is {@code null}. |
151 | * @throws IOException if committing model objects fails. |
152 | * |
153 | * @see #commitModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) |
154 | */ |
155 | public final void commitModelObjects( final ModelContext context, final File classesDirectory ) throws IOException |
156 | { |
157 | if ( context == null ) |
158 | { |
159 | throw new NullPointerException( "context" ); |
160 | } |
161 | if ( classesDirectory == null ) |
162 | { |
163 | throw new NullPointerException( "classesDirectory" ); |
164 | } |
165 | |
166 | try |
167 | { |
168 | if ( this.getModules() != null ) |
169 | { |
170 | final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() ); |
171 | m.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
172 | |
173 | this.commitModelObjects( this.getModules().getSpecifications(), this.getModules().getImplementations(), |
174 | m, classesDirectory ); |
175 | |
176 | } |
177 | else if ( this.isLoggable( Level.WARNING ) ) |
178 | { |
179 | this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null ); |
180 | } |
181 | } |
182 | catch ( final ModelException e ) |
183 | { |
184 | // JDK: As of JDK 6, "new IOException( message, cause )". |
185 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
186 | } |
187 | } |
188 | |
189 | /** |
190 | * Commits model objects of a given module of the modules of the instance to class files. |
191 | * |
192 | * @param module The module to process. |
193 | * @param context The model context to use for committing the model objects. |
194 | * @param classesDirectory The directory holding the class files. |
195 | * |
196 | * @throws NullPointerException if {@code module}, {@code context} or {@code classesDirectory} is {@code null}. |
197 | * @throws IOException if committing model objects fails. |
198 | * |
199 | * @see #commitModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) |
200 | * @see #commitModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) |
201 | */ |
202 | public final void commitModelObjects( final Module module, final ModelContext context, final File classesDirectory ) |
203 | throws IOException |
204 | { |
205 | if ( module == null ) |
206 | { |
207 | throw new NullPointerException( "module" ); |
208 | } |
209 | if ( context == null ) |
210 | { |
211 | throw new NullPointerException( "context" ); |
212 | } |
213 | if ( classesDirectory == null ) |
214 | { |
215 | throw new NullPointerException( "classesDirectory" ); |
216 | } |
217 | |
218 | try |
219 | { |
220 | if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null ) |
221 | { |
222 | final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() ); |
223 | m.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
224 | |
225 | this.commitModelObjects( module.getSpecifications(), module.getImplementations(), m, classesDirectory ); |
226 | } |
227 | else if ( this.isLoggable( Level.WARNING ) ) |
228 | { |
229 | this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null ); |
230 | } |
231 | } |
232 | catch ( final ModelException e ) |
233 | { |
234 | // JDK: As of JDK 6, "new IOException( message, cause )". |
235 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
236 | } |
237 | } |
238 | |
239 | /** |
240 | * Commits model objects of a given specification of the modules of the instance to class files. |
241 | * |
242 | * @param specification The specification to process. |
243 | * @param context The model context to use for committing the model objects. |
244 | * @param classesDirectory The directory holding the class files. |
245 | * |
246 | * @throws NullPointerException if {@code specification}, {@code context} or {@code classesDirectory} is |
247 | * {@code null}. |
248 | * @throws IOException if committing model objects fails. |
249 | * |
250 | * @see #commitModelObjects(org.jomc.model.Specification, javax.xml.bind.Marshaller, org.apache.bcel.classfile.JavaClass) |
251 | */ |
252 | public final void commitModelObjects( final Specification specification, final ModelContext context, |
253 | final File classesDirectory ) throws IOException |
254 | { |
255 | if ( specification == null ) |
256 | { |
257 | throw new NullPointerException( "specification" ); |
258 | } |
259 | if ( context == null ) |
260 | { |
261 | throw new NullPointerException( "context" ); |
262 | } |
263 | if ( classesDirectory == null ) |
264 | { |
265 | throw new NullPointerException( "classesDirectory" ); |
266 | } |
267 | |
268 | try |
269 | { |
270 | if ( this.getModules() != null |
271 | && this.getModules().getSpecification( specification.getIdentifier() ) != null ) |
272 | { |
273 | final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() ); |
274 | m.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
275 | |
276 | this.commitModelObjects( specification, m, classesDirectory ); |
277 | } |
278 | else if ( this.isLoggable( Level.WARNING ) ) |
279 | { |
280 | this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null ); |
281 | } |
282 | } |
283 | catch ( final ModelException e ) |
284 | { |
285 | // JDK: As of JDK 6, "new IOException( message, cause )". |
286 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
287 | } |
288 | } |
289 | |
290 | /** |
291 | * Commits model objects of a given implementation of the modules of the instance to class files. |
292 | * |
293 | * @param implementation The implementation to process. |
294 | * @param context The model context to use for committing the model objects. |
295 | * @param classesDirectory The directory holding the class files. |
296 | * |
297 | * @throws NullPointerException if {@code implementation}, {@code context} or {@code classesDirectory} is |
298 | * {@code null}. |
299 | * @throws IOException if committing model objects fails. |
300 | * |
301 | * @see #commitModelObjects(org.jomc.model.Implementation, javax.xml.bind.Marshaller, org.apache.bcel.classfile.JavaClass) |
302 | */ |
303 | public final void commitModelObjects( final Implementation implementation, final ModelContext context, |
304 | final File classesDirectory ) throws IOException |
305 | { |
306 | if ( implementation == null ) |
307 | { |
308 | throw new NullPointerException( "implementation" ); |
309 | } |
310 | if ( context == null ) |
311 | { |
312 | throw new NullPointerException( "context" ); |
313 | } |
314 | if ( classesDirectory == null ) |
315 | { |
316 | throw new NullPointerException( "classesDirectory" ); |
317 | } |
318 | |
319 | try |
320 | { |
321 | if ( this.getModules() != null |
322 | && this.getModules().getImplementation( implementation.getIdentifier() ) != null ) |
323 | { |
324 | final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() ); |
325 | m.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
326 | |
327 | this.commitModelObjects( implementation, m, classesDirectory ); |
328 | } |
329 | else if ( this.isLoggable( Level.WARNING ) ) |
330 | { |
331 | this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null ); |
332 | } |
333 | } |
334 | catch ( final ModelException e ) |
335 | { |
336 | // JDK: As of JDK 6, "new IOException( message, cause )". |
337 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
338 | } |
339 | } |
340 | |
341 | /** |
342 | * Commits model objects of a given specification of the modules of the instance to a given class file. |
343 | * |
344 | * @param specification The specification to process. |
345 | * @param marshaller The marshaller to use for committing the model objects. |
346 | * @param javaClass The java class to commit to. |
347 | * |
348 | * @throws NullPointerException if {@code specification}, {@code marshaller} or {@code javaClass} is {@code null}. |
349 | * @throws IOException if committing model objects fails. |
350 | */ |
351 | public void commitModelObjects( final Specification specification, final Marshaller marshaller, |
352 | final JavaClass javaClass ) throws IOException |
353 | { |
354 | if ( specification == null ) |
355 | { |
356 | throw new NullPointerException( "specification" ); |
357 | } |
358 | if ( marshaller == null ) |
359 | { |
360 | throw new NullPointerException( "marshaller" ); |
361 | } |
362 | if ( javaClass == null ) |
363 | { |
364 | throw new NullPointerException( "javaClass" ); |
365 | } |
366 | |
367 | if ( this.getModules() != null |
368 | && this.getModules().getSpecification( specification.getIdentifier() ) != null ) |
369 | { |
370 | this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject( |
371 | marshaller, new ObjectFactory().createSpecification( specification ) ) ); |
372 | |
373 | } |
374 | else if ( this.isLoggable( Level.WARNING ) ) |
375 | { |
376 | this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null ); |
377 | } |
378 | } |
379 | |
380 | /** |
381 | * Commits model objects of a given implementation of the modules of the instance to a given class file. |
382 | * |
383 | * @param implementation The implementation to process. |
384 | * @param marshaller The marshaller to use for committing the model objects. |
385 | * @param javaClass The java class to commit to. |
386 | * |
387 | * @throws NullPointerException if {@code implementation}, {@code marshaller} or {@code javaClass} is {@code null}. |
388 | * @throws IOException if committing model objects fails. |
389 | */ |
390 | public void commitModelObjects( final Implementation implementation, final Marshaller marshaller, |
391 | final JavaClass javaClass ) throws IOException |
392 | { |
393 | if ( implementation == null ) |
394 | { |
395 | throw new NullPointerException( "implementation" ); |
396 | } |
397 | if ( marshaller == null ) |
398 | { |
399 | throw new NullPointerException( "marshaller" ); |
400 | } |
401 | if ( javaClass == null ) |
402 | { |
403 | throw new NullPointerException( "javaClass" ); |
404 | } |
405 | |
406 | if ( this.getModules() != null |
407 | && this.getModules().getImplementation( implementation.getIdentifier() ) != null ) |
408 | { |
409 | final ObjectFactory of = new ObjectFactory(); |
410 | |
411 | Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() ); |
412 | if ( dependencies == null ) |
413 | { |
414 | dependencies = new Dependencies(); |
415 | } |
416 | |
417 | Properties properties = this.getModules().getProperties( implementation.getIdentifier() ); |
418 | if ( properties == null ) |
419 | { |
420 | properties = new Properties(); |
421 | } |
422 | |
423 | Messages messages = this.getModules().getMessages( implementation.getIdentifier() ); |
424 | if ( messages == null ) |
425 | { |
426 | messages = new Messages(); |
427 | } |
428 | |
429 | Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() ); |
430 | if ( specifications == null ) |
431 | { |
432 | specifications = new Specifications(); |
433 | } |
434 | |
435 | for ( int i = 0, s0 = specifications.getReference().size(); i < s0; i++ ) |
436 | { |
437 | final SpecificationReference r = specifications.getReference().get( i ); |
438 | |
439 | if ( specifications.getSpecification( r.getIdentifier() ) == null && this.isLoggable( Level.WARNING ) ) |
440 | { |
441 | this.log( Level.WARNING, getMessage( "unresolvedSpecification", r.getIdentifier(), |
442 | implementation.getIdentifier() ), null ); |
443 | |
444 | } |
445 | } |
446 | |
447 | for ( int i = 0, s0 = dependencies.getDependency().size(); i < s0; i++ ) |
448 | { |
449 | final Dependency d = dependencies.getDependency().get( i ); |
450 | final Specification s = this.getModules().getSpecification( d.getIdentifier() ); |
451 | |
452 | if ( s != null ) |
453 | { |
454 | if ( specifications.getSpecification( s.getIdentifier() ) == null ) |
455 | { |
456 | specifications.getSpecification().add( s ); |
457 | } |
458 | } |
459 | else if ( this.isLoggable( Level.WARNING ) ) |
460 | { |
461 | this.log( Level.WARNING, getMessage( "unresolvedDependencySpecification", d.getIdentifier(), |
462 | d.getName(), implementation.getIdentifier() ), null ); |
463 | |
464 | } |
465 | } |
466 | |
467 | this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject( |
468 | marshaller, of.createDependencies( dependencies ) ) ); |
469 | |
470 | this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject( |
471 | marshaller, of.createProperties( properties ) ) ); |
472 | |
473 | this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject( |
474 | marshaller, of.createMessages( messages ) ) ); |
475 | |
476 | this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject( |
477 | marshaller, of.createSpecifications( specifications ) ) ); |
478 | |
479 | } |
480 | else if ( this.isLoggable( Level.WARNING ) ) |
481 | { |
482 | this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null ); |
483 | } |
484 | } |
485 | |
486 | /** |
487 | * Validates model objects of class files of the modules of the instance. |
488 | * |
489 | * @param context The model context to use for validating model objects. |
490 | * |
491 | * @return The report of the validation or {@code null}, if no model objects are found. |
492 | * |
493 | * @throws NullPointerException if {@code context} is {@code null}. |
494 | * @throws IOException if validating model objects fails. |
495 | * |
496 | * @see #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext) |
497 | */ |
498 | public final ModelValidationReport validateModelObjects( final ModelContext context ) throws IOException |
499 | { |
500 | if ( context == null ) |
501 | { |
502 | throw new NullPointerException( "context" ); |
503 | } |
504 | |
505 | try |
506 | { |
507 | ModelValidationReport report = null; |
508 | |
509 | if ( this.getModules() != null ) |
510 | { |
511 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
512 | u.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
513 | report = this.validateModelObjects( this.getModules().getSpecifications(), |
514 | this.getModules().getImplementations(), u, context ); |
515 | |
516 | } |
517 | else if ( this.isLoggable( Level.WARNING ) ) |
518 | { |
519 | this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null ); |
520 | } |
521 | |
522 | return report; |
523 | } |
524 | catch ( final ModelException e ) |
525 | { |
526 | // JDK: As of JDK 6, "new IOException( message, cause )". |
527 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
528 | } |
529 | } |
530 | |
531 | /** |
532 | * Validates model objects of class files of a given module of the modules of the instance. |
533 | * |
534 | * @param module The module to process. |
535 | * @param context The model context to use for validating model objects. |
536 | * |
537 | * @return The report of the validation or {@code null}, if no model objects are found. |
538 | * |
539 | * @throws NullPointerException if {@code module} or {@code context} is {@code null}. |
540 | * @throws IOException if validating model objects fails. |
541 | * |
542 | * @see #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext) |
543 | * @see #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext) |
544 | */ |
545 | public final ModelValidationReport validateModelObjects( final Module module, final ModelContext context ) |
546 | throws IOException |
547 | { |
548 | if ( module == null ) |
549 | { |
550 | throw new NullPointerException( "module" ); |
551 | } |
552 | if ( context == null ) |
553 | { |
554 | throw new NullPointerException( "context" ); |
555 | } |
556 | |
557 | try |
558 | { |
559 | ModelValidationReport report = null; |
560 | |
561 | if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null ) |
562 | { |
563 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
564 | u.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
565 | report = this.validateModelObjects( module.getSpecifications(), module.getImplementations(), u, |
566 | context ); |
567 | |
568 | } |
569 | else if ( this.isLoggable( Level.WARNING ) ) |
570 | { |
571 | this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null ); |
572 | } |
573 | |
574 | return report; |
575 | } |
576 | catch ( final ModelException e ) |
577 | { |
578 | // JDK: As of JDK 6, "new IOException( message, cause )". |
579 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
580 | } |
581 | } |
582 | |
583 | /** |
584 | * Validates model objects of class files of a given specification of the modules of the instance. |
585 | * |
586 | * @param specification The specification to process. |
587 | * @param context The model context to use for validating model objects. |
588 | * |
589 | * @return The report of the validation or {@code null}, if no model objects are found. |
590 | * |
591 | * @throws NullPointerException if {@code specification} or {@code context} is {@code null}. |
592 | * |
593 | * @throws IOException if validating model objects fails. |
594 | * |
595 | * @see #validateModelObjects(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass) |
596 | */ |
597 | public final ModelValidationReport validateModelObjects( final Specification specification, |
598 | final ModelContext context ) throws IOException |
599 | { |
600 | if ( specification == null ) |
601 | { |
602 | throw new NullPointerException( "specification" ); |
603 | } |
604 | if ( context == null ) |
605 | { |
606 | throw new NullPointerException( "context" ); |
607 | } |
608 | |
609 | try |
610 | { |
611 | ModelValidationReport report = null; |
612 | |
613 | if ( this.getModules() != null |
614 | && this.getModules().getSpecification( specification.getIdentifier() ) != null ) |
615 | { |
616 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
617 | u.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
618 | report = this.validateModelObjects( specification, u, context ); |
619 | } |
620 | else if ( this.isLoggable( Level.WARNING ) ) |
621 | { |
622 | this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null ); |
623 | } |
624 | |
625 | return report; |
626 | } |
627 | catch ( final ModelException e ) |
628 | { |
629 | // JDK: As of JDK 6, "new IOException( message, cause )". |
630 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
631 | } |
632 | } |
633 | |
634 | /** |
635 | * Validates model objects of class files of a given implementation of the modules of the instance. |
636 | * |
637 | * @param implementation The implementation to process. |
638 | * @param context The model context to use for validating model objects. |
639 | * |
640 | * @return The report of the validation or {@code null}, if no model objects are found. |
641 | * |
642 | * @throws NullPointerException if {@code implementation} or {@code context} is {@code null}. |
643 | * |
644 | * @throws IOException if validating model objects fails. |
645 | * |
646 | * @see #validateModelObjects(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass) |
647 | */ |
648 | public final ModelValidationReport validateModelObjects( final Implementation implementation, |
649 | final ModelContext context ) throws IOException |
650 | { |
651 | if ( implementation == null ) |
652 | { |
653 | throw new NullPointerException( "implementation" ); |
654 | } |
655 | if ( context == null ) |
656 | { |
657 | throw new NullPointerException( "context" ); |
658 | } |
659 | |
660 | try |
661 | { |
662 | ModelValidationReport report = null; |
663 | |
664 | if ( this.getModules() != null |
665 | && this.getModules().getImplementation( implementation.getIdentifier() ) != null ) |
666 | { |
667 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
668 | u.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
669 | report = this.validateModelObjects( implementation, u, context ); |
670 | } |
671 | else if ( this.isLoggable( Level.WARNING ) ) |
672 | { |
673 | this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null ); |
674 | } |
675 | |
676 | return report; |
677 | } |
678 | catch ( final ModelException e ) |
679 | { |
680 | // JDK: As of JDK 6, "new IOException( message, cause )". |
681 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
682 | } |
683 | } |
684 | |
685 | /** |
686 | * Validates model objects of class files of the modules of the instance. |
687 | * |
688 | * @param context The model context to use for validating model objects. |
689 | * @param classesDirectory The directory holding the class files. |
690 | * |
691 | * @return The report of the validation or {@code null}, if no model objects are found. |
692 | * |
693 | * @throws NullPointerException if {@code context} or {@code classesDirectory} is {@code null}. |
694 | * @throws IOException if validating model objects fails. |
695 | * |
696 | * @see #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) |
697 | */ |
698 | public final ModelValidationReport validateModelObjects( final ModelContext context, final File classesDirectory ) |
699 | throws IOException |
700 | { |
701 | if ( context == null ) |
702 | { |
703 | throw new NullPointerException( "context" ); |
704 | } |
705 | if ( classesDirectory == null ) |
706 | { |
707 | throw new NullPointerException( "classesDirectory" ); |
708 | } |
709 | |
710 | try |
711 | { |
712 | ModelValidationReport report = null; |
713 | |
714 | if ( this.getModules() != null ) |
715 | { |
716 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
717 | u.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
718 | report = this.validateModelObjects( this.getModules().getSpecifications(), |
719 | this.getModules().getImplementations(), u, classesDirectory ); |
720 | |
721 | } |
722 | else if ( this.isLoggable( Level.WARNING ) ) |
723 | { |
724 | this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null ); |
725 | } |
726 | |
727 | return report; |
728 | } |
729 | catch ( final ModelException e ) |
730 | { |
731 | // JDK: As of JDK 6, "new IOException( message, cause )". |
732 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
733 | } |
734 | } |
735 | |
736 | /** |
737 | * Validates model objects of class files of a given module of the modules of the instance. |
738 | * |
739 | * @param module The module to process. |
740 | * @param context The model context to use for validating model objects. |
741 | * @param classesDirectory The directory holding the class files. |
742 | * |
743 | * @return The report of the validation or {@code null}, if no model objects are found. |
744 | * |
745 | * @throws NullPointerException if {@code module}, {@code context} or {@code classesDirectory} is {@code null}. |
746 | * @throws IOException if validating model objects fails. |
747 | * |
748 | * @see #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) |
749 | * @see #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) |
750 | */ |
751 | public final ModelValidationReport validateModelObjects( final Module module, final ModelContext context, |
752 | final File classesDirectory ) throws IOException |
753 | { |
754 | if ( module == null ) |
755 | { |
756 | throw new NullPointerException( "module" ); |
757 | } |
758 | if ( context == null ) |
759 | { |
760 | throw new NullPointerException( "context" ); |
761 | } |
762 | if ( classesDirectory == null ) |
763 | { |
764 | throw new NullPointerException( "classesDirectory" ); |
765 | } |
766 | |
767 | try |
768 | { |
769 | ModelValidationReport report = null; |
770 | |
771 | if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null ) |
772 | { |
773 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
774 | u.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
775 | report = this.validateModelObjects( module.getSpecifications(), module.getImplementations(), u, |
776 | classesDirectory ); |
777 | |
778 | } |
779 | else if ( this.isLoggable( Level.WARNING ) ) |
780 | { |
781 | this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null ); |
782 | } |
783 | |
784 | return report; |
785 | } |
786 | catch ( final ModelException e ) |
787 | { |
788 | // JDK: As of JDK 6, "new IOException( message, cause )". |
789 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
790 | } |
791 | } |
792 | |
793 | /** |
794 | * Validates model objects of class files of a given specification of the modules of the instance. |
795 | * |
796 | * @param specification The specification to process. |
797 | * @param context The model context to use for validating model objects. |
798 | * @param classesDirectory The directory holding the class files. |
799 | * |
800 | * @return The report of the validation or {@code null}, if no model objects are found. |
801 | * |
802 | * @throws NullPointerException if {@code specification}, {@code context} or {@code classesDirectory} is |
803 | * {@code null}. |
804 | * |
805 | * @throws IOException if validating model objects fails. |
806 | * |
807 | * @see #validateModelObjects(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass) |
808 | */ |
809 | public final ModelValidationReport validateModelObjects( final Specification specification, |
810 | final ModelContext context, final File classesDirectory ) |
811 | throws IOException |
812 | { |
813 | if ( specification == null ) |
814 | { |
815 | throw new NullPointerException( "specification" ); |
816 | } |
817 | if ( context == null ) |
818 | { |
819 | throw new NullPointerException( "context" ); |
820 | } |
821 | if ( classesDirectory == null ) |
822 | { |
823 | throw new NullPointerException( "classesDirectory" ); |
824 | } |
825 | |
826 | try |
827 | { |
828 | ModelValidationReport report = null; |
829 | |
830 | if ( this.getModules() != null |
831 | && this.getModules().getSpecification( specification.getIdentifier() ) != null ) |
832 | { |
833 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
834 | u.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
835 | report = this.validateModelObjects( specification, u, classesDirectory ); |
836 | } |
837 | else if ( this.isLoggable( Level.WARNING ) ) |
838 | { |
839 | this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null ); |
840 | } |
841 | |
842 | return report; |
843 | } |
844 | catch ( final ModelException e ) |
845 | { |
846 | // JDK: As of JDK 6, "new IOException( message, cause )". |
847 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
848 | } |
849 | } |
850 | |
851 | /** |
852 | * Validates model objects of class files of a given implementation of the modules of the instance. |
853 | * |
854 | * @param implementation The implementation to process. |
855 | * @param context The model context to use for validating model objects. |
856 | * @param classesDirectory The directory holding the class files. |
857 | * |
858 | * @return The report of the validation or {@code null}, if no model objects are found. |
859 | * |
860 | * @throws NullPointerException if {@code implementation}, {@code context} or {@code classesDirectory} is |
861 | * {@code null}. |
862 | * |
863 | * @throws IOException if validating model objects fails. |
864 | * |
865 | * @see #validateModelObjects(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass) |
866 | */ |
867 | public final ModelValidationReport validateModelObjects( final Implementation implementation, |
868 | final ModelContext context, final File classesDirectory ) |
869 | throws IOException |
870 | { |
871 | if ( implementation == null ) |
872 | { |
873 | throw new NullPointerException( "implementation" ); |
874 | } |
875 | if ( context == null ) |
876 | { |
877 | throw new NullPointerException( "context" ); |
878 | } |
879 | if ( classesDirectory == null ) |
880 | { |
881 | throw new NullPointerException( "classesDirectory" ); |
882 | } |
883 | |
884 | try |
885 | { |
886 | ModelValidationReport report = null; |
887 | |
888 | if ( this.getModules() != null |
889 | && this.getModules().getImplementation( implementation.getIdentifier() ) != null ) |
890 | { |
891 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
892 | u.setSchema( context.createSchema( this.getModel().getIdentifier() ) ); |
893 | report = this.validateModelObjects( implementation, u, classesDirectory ); |
894 | } |
895 | else if ( this.isLoggable( Level.WARNING ) ) |
896 | { |
897 | this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null ); |
898 | } |
899 | |
900 | return report; |
901 | } |
902 | catch ( final ModelException e ) |
903 | { |
904 | // JDK: As of JDK 6, "new IOException( message, cause )". |
905 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
906 | } |
907 | } |
908 | |
909 | /** |
910 | * Validates model objects of a given specification of the modules of the instance. |
911 | * |
912 | * @param specification The specification to process. |
913 | * @param unmarshaller The unmarshaller to use for validating model objects. |
914 | * @param javaClass The java class to validate. |
915 | * |
916 | * @return The report of the validation or {@code null}, if no model objects are found. |
917 | * |
918 | * @throws NullPointerException if {@code specification}, {@code unmarshaller} or {@code javaClass} is {@code null}. |
919 | * @throws IOException if validating model objects fails. |
920 | */ |
921 | public ModelValidationReport validateModelObjects( final Specification specification, |
922 | final Unmarshaller unmarshaller, final JavaClass javaClass ) |
923 | throws IOException |
924 | { |
925 | if ( specification == null ) |
926 | { |
927 | throw new NullPointerException( "specification" ); |
928 | } |
929 | if ( unmarshaller == null ) |
930 | { |
931 | throw new NullPointerException( "unmarshaller" ); |
932 | } |
933 | if ( javaClass == null ) |
934 | { |
935 | throw new NullPointerException( "javaClass" ); |
936 | } |
937 | |
938 | ModelValidationReport report = null; |
939 | |
940 | if ( this.getModules() != null && this.getModules().getSpecification( specification.getIdentifier() ) != null ) |
941 | { |
942 | report = new ModelValidationReport(); |
943 | |
944 | Specification decoded = null; |
945 | final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() ); |
946 | if ( bytes != null ) |
947 | { |
948 | decoded = this.decodeModelObject( unmarshaller, bytes, Specification.class ); |
949 | } |
950 | |
951 | if ( decoded != null ) |
952 | { |
953 | if ( decoded.getMultiplicity() != specification.getMultiplicity() ) |
954 | { |
955 | report.getDetails().add( new ModelValidationReport.Detail( |
956 | "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage( |
957 | "illegalMultiplicity", specification.getIdentifier(), |
958 | specification.getMultiplicity().value(), |
959 | decoded.getMultiplicity().value() ), |
960 | new ObjectFactory().createSpecification( specification ) ) ); |
961 | |
962 | } |
963 | |
964 | if ( decoded.getScope() == null |
965 | ? specification.getScope() != null |
966 | : !decoded.getScope().equals( specification.getScope() ) ) |
967 | { |
968 | report.getDetails().add( new ModelValidationReport.Detail( |
969 | "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage( |
970 | "illegalScope", specification.getIdentifier(), |
971 | specification.getScope() == null ? "Multiton" : specification.getScope(), |
972 | decoded.getScope() == null ? "Multiton" : decoded.getScope() ), |
973 | new ObjectFactory().createSpecification( specification ) ) ); |
974 | |
975 | } |
976 | |
977 | if ( decoded.getClazz() == null |
978 | ? specification.getClazz() != null |
979 | : !decoded.getClazz().equals( specification.getClazz() ) ) |
980 | { |
981 | report.getDetails().add( new ModelValidationReport.Detail( |
982 | "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage( |
983 | "illegalSpecificationClass", decoded.getIdentifier(), |
984 | specification.getClazz(), decoded.getClazz() ), |
985 | new ObjectFactory().createSpecification( specification ) ) ); |
986 | |
987 | } |
988 | } |
989 | else if ( this.isLoggable( Level.WARNING ) ) |
990 | { |
991 | this.log( Level.WARNING, getMessage( "cannotValidateSpecification", specification.getIdentifier(), |
992 | Specification.class.getName() ), null ); |
993 | |
994 | } |
995 | } |
996 | else if ( this.isLoggable( Level.WARNING ) ) |
997 | { |
998 | this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null ); |
999 | } |
1000 | |
1001 | return report; |
1002 | } |
1003 | |
1004 | /** |
1005 | * Validates model objects of a given implementation of the modules of the instance. |
1006 | * |
1007 | * @param implementation The implementation to process. |
1008 | * @param unmarshaller The unmarshaller to use for validating model objects. |
1009 | * @param javaClass The java class to validate. |
1010 | * |
1011 | * @return The report of the validation or {@code null}, if no model objects are found. |
1012 | * |
1013 | * @throws NullPointerException if {@code implementation}, {@code unmarshaller} or {@code javaClass} is {@code null}. |
1014 | * @throws IOException if validating model objects fails. |
1015 | */ |
1016 | public ModelValidationReport validateModelObjects( final Implementation implementation, |
1017 | final Unmarshaller unmarshaller, final JavaClass javaClass ) |
1018 | throws IOException |
1019 | { |
1020 | if ( implementation == null ) |
1021 | { |
1022 | throw new NullPointerException( "implementation" ); |
1023 | } |
1024 | if ( unmarshaller == null ) |
1025 | { |
1026 | throw new NullPointerException( "unmarshaller" ); |
1027 | } |
1028 | if ( javaClass == null ) |
1029 | { |
1030 | throw new NullPointerException( "javaClass" ); |
1031 | } |
1032 | |
1033 | try |
1034 | { |
1035 | ModelValidationReport report = null; |
1036 | |
1037 | if ( this.getModules() != null |
1038 | && this.getModules().getImplementation( implementation.getIdentifier() ) != null ) |
1039 | { |
1040 | report = new ModelValidationReport(); |
1041 | Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() ); |
1042 | if ( dependencies == null ) |
1043 | { |
1044 | dependencies = new Dependencies(); |
1045 | } |
1046 | |
1047 | Properties properties = this.getModules().getProperties( implementation.getIdentifier() ); |
1048 | if ( properties == null ) |
1049 | { |
1050 | properties = new Properties(); |
1051 | } |
1052 | |
1053 | Messages messages = this.getModules().getMessages( implementation.getIdentifier() ); |
1054 | if ( messages == null ) |
1055 | { |
1056 | messages = new Messages(); |
1057 | } |
1058 | |
1059 | Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() ); |
1060 | if ( specifications == null ) |
1061 | { |
1062 | specifications = new Specifications(); |
1063 | } |
1064 | |
1065 | Dependencies decodedDependencies = null; |
1066 | byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() ); |
1067 | if ( bytes != null ) |
1068 | { |
1069 | decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class ); |
1070 | } |
1071 | |
1072 | Properties decodedProperties = null; |
1073 | bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() ); |
1074 | if ( bytes != null ) |
1075 | { |
1076 | decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class ); |
1077 | } |
1078 | |
1079 | Messages decodedMessages = null; |
1080 | bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() ); |
1081 | if ( bytes != null ) |
1082 | { |
1083 | decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class ); |
1084 | } |
1085 | |
1086 | Specifications decodedSpecifications = null; |
1087 | bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() ); |
1088 | if ( bytes != null ) |
1089 | { |
1090 | decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class ); |
1091 | } |
1092 | |
1093 | if ( decodedDependencies != null ) |
1094 | { |
1095 | for ( int i = 0, s0 = decodedDependencies.getDependency().size(); i < s0; i++ ) |
1096 | { |
1097 | final Dependency decodedDependency = decodedDependencies.getDependency().get( i ); |
1098 | final Dependency dependency = dependencies.getDependency( decodedDependency.getName() ); |
1099 | final Specification s = this.getModules().getSpecification( decodedDependency.getIdentifier() ); |
1100 | |
1101 | if ( dependency == null ) |
1102 | { |
1103 | report.getDetails().add( new ModelValidationReport.Detail( |
1104 | "CLASS_MISSING_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage( |
1105 | "missingDependency", implementation.getIdentifier(), decodedDependency.getName() ), |
1106 | new ObjectFactory().createImplementation( implementation ) ) ); |
1107 | |
1108 | } |
1109 | else if ( decodedDependency.getImplementationName() != null |
1110 | && dependency.getImplementationName() == null ) |
1111 | { |
1112 | report.getDetails().add( new ModelValidationReport.Detail( |
1113 | "CLASS_MISSING_DEPENDENCY_IMPLEMENTATION_NAME", Level.SEVERE, getMessage( |
1114 | "missingDependencyImplementationName", implementation.getIdentifier(), |
1115 | decodedDependency.getName() ), |
1116 | new ObjectFactory().createImplementation( implementation ) ) ); |
1117 | |
1118 | } |
1119 | |
1120 | if ( s != null && s.getVersion() != null && decodedDependency.getVersion() != null |
1121 | && VersionParser.compare( decodedDependency.getVersion(), s.getVersion() ) > 0 ) |
1122 | { |
1123 | final Module moduleOfSpecification = |
1124 | this.getModules().getModuleOfSpecification( s.getIdentifier() ); |
1125 | |
1126 | final Module moduleOfImplementation = |
1127 | this.getModules().getModuleOfImplementation( implementation.getIdentifier() ); |
1128 | |
1129 | report.getDetails().add( new ModelValidationReport.Detail( |
1130 | "CLASS_INCOMPATIBLE_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage( |
1131 | "incompatibleDependency", javaClass.getClassName(), |
1132 | moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(), |
1133 | s.getIdentifier(), |
1134 | moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(), |
1135 | decodedDependency.getVersion(), s.getVersion() ), |
1136 | new ObjectFactory().createImplementation( implementation ) ) ); |
1137 | |
1138 | } |
1139 | } |
1140 | } |
1141 | else if ( this.isLoggable( Level.WARNING ) ) |
1142 | { |
1143 | this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(), |
1144 | Dependencies.class.getName() ), null ); |
1145 | |
1146 | } |
1147 | |
1148 | if ( decodedProperties != null ) |
1149 | { |
1150 | for ( int i = 0, s0 = decodedProperties.getProperty().size(); i < s0; i++ ) |
1151 | { |
1152 | final Property decodedProperty = decodedProperties.getProperty().get( i ); |
1153 | final Property property = properties.getProperty( decodedProperty.getName() ); |
1154 | |
1155 | if ( property == null ) |
1156 | { |
1157 | report.getDetails().add( new ModelValidationReport.Detail( |
1158 | "CLASS_MISSING_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage( |
1159 | "missingProperty", implementation.getIdentifier(), decodedProperty.getName() ), |
1160 | new ObjectFactory().createImplementation( implementation ) ) ); |
1161 | |
1162 | } |
1163 | else if ( decodedProperty.getType() == null |
1164 | ? property.getType() != null |
1165 | : !decodedProperty.getType().equals( property.getType() ) ) |
1166 | { |
1167 | report.getDetails().add( new ModelValidationReport.Detail( |
1168 | "CLASS_ILLEGAL_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage( |
1169 | "illegalPropertyType", implementation.getIdentifier(), decodedProperty.getName(), |
1170 | property.getType() == null ? "<>" : property.getType(), |
1171 | decodedProperty.getType() == null ? "<>" : decodedProperty.getType() ), |
1172 | new ObjectFactory().createImplementation( implementation ) ) ); |
1173 | |
1174 | } |
1175 | } |
1176 | } |
1177 | else if ( this.isLoggable( Level.WARNING ) ) |
1178 | { |
1179 | this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(), |
1180 | Properties.class.getName() ), null ); |
1181 | |
1182 | } |
1183 | |
1184 | if ( decodedMessages != null ) |
1185 | { |
1186 | for ( int i = 0, s0 = decodedMessages.getMessage().size(); i < s0; i++ ) |
1187 | { |
1188 | final Message decodedMessage = decodedMessages.getMessage().get( i ); |
1189 | final Message message = messages.getMessage( decodedMessage.getName() ); |
1190 | |
1191 | if ( message == null ) |
1192 | { |
1193 | report.getDetails().add( new ModelValidationReport.Detail( |
1194 | "CLASS_MISSING_IMPLEMENTATION_MESSAGE", Level.SEVERE, getMessage( |
1195 | "missingMessage", implementation.getIdentifier(), decodedMessage.getName() ), |
1196 | new ObjectFactory().createImplementation( implementation ) ) ); |
1197 | |
1198 | } |
1199 | } |
1200 | } |
1201 | else if ( this.isLoggable( Level.WARNING ) ) |
1202 | { |
1203 | this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(), |
1204 | Messages.class.getName() ), null ); |
1205 | |
1206 | } |
1207 | |
1208 | if ( decodedSpecifications != null ) |
1209 | { |
1210 | for ( int i = 0, s0 = decodedSpecifications.getSpecification().size(); i < s0; i++ ) |
1211 | { |
1212 | final Specification decodedSpecification = decodedSpecifications.getSpecification().get( i ); |
1213 | final Specification specification = |
1214 | this.getModules().getSpecification( decodedSpecification.getIdentifier() ); |
1215 | |
1216 | if ( specification == null ) |
1217 | { |
1218 | report.getDetails().add( new ModelValidationReport.Detail( |
1219 | "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage( |
1220 | "missingSpecification", implementation.getIdentifier(), |
1221 | decodedSpecification.getIdentifier() ), |
1222 | new ObjectFactory().createImplementation( implementation ) ) ); |
1223 | |
1224 | } |
1225 | else |
1226 | { |
1227 | if ( decodedSpecification.getMultiplicity() != specification.getMultiplicity() ) |
1228 | { |
1229 | report.getDetails().add( new ModelValidationReport.Detail( |
1230 | "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage( |
1231 | "illegalMultiplicity", specification.getIdentifier(), |
1232 | specification.getMultiplicity().value(), |
1233 | decodedSpecification.getMultiplicity().value() ), |
1234 | new ObjectFactory().createImplementation( implementation ) ) ); |
1235 | |
1236 | } |
1237 | |
1238 | if ( decodedSpecification.getScope() == null |
1239 | ? specification.getScope() != null |
1240 | : !decodedSpecification.getScope().equals( specification.getScope() ) ) |
1241 | { |
1242 | report.getDetails().add( new ModelValidationReport.Detail( |
1243 | "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage( |
1244 | "illegalScope", decodedSpecification.getIdentifier(), |
1245 | specification.getScope() == null ? "Multiton" : specification.getScope(), |
1246 | decodedSpecification.getScope() == null |
1247 | ? "Multiton" |
1248 | : decodedSpecification.getScope() ), |
1249 | new ObjectFactory().createImplementation( implementation ) ) ); |
1250 | |
1251 | } |
1252 | |
1253 | if ( decodedSpecification.getClazz() == null |
1254 | ? specification.getClazz() != null |
1255 | : !decodedSpecification.getClazz().equals( specification.getClazz() ) ) |
1256 | { |
1257 | report.getDetails().add( new ModelValidationReport.Detail( |
1258 | "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage( |
1259 | "illegalSpecificationClass", decodedSpecification.getIdentifier(), |
1260 | specification.getClazz(), decodedSpecification.getClazz() ), |
1261 | new ObjectFactory().createImplementation( implementation ) ) ); |
1262 | |
1263 | } |
1264 | } |
1265 | } |
1266 | |
1267 | for ( int i = 0, s0 = decodedSpecifications.getReference().size(); i < s0; i++ ) |
1268 | { |
1269 | final SpecificationReference decodedReference = decodedSpecifications.getReference().get( i ); |
1270 | final Specification specification = |
1271 | specifications.getSpecification( decodedReference.getIdentifier() ); |
1272 | |
1273 | if ( specification == null ) |
1274 | { |
1275 | report.getDetails().add( new ModelValidationReport.Detail( |
1276 | "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage( |
1277 | "missingSpecification", implementation.getIdentifier(), |
1278 | decodedReference.getIdentifier() ), |
1279 | new ObjectFactory().createImplementation( implementation ) ) ); |
1280 | |
1281 | } |
1282 | else if ( decodedReference.getVersion() != null && specification.getVersion() != null |
1283 | && VersionParser.compare( decodedReference.getVersion(), |
1284 | specification.getVersion() ) != 0 ) |
1285 | { |
1286 | final Module moduleOfSpecification = |
1287 | this.getModules().getModuleOfSpecification( decodedReference.getIdentifier() ); |
1288 | |
1289 | final Module moduleOfImplementation = |
1290 | this.getModules().getModuleOfImplementation( implementation.getIdentifier() ); |
1291 | |
1292 | report.getDetails().add( new ModelValidationReport.Detail( |
1293 | "CLASS_INCOMPATIBLE_IMPLEMENTATION", Level.SEVERE, getMessage( |
1294 | "incompatibleImplementation", javaClass.getClassName(), |
1295 | moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(), |
1296 | specification.getIdentifier(), |
1297 | moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(), |
1298 | decodedReference.getVersion(), specification.getVersion() ), |
1299 | new ObjectFactory().createImplementation( implementation ) ) ); |
1300 | |
1301 | } |
1302 | } |
1303 | } |
1304 | else if ( this.isLoggable( Level.WARNING ) ) |
1305 | { |
1306 | this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(), |
1307 | Specifications.class.getName() ), null ); |
1308 | |
1309 | } |
1310 | } |
1311 | else if ( this.isLoggable( Level.WARNING ) ) |
1312 | { |
1313 | this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null ); |
1314 | } |
1315 | |
1316 | return report; |
1317 | } |
1318 | catch ( final ParseException e ) |
1319 | { |
1320 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1321 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
1322 | } |
1323 | catch ( final TokenMgrError e ) |
1324 | { |
1325 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1326 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
1327 | } |
1328 | } |
1329 | |
1330 | /** |
1331 | * Transforms model objects of class files of the modules of the instance. |
1332 | * |
1333 | * @param context The model context to use for transforming model objects. |
1334 | * @param classesDirectory The directory holding the class files. |
1335 | * @param transformers The transformers to use for transforming model objects. |
1336 | * |
1337 | * @throws NullPointerException if {@code context}, {@code classesDirectory} or {@code transformers} is |
1338 | * {@code null}. |
1339 | * @throws IOException if transforming model objects fails. |
1340 | * |
1341 | * @see #transformModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File, java.util.List) |
1342 | */ |
1343 | public final void transformModelObjects( final ModelContext context, final File classesDirectory, |
1344 | final List<Transformer> transformers ) throws IOException |
1345 | { |
1346 | if ( context == null ) |
1347 | { |
1348 | throw new NullPointerException( "context" ); |
1349 | } |
1350 | if ( classesDirectory == null ) |
1351 | { |
1352 | throw new NullPointerException( "classesDirectory" ); |
1353 | } |
1354 | if ( transformers == null ) |
1355 | { |
1356 | throw new NullPointerException( "transformers" ); |
1357 | } |
1358 | if ( !classesDirectory.isDirectory() ) |
1359 | { |
1360 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
1361 | } |
1362 | |
1363 | try |
1364 | { |
1365 | if ( this.getModules() != null ) |
1366 | { |
1367 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
1368 | final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() ); |
1369 | final Schema s = context.createSchema( this.getModel().getIdentifier() ); |
1370 | u.setSchema( s ); |
1371 | m.setSchema( s ); |
1372 | |
1373 | this.transformModelObjects( this.getModules().getSpecifications(), |
1374 | this.getModules().getImplementations(), |
1375 | u, m, classesDirectory, transformers ); |
1376 | |
1377 | } |
1378 | else if ( this.isLoggable( Level.WARNING ) ) |
1379 | { |
1380 | this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null ); |
1381 | } |
1382 | } |
1383 | catch ( final ModelException e ) |
1384 | { |
1385 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1386 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
1387 | } |
1388 | } |
1389 | |
1390 | /** |
1391 | * Transforms model objects of class files of a given module of the modules of the instance. |
1392 | * |
1393 | * @param module The module to process. |
1394 | * @param context The model context to use for transforming model objects. |
1395 | * @param classesDirectory The directory holding the class files. |
1396 | * @param transformers The transformers to use for transforming the model objects. |
1397 | * |
1398 | * @throws NullPointerException if {@code module}, {@code context}, {@code classesDirectory} or {@code transformers} |
1399 | * is {@code null}. |
1400 | * @throws IOException if transforming model objects fails. |
1401 | * |
1402 | * @see #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) |
1403 | * @see #transformModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File, java.util.List) |
1404 | */ |
1405 | public final void transformModelObjects( final Module module, final ModelContext context, |
1406 | final File classesDirectory, final List<Transformer> transformers ) |
1407 | throws IOException |
1408 | { |
1409 | if ( module == null ) |
1410 | { |
1411 | throw new NullPointerException( "module" ); |
1412 | } |
1413 | if ( context == null ) |
1414 | { |
1415 | throw new NullPointerException( "context" ); |
1416 | } |
1417 | if ( classesDirectory == null ) |
1418 | { |
1419 | throw new NullPointerException( "classesDirectory" ); |
1420 | } |
1421 | if ( transformers == null ) |
1422 | { |
1423 | throw new NullPointerException( "transformers" ); |
1424 | } |
1425 | if ( !classesDirectory.isDirectory() ) |
1426 | { |
1427 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
1428 | } |
1429 | |
1430 | try |
1431 | { |
1432 | if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null ) |
1433 | { |
1434 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
1435 | final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() ); |
1436 | final Schema s = context.createSchema( this.getModel().getIdentifier() ); |
1437 | u.setSchema( s ); |
1438 | m.setSchema( s ); |
1439 | |
1440 | this.transformModelObjects( module.getSpecifications(), module.getImplementations(), u, m, |
1441 | classesDirectory, transformers ); |
1442 | |
1443 | } |
1444 | else if ( this.isLoggable( Level.WARNING ) ) |
1445 | { |
1446 | this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null ); |
1447 | } |
1448 | } |
1449 | catch ( final ModelException e ) |
1450 | { |
1451 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1452 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
1453 | } |
1454 | } |
1455 | |
1456 | /** |
1457 | * Transforms model objects of class files of a given specification of the modules of the instance. |
1458 | * |
1459 | * @param specification The specification to process. |
1460 | * @param context The model context to use for transforming model objects. |
1461 | * @param classesDirectory The directory holding the class files. |
1462 | * @param transformers The transformers to use for transforming the model objects. |
1463 | * |
1464 | * @throws NullPointerException if {@code specification}, {@code context}, {@code classesDirectory} or |
1465 | * {@code transformers} is {@code null}. |
1466 | * @throws IOException if transforming model objects fails. |
1467 | * |
1468 | * @see #transformModelObjects(org.jomc.model.Specification, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List) |
1469 | */ |
1470 | public final void transformModelObjects( final Specification specification, final ModelContext context, |
1471 | final File classesDirectory, final List<Transformer> transformers ) |
1472 | throws IOException |
1473 | { |
1474 | if ( specification == null ) |
1475 | { |
1476 | throw new NullPointerException( "specification" ); |
1477 | } |
1478 | if ( context == null ) |
1479 | { |
1480 | throw new NullPointerException( "context" ); |
1481 | } |
1482 | if ( classesDirectory == null ) |
1483 | { |
1484 | throw new NullPointerException( "classesDirectory" ); |
1485 | } |
1486 | if ( transformers == null ) |
1487 | { |
1488 | throw new NullPointerException( "transformers" ); |
1489 | } |
1490 | if ( !classesDirectory.isDirectory() ) |
1491 | { |
1492 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
1493 | } |
1494 | |
1495 | try |
1496 | { |
1497 | if ( this.getModules() != null |
1498 | && this.getModules().getSpecification( specification.getIdentifier() ) != null ) |
1499 | { |
1500 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
1501 | final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() ); |
1502 | final Schema s = context.createSchema( this.getModel().getIdentifier() ); |
1503 | u.setSchema( s ); |
1504 | m.setSchema( s ); |
1505 | |
1506 | this.transformModelObjects( specification, m, u, classesDirectory, transformers ); |
1507 | } |
1508 | else if ( this.isLoggable( Level.WARNING ) ) |
1509 | { |
1510 | this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null ); |
1511 | } |
1512 | } |
1513 | catch ( final ModelException e ) |
1514 | { |
1515 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1516 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
1517 | } |
1518 | } |
1519 | |
1520 | /** |
1521 | * Transforms model objects of class files of a given implementation of the modules of the instance. |
1522 | * |
1523 | * @param implementation The implementation to process. |
1524 | * @param context The model context to use for transforming model objects. |
1525 | * @param classesDirectory The directory holding the class files. |
1526 | * @param transformers The transformers to use for transforming the model objects. |
1527 | * |
1528 | * @throws NullPointerException if {@code implementation}, {@code context}, {@code classesDirectory} or |
1529 | * {@code transformers} is {@code null}. |
1530 | * @throws IOException if transforming model objects fails. |
1531 | * |
1532 | * @see #transformModelObjects(org.jomc.model.Implementation, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List) |
1533 | */ |
1534 | public final void transformModelObjects( final Implementation implementation, final ModelContext context, |
1535 | final File classesDirectory, final List<Transformer> transformers ) |
1536 | throws IOException |
1537 | { |
1538 | if ( implementation == null ) |
1539 | { |
1540 | throw new NullPointerException( "implementation" ); |
1541 | } |
1542 | if ( context == null ) |
1543 | { |
1544 | throw new NullPointerException( "context" ); |
1545 | } |
1546 | if ( classesDirectory == null ) |
1547 | { |
1548 | throw new NullPointerException( "classesDirectory" ); |
1549 | } |
1550 | if ( transformers == null ) |
1551 | { |
1552 | throw new NullPointerException( "transformers" ); |
1553 | } |
1554 | if ( !classesDirectory.isDirectory() ) |
1555 | { |
1556 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
1557 | } |
1558 | |
1559 | try |
1560 | { |
1561 | if ( this.getModules() != null |
1562 | && this.getModules().getImplementation( implementation.getIdentifier() ) != null ) |
1563 | { |
1564 | final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() ); |
1565 | final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() ); |
1566 | final Schema s = context.createSchema( this.getModel().getIdentifier() ); |
1567 | u.setSchema( s ); |
1568 | m.setSchema( s ); |
1569 | |
1570 | this.transformModelObjects( implementation, m, u, classesDirectory, transformers ); |
1571 | } |
1572 | else if ( this.isLoggable( Level.WARNING ) ) |
1573 | { |
1574 | this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null ); |
1575 | } |
1576 | } |
1577 | catch ( final ModelException e ) |
1578 | { |
1579 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1580 | throw (IOException) new IOException( getMessage( e ) ).initCause( e ); |
1581 | } |
1582 | } |
1583 | |
1584 | /** |
1585 | * Transforms model objects of a given specification of the modules of the instance. |
1586 | * |
1587 | * @param specification The specification to process. |
1588 | * @param marshaller The marshaller to use for transforming model objects. |
1589 | * @param unmarshaller The unmarshaller to use for transforming model objects. |
1590 | * @param javaClass The java class to transform model objects of. |
1591 | * @param transformers The transformers to use for transforming the model objects. |
1592 | * |
1593 | * @throws NullPointerException if {@code specification}, {@code marshaller}, {@code unmarshaller}, |
1594 | * {@code javaClass} or {@code transformers} is {@code null}. |
1595 | * @throws IOException if transforming model objects fails. |
1596 | */ |
1597 | public void transformModelObjects( final Specification specification, final Marshaller marshaller, |
1598 | final Unmarshaller unmarshaller, final JavaClass javaClass, |
1599 | final List<Transformer> transformers ) throws IOException |
1600 | { |
1601 | if ( specification == null ) |
1602 | { |
1603 | throw new NullPointerException( "specification" ); |
1604 | } |
1605 | if ( marshaller == null ) |
1606 | { |
1607 | throw new NullPointerException( "marshaller" ); |
1608 | } |
1609 | if ( unmarshaller == null ) |
1610 | { |
1611 | throw new NullPointerException( "unmarshaller" ); |
1612 | } |
1613 | if ( javaClass == null ) |
1614 | { |
1615 | throw new NullPointerException( "javaClass" ); |
1616 | } |
1617 | if ( transformers == null ) |
1618 | { |
1619 | throw new NullPointerException( "transformers" ); |
1620 | } |
1621 | |
1622 | try |
1623 | { |
1624 | if ( this.getModules() != null |
1625 | && this.getModules().getSpecification( specification.getIdentifier() ) != null ) |
1626 | { |
1627 | Specification decodedSpecification = null; |
1628 | final ObjectFactory objectFactory = new ObjectFactory(); |
1629 | final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() ); |
1630 | if ( bytes != null ) |
1631 | { |
1632 | decodedSpecification = this.decodeModelObject( unmarshaller, bytes, Specification.class ); |
1633 | } |
1634 | |
1635 | if ( decodedSpecification != null ) |
1636 | { |
1637 | for ( int i = 0, l = transformers.size(); i < l; i++ ) |
1638 | { |
1639 | final JAXBSource source = |
1640 | new JAXBSource( marshaller, objectFactory.createSpecification( decodedSpecification ) ); |
1641 | |
1642 | final JAXBResult result = new JAXBResult( unmarshaller ); |
1643 | transformers.get( i ).transform( source, result ); |
1644 | |
1645 | if ( result.getResult() instanceof JAXBElement<?> |
1646 | && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Specification ) |
1647 | { |
1648 | decodedSpecification = (Specification) ( (JAXBElement<?>) result.getResult() ).getValue(); |
1649 | } |
1650 | else |
1651 | { |
1652 | throw new IOException( getMessage( |
1653 | "illegalSpecificationTransformationResult", specification.getIdentifier() ) ); |
1654 | |
1655 | } |
1656 | } |
1657 | |
1658 | this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject( |
1659 | marshaller, |
1660 | objectFactory.createSpecification( decodedSpecification ) ) ); |
1661 | |
1662 | } |
1663 | } |
1664 | else if ( this.isLoggable( Level.WARNING ) ) |
1665 | { |
1666 | this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null ); |
1667 | } |
1668 | } |
1669 | catch ( final JAXBException e ) |
1670 | { |
1671 | String message = getMessage( e ); |
1672 | if ( message == null && e.getLinkedException() != null ) |
1673 | { |
1674 | message = getMessage( e.getLinkedException() ); |
1675 | } |
1676 | |
1677 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1678 | throw (IOException) new IOException( message ).initCause( e ); |
1679 | } |
1680 | catch ( final TransformerException e ) |
1681 | { |
1682 | String message = getMessage( e ); |
1683 | if ( message == null && e.getException() != null ) |
1684 | { |
1685 | message = getMessage( e.getException() ); |
1686 | } |
1687 | |
1688 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1689 | throw (IOException) new IOException( message ).initCause( e ); |
1690 | } |
1691 | } |
1692 | |
1693 | /** |
1694 | * Transforms model objects of a given implementation of the modules of the instance. |
1695 | * |
1696 | * @param implementation The implementation to process. |
1697 | * @param marshaller The marshaller to use for transforming model objects. |
1698 | * @param unmarshaller The unmarshaller to use for transforming model objects. |
1699 | * @param javaClass The java class to transform model object of. |
1700 | * @param transformers The transformers to use for transforming the model objects. |
1701 | * |
1702 | * @throws NullPointerException if {@code implementation}, {@code marshaller}, {@code unmarshaller}, |
1703 | * {@code javaClass} or {@code transformers} is {@code null}. |
1704 | * @throws IOException if transforming model objects fails. |
1705 | */ |
1706 | public void transformModelObjects( final Implementation implementation, final Marshaller marshaller, |
1707 | final Unmarshaller unmarshaller, final JavaClass javaClass, |
1708 | final List<Transformer> transformers ) throws IOException |
1709 | { |
1710 | if ( implementation == null ) |
1711 | { |
1712 | throw new NullPointerException( "implementation" ); |
1713 | } |
1714 | if ( marshaller == null ) |
1715 | { |
1716 | throw new NullPointerException( "marshaller" ); |
1717 | } |
1718 | if ( unmarshaller == null ) |
1719 | { |
1720 | throw new NullPointerException( "unmarshaller" ); |
1721 | } |
1722 | if ( javaClass == null ) |
1723 | { |
1724 | throw new NullPointerException( "javaClass" ); |
1725 | } |
1726 | if ( transformers == null ) |
1727 | { |
1728 | throw new NullPointerException( "transformers" ); |
1729 | } |
1730 | |
1731 | try |
1732 | { |
1733 | if ( this.getModules() != null |
1734 | && this.getModules().getImplementation( implementation.getIdentifier() ) != null ) |
1735 | { |
1736 | Dependencies decodedDependencies = null; |
1737 | byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() ); |
1738 | if ( bytes != null ) |
1739 | { |
1740 | decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class ); |
1741 | } |
1742 | |
1743 | Messages decodedMessages = null; |
1744 | bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() ); |
1745 | if ( bytes != null ) |
1746 | { |
1747 | decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class ); |
1748 | } |
1749 | |
1750 | Properties decodedProperties = null; |
1751 | bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() ); |
1752 | if ( bytes != null ) |
1753 | { |
1754 | decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class ); |
1755 | } |
1756 | |
1757 | Specifications decodedSpecifications = null; |
1758 | bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() ); |
1759 | if ( bytes != null ) |
1760 | { |
1761 | decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class ); |
1762 | } |
1763 | |
1764 | final ObjectFactory of = new ObjectFactory(); |
1765 | for ( int i = 0, l = transformers.size(); i < l; i++ ) |
1766 | { |
1767 | final Transformer transformer = transformers.get( i ); |
1768 | |
1769 | if ( decodedDependencies != null ) |
1770 | { |
1771 | final JAXBSource source = |
1772 | new JAXBSource( marshaller, of.createDependencies( decodedDependencies ) ); |
1773 | |
1774 | final JAXBResult result = new JAXBResult( unmarshaller ); |
1775 | transformer.transform( source, result ); |
1776 | |
1777 | if ( result.getResult() instanceof JAXBElement<?> |
1778 | && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Dependencies ) |
1779 | { |
1780 | decodedDependencies = (Dependencies) ( (JAXBElement<?>) result.getResult() ).getValue(); |
1781 | } |
1782 | else |
1783 | { |
1784 | throw new IOException( getMessage( |
1785 | "illegalImplementationTransformationResult", implementation.getIdentifier() ) ); |
1786 | |
1787 | } |
1788 | } |
1789 | |
1790 | if ( decodedMessages != null ) |
1791 | { |
1792 | final JAXBSource source = new JAXBSource( marshaller, of.createMessages( decodedMessages ) ); |
1793 | final JAXBResult result = new JAXBResult( unmarshaller ); |
1794 | transformer.transform( source, result ); |
1795 | |
1796 | if ( result.getResult() instanceof JAXBElement<?> |
1797 | && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Messages ) |
1798 | { |
1799 | decodedMessages = (Messages) ( (JAXBElement<?>) result.getResult() ).getValue(); |
1800 | } |
1801 | else |
1802 | { |
1803 | throw new IOException( getMessage( |
1804 | "illegalImplementationTransformationResult", implementation.getIdentifier() ) ); |
1805 | |
1806 | } |
1807 | } |
1808 | |
1809 | if ( decodedProperties != null ) |
1810 | { |
1811 | final JAXBSource source = |
1812 | new JAXBSource( marshaller, of.createProperties( decodedProperties ) ); |
1813 | |
1814 | final JAXBResult result = new JAXBResult( unmarshaller ); |
1815 | transformer.transform( source, result ); |
1816 | |
1817 | if ( result.getResult() instanceof JAXBElement<?> |
1818 | && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Properties ) |
1819 | { |
1820 | decodedProperties = (Properties) ( (JAXBElement<?>) result.getResult() ).getValue(); |
1821 | } |
1822 | else |
1823 | { |
1824 | throw new IOException( getMessage( |
1825 | "illegalImplementationTransformationResult", implementation.getIdentifier() ) ); |
1826 | |
1827 | } |
1828 | } |
1829 | |
1830 | if ( decodedSpecifications != null ) |
1831 | { |
1832 | final JAXBSource source = |
1833 | new JAXBSource( marshaller, of.createSpecifications( decodedSpecifications ) ); |
1834 | |
1835 | final JAXBResult result = new JAXBResult( unmarshaller ); |
1836 | transformer.transform( source, result ); |
1837 | |
1838 | if ( result.getResult() instanceof JAXBElement<?> |
1839 | && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Specifications ) |
1840 | { |
1841 | decodedSpecifications = (Specifications) ( (JAXBElement<?>) result.getResult() ).getValue(); |
1842 | } |
1843 | else |
1844 | { |
1845 | throw new IOException( getMessage( |
1846 | "illegalImplementationTransformationResult", implementation.getIdentifier() ) ); |
1847 | |
1848 | } |
1849 | } |
1850 | } |
1851 | |
1852 | if ( decodedDependencies != null ) |
1853 | { |
1854 | this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject( |
1855 | marshaller, of.createDependencies( decodedDependencies ) ) ); |
1856 | |
1857 | } |
1858 | |
1859 | if ( decodedMessages != null ) |
1860 | { |
1861 | this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject( |
1862 | marshaller, of.createMessages( decodedMessages ) ) ); |
1863 | |
1864 | } |
1865 | |
1866 | if ( decodedProperties != null ) |
1867 | { |
1868 | this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject( |
1869 | marshaller, of.createProperties( decodedProperties ) ) ); |
1870 | |
1871 | } |
1872 | |
1873 | if ( decodedSpecifications != null ) |
1874 | { |
1875 | this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject( |
1876 | marshaller, of.createSpecifications( decodedSpecifications ) ) ); |
1877 | |
1878 | } |
1879 | } |
1880 | else if ( this.isLoggable( Level.WARNING ) ) |
1881 | { |
1882 | this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null ); |
1883 | } |
1884 | } |
1885 | catch ( final JAXBException e ) |
1886 | { |
1887 | String message = getMessage( e ); |
1888 | if ( message == null && e.getLinkedException() != null ) |
1889 | { |
1890 | message = getMessage( e.getLinkedException() ); |
1891 | } |
1892 | |
1893 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1894 | throw (IOException) new IOException( message ).initCause( e ); |
1895 | } |
1896 | catch ( final TransformerException e ) |
1897 | { |
1898 | String message = getMessage( e ); |
1899 | if ( message == null && e.getException() != null ) |
1900 | { |
1901 | message = getMessage( e.getException() ); |
1902 | } |
1903 | |
1904 | // JDK: As of JDK 6, "new IOException( message, cause )". |
1905 | throw (IOException) new IOException( message ).initCause( e ); |
1906 | } |
1907 | } |
1908 | |
1909 | /** |
1910 | * Gets an attribute from a java class. |
1911 | * |
1912 | * @param clazz The java class to get an attribute from. |
1913 | * @param attributeName The name of the attribute to get. |
1914 | * |
1915 | * @return The value of attribute {@code attributeName} of {@code clazz} or {@code null}, if no such attribute |
1916 | * exists. |
1917 | * |
1918 | * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}. |
1919 | * @throws IOException if getting the attribute fails. |
1920 | * |
1921 | * @see JavaClass#getAttributes() |
1922 | */ |
1923 | public byte[] getClassfileAttribute( final JavaClass clazz, final String attributeName ) throws IOException |
1924 | { |
1925 | if ( clazz == null ) |
1926 | { |
1927 | throw new NullPointerException( "clazz" ); |
1928 | } |
1929 | if ( attributeName == null ) |
1930 | { |
1931 | throw new NullPointerException( "attributeName" ); |
1932 | } |
1933 | |
1934 | final Attribute[] attributes = clazz.getAttributes(); |
1935 | |
1936 | for ( int i = attributes.length - 1; i >= 0; i-- ) |
1937 | { |
1938 | final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() ); |
1939 | |
1940 | if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) ) |
1941 | { |
1942 | final Unknown unknown = (Unknown) attributes[i]; |
1943 | return unknown.getBytes(); |
1944 | } |
1945 | } |
1946 | |
1947 | return null; |
1948 | } |
1949 | |
1950 | /** |
1951 | * Adds or updates an attribute in a java class. |
1952 | * |
1953 | * @param clazz The class to update an attribute of. |
1954 | * @param attributeName The name of the attribute to update. |
1955 | * @param data The new data of the attribute to update the {@code clazz} with. |
1956 | * |
1957 | * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}. |
1958 | * @throws IOException if updating the class file fails. |
1959 | * |
1960 | * @see JavaClass#getAttributes() |
1961 | */ |
1962 | public void setClassfileAttribute( final JavaClass clazz, final String attributeName, final byte[] data ) |
1963 | throws IOException |
1964 | { |
1965 | if ( clazz == null ) |
1966 | { |
1967 | throw new NullPointerException( "clazz" ); |
1968 | } |
1969 | if ( attributeName == null ) |
1970 | { |
1971 | throw new NullPointerException( "attributeName" ); |
1972 | } |
1973 | |
1974 | final byte[] attributeData = data != null ? data : NO_BYTES; |
1975 | |
1976 | /* |
1977 | * The JavaTM Virtual Machine Specification - Second Edition - Chapter 4.1 |
1978 | * |
1979 | * A Java virtual machine implementation is required to silently ignore any |
1980 | * or all attributes in the attributes table of a ClassFile structure that |
1981 | * it does not recognize. Attributes not defined in this specification are |
1982 | * not allowed to affect the semantics of the class file, but only to |
1983 | * provide additional descriptive information (§4.7.1). |
1984 | */ |
1985 | Attribute[] attributes = clazz.getAttributes(); |
1986 | |
1987 | int attributeIndex = -1; |
1988 | int nameIndex = -1; |
1989 | |
1990 | for ( int i = attributes.length - 1; i >= 0; i-- ) |
1991 | { |
1992 | final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() ); |
1993 | |
1994 | if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) ) |
1995 | { |
1996 | attributeIndex = i; |
1997 | nameIndex = attributes[i].getNameIndex(); |
1998 | } |
1999 | } |
2000 | |
2001 | if ( nameIndex == -1 ) |
2002 | { |
2003 | final Constant[] pool = clazz.getConstantPool().getConstantPool(); |
2004 | final Constant[] tmp = new Constant[ pool.length + 1 ]; |
2005 | System.arraycopy( pool, 0, tmp, 0, pool.length ); |
2006 | tmp[pool.length] = new ConstantUtf8( attributeName ); |
2007 | nameIndex = pool.length; |
2008 | clazz.setConstantPool( new ConstantPool( tmp ) ); |
2009 | } |
2010 | |
2011 | final Unknown unknown = new Unknown( nameIndex, attributeData.length, attributeData, clazz.getConstantPool() ); |
2012 | |
2013 | if ( attributeIndex == -1 ) |
2014 | { |
2015 | final Attribute[] tmp = new Attribute[ attributes.length + 1 ]; |
2016 | System.arraycopy( attributes, 0, tmp, 0, attributes.length ); |
2017 | tmp[attributes.length] = unknown; |
2018 | attributes = tmp; |
2019 | } |
2020 | else |
2021 | { |
2022 | attributes[attributeIndex] = unknown; |
2023 | } |
2024 | |
2025 | clazz.setAttributes( attributes ); |
2026 | } |
2027 | |
2028 | /** |
2029 | * Encodes a model object to a byte array. |
2030 | * |
2031 | * @param marshaller The marshaller to use for encoding the object. |
2032 | * @param modelObject The model object to encode. |
2033 | * |
2034 | * @return GZIP compressed XML document of {@code modelObject}. |
2035 | * |
2036 | * @throws NullPointerException if {@code marshaller} or {@code modelObject} is {@code null}. |
2037 | * @throws IOException if encoding {@code modelObject} fails. |
2038 | * |
2039 | * @see #decodeModelObject(javax.xml.bind.Unmarshaller, byte[], java.lang.Class) |
2040 | */ |
2041 | public byte[] encodeModelObject( final Marshaller marshaller, final JAXBElement<? extends ModelObject> modelObject ) |
2042 | throws IOException |
2043 | { |
2044 | if ( marshaller == null ) |
2045 | { |
2046 | throw new NullPointerException( "marshaller" ); |
2047 | } |
2048 | if ( modelObject == null ) |
2049 | { |
2050 | throw new NullPointerException( "modelObject" ); |
2051 | } |
2052 | |
2053 | try |
2054 | { |
2055 | final ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
2056 | final GZIPOutputStream out = new GZIPOutputStream( baos ); |
2057 | marshaller.marshal( modelObject, out ); |
2058 | out.close(); |
2059 | return baos.toByteArray(); |
2060 | } |
2061 | catch ( final JAXBException e ) |
2062 | { |
2063 | String message = getMessage( e ); |
2064 | if ( message == null && e.getLinkedException() != null ) |
2065 | { |
2066 | message = getMessage( e.getLinkedException() ); |
2067 | } |
2068 | |
2069 | // JDK: As of JDK 6, "new IOException( message, cause )". |
2070 | throw (IOException) new IOException( message ).initCause( e ); |
2071 | } |
2072 | } |
2073 | |
2074 | /** |
2075 | * Decodes a model object from a byte array. |
2076 | * |
2077 | * @param unmarshaller The unmarshaller to use for decoding the object. |
2078 | * @param bytes The encoded model object to decode. |
2079 | * @param type The class of the type of the encoded model object. |
2080 | * @param <T> The type of the encoded model object. |
2081 | * |
2082 | * @return Model object decoded from {@code bytes}. |
2083 | * |
2084 | * @throws NullPointerException if {@code unmarshaller}, {@code bytes} or {@code type} is {@code null}. |
2085 | * @throws IOException if decoding {@code bytes} fails. |
2086 | * |
2087 | * @see #encodeModelObject(javax.xml.bind.Marshaller, javax.xml.bind.JAXBElement) |
2088 | */ |
2089 | public <T extends ModelObject> T decodeModelObject( final Unmarshaller unmarshaller, final byte[] bytes, |
2090 | final Class<T> type ) throws IOException |
2091 | { |
2092 | if ( unmarshaller == null ) |
2093 | { |
2094 | throw new NullPointerException( "unmarshaller" ); |
2095 | } |
2096 | if ( bytes == null ) |
2097 | { |
2098 | throw new NullPointerException( "bytes" ); |
2099 | } |
2100 | if ( type == null ) |
2101 | { |
2102 | throw new NullPointerException( "type" ); |
2103 | } |
2104 | |
2105 | try |
2106 | { |
2107 | final ByteArrayInputStream bais = new ByteArrayInputStream( bytes ); |
2108 | final GZIPInputStream in = new GZIPInputStream( bais ); |
2109 | final JAXBElement<T> element = (JAXBElement<T>) unmarshaller.unmarshal( in ); |
2110 | in.close(); |
2111 | return element.getValue(); |
2112 | } |
2113 | catch ( final JAXBException e ) |
2114 | { |
2115 | String message = getMessage( e ); |
2116 | if ( message == null && e.getLinkedException() != null ) |
2117 | { |
2118 | message = getMessage( e.getLinkedException() ); |
2119 | } |
2120 | |
2121 | // JDK: As of JDK 6, "new IOException( message, cause )". |
2122 | throw (IOException) new IOException( message ).initCause( e ); |
2123 | } |
2124 | } |
2125 | |
2126 | private void commitModelObjects( final Specifications specifications, final Implementations implementations, |
2127 | final Marshaller marshaller, final File classesDirectory ) |
2128 | throws IOException, ModelObjectException |
2129 | { |
2130 | if ( specifications != null ) |
2131 | { |
2132 | for ( int i = specifications.getSpecification().size() - 1; i >= 0; i-- ) |
2133 | { |
2134 | this.commitModelObjects( specifications.getSpecification().get( i ), marshaller, classesDirectory ); |
2135 | } |
2136 | } |
2137 | |
2138 | if ( implementations != null ) |
2139 | { |
2140 | for ( int i = implementations.getImplementation().size() - 1; i >= 0; i-- ) |
2141 | { |
2142 | this.commitModelObjects( implementations.getImplementation().get( i ), marshaller, classesDirectory ); |
2143 | } |
2144 | } |
2145 | } |
2146 | |
2147 | private void commitModelObjects( final Specification specification, final Marshaller marshaller, |
2148 | final File classesDirectory ) throws IOException, ModelObjectException |
2149 | { |
2150 | if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null ) |
2151 | { |
2152 | final String classLocation = |
2153 | specification.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class"; |
2154 | |
2155 | final File classFile = new File( classesDirectory, classLocation ); |
2156 | |
2157 | if ( !classesDirectory.isDirectory() ) |
2158 | { |
2159 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
2160 | } |
2161 | if ( !classFile.isFile() ) |
2162 | { |
2163 | throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) ); |
2164 | } |
2165 | if ( !( classFile.canRead() && classFile.canWrite() ) ) |
2166 | { |
2167 | throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) ); |
2168 | } |
2169 | |
2170 | if ( this.isLoggable( Level.INFO ) ) |
2171 | { |
2172 | this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null ); |
2173 | } |
2174 | |
2175 | final JavaClass javaClass = this.readJavaClass( classFile ); |
2176 | this.commitModelObjects( specification, marshaller, javaClass ); |
2177 | this.writeJavaClass( javaClass, classFile ); |
2178 | } |
2179 | } |
2180 | |
2181 | private void commitModelObjects( final Implementation implementation, final Marshaller marshaller, |
2182 | final File classesDirectory ) throws IOException, ModelObjectException |
2183 | { |
2184 | if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null ) |
2185 | { |
2186 | final String classLocation = |
2187 | implementation.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class"; |
2188 | |
2189 | final File classFile = new File( classesDirectory, classLocation ); |
2190 | |
2191 | if ( !classesDirectory.isDirectory() ) |
2192 | { |
2193 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
2194 | } |
2195 | if ( !classFile.isFile() ) |
2196 | { |
2197 | throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) ); |
2198 | } |
2199 | if ( !( classFile.canRead() && classFile.canWrite() ) ) |
2200 | { |
2201 | throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) ); |
2202 | } |
2203 | |
2204 | if ( this.isLoggable( Level.INFO ) ) |
2205 | { |
2206 | this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null ); |
2207 | } |
2208 | |
2209 | final JavaClass javaClass = this.readJavaClass( classFile ); |
2210 | this.commitModelObjects( implementation, marshaller, javaClass ); |
2211 | this.writeJavaClass( javaClass, classFile ); |
2212 | } |
2213 | } |
2214 | |
2215 | private ModelValidationReport validateModelObjects( final Specifications specifications, |
2216 | final Implementations implementations, |
2217 | final Unmarshaller unmarshaller, final File classesDirectory ) |
2218 | throws IOException, ModelObjectException |
2219 | { |
2220 | final ModelValidationReport report = new ModelValidationReport(); |
2221 | |
2222 | if ( specifications != null ) |
2223 | { |
2224 | for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ ) |
2225 | { |
2226 | final ModelValidationReport current = this.validateModelObjects( |
2227 | specifications.getSpecification().get( i ), unmarshaller, classesDirectory ); |
2228 | |
2229 | report.getDetails().addAll( current.getDetails() ); |
2230 | } |
2231 | } |
2232 | |
2233 | if ( implementations != null ) |
2234 | { |
2235 | for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ ) |
2236 | { |
2237 | final ModelValidationReport current = this.validateModelObjects( |
2238 | implementations.getImplementation().get( i ), unmarshaller, classesDirectory ); |
2239 | |
2240 | report.getDetails().addAll( current.getDetails() ); |
2241 | } |
2242 | } |
2243 | |
2244 | return report; |
2245 | } |
2246 | |
2247 | private ModelValidationReport validateModelObjects( final Specification specification, |
2248 | final Unmarshaller unmarshaller, |
2249 | final File classesDirectory ) |
2250 | throws IOException, ModelObjectException |
2251 | { |
2252 | final ModelValidationReport report = new ModelValidationReport(); |
2253 | |
2254 | if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null ) |
2255 | { |
2256 | final String classLocation = |
2257 | specification.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class"; |
2258 | |
2259 | final File classFile = new File( classesDirectory, classLocation ); |
2260 | |
2261 | if ( !classesDirectory.isDirectory() ) |
2262 | { |
2263 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
2264 | } |
2265 | if ( !classFile.isFile() ) |
2266 | { |
2267 | throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) ); |
2268 | } |
2269 | if ( !classFile.canRead() ) |
2270 | { |
2271 | throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) ); |
2272 | } |
2273 | |
2274 | if ( this.isLoggable( Level.INFO ) ) |
2275 | { |
2276 | this.log( Level.INFO, getMessage( "validating", classFile.getAbsolutePath() ), null ); |
2277 | } |
2278 | |
2279 | final JavaClass javaClass = this.readJavaClass( classFile ); |
2280 | |
2281 | report.getDetails().addAll( |
2282 | this.validateModelObjects( specification, unmarshaller, javaClass ).getDetails() ); |
2283 | |
2284 | } |
2285 | |
2286 | return report; |
2287 | } |
2288 | |
2289 | private ModelValidationReport validateModelObjects( final Implementation implementation, |
2290 | final Unmarshaller unmarshaller, |
2291 | final File classesDirectory ) |
2292 | throws IOException, ModelObjectException |
2293 | { |
2294 | final ModelValidationReport report = new ModelValidationReport(); |
2295 | |
2296 | if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null ) |
2297 | { |
2298 | final String classLocation = |
2299 | implementation.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class"; |
2300 | |
2301 | final File classFile = new File( classesDirectory, classLocation ); |
2302 | |
2303 | if ( !classesDirectory.isDirectory() ) |
2304 | { |
2305 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
2306 | } |
2307 | if ( !classFile.isFile() ) |
2308 | { |
2309 | throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) ); |
2310 | } |
2311 | if ( !classFile.canRead() ) |
2312 | { |
2313 | throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) ); |
2314 | } |
2315 | |
2316 | if ( this.isLoggable( Level.INFO ) ) |
2317 | { |
2318 | this.log( Level.INFO, getMessage( "validating", classFile.getAbsolutePath() ), null ); |
2319 | } |
2320 | |
2321 | final JavaClass javaClass = this.readJavaClass( classFile ); |
2322 | |
2323 | report.getDetails().addAll( |
2324 | this.validateModelObjects( implementation, unmarshaller, javaClass ).getDetails() ); |
2325 | |
2326 | } |
2327 | |
2328 | return report; |
2329 | } |
2330 | |
2331 | private ModelValidationReport validateModelObjects( final Specifications specifications, |
2332 | final Implementations implementations, |
2333 | final Unmarshaller unmarshaller, final ModelContext context ) |
2334 | throws IOException, ModelException |
2335 | { |
2336 | final ModelValidationReport report = new ModelValidationReport(); |
2337 | |
2338 | if ( specifications != null ) |
2339 | { |
2340 | for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ ) |
2341 | { |
2342 | final ModelValidationReport current = this.validateModelObjects( |
2343 | specifications.getSpecification().get( i ), unmarshaller, context ); |
2344 | |
2345 | report.getDetails().addAll( current.getDetails() ); |
2346 | } |
2347 | } |
2348 | |
2349 | if ( implementations != null ) |
2350 | { |
2351 | for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ ) |
2352 | { |
2353 | final ModelValidationReport current = this.validateModelObjects( |
2354 | implementations.getImplementation().get( i ), unmarshaller, context ); |
2355 | |
2356 | report.getDetails().addAll( current.getDetails() ); |
2357 | } |
2358 | } |
2359 | |
2360 | return report; |
2361 | } |
2362 | |
2363 | private ModelValidationReport validateModelObjects( final Specification specification, |
2364 | final Unmarshaller unmarshaller, |
2365 | final ModelContext context ) throws IOException, ModelException |
2366 | { |
2367 | final ModelValidationReport report = new ModelValidationReport(); |
2368 | |
2369 | if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null ) |
2370 | { |
2371 | final String classLocation = |
2372 | specification.getJavaTypeName().getClassName().replace( '.', '/' ) + ".class"; |
2373 | |
2374 | final URL classUrl = context.findResource( classLocation ); |
2375 | |
2376 | if ( classUrl == null ) |
2377 | { |
2378 | throw new IOException( getMessage( "resourceNotFound", classLocation ) ); |
2379 | } |
2380 | |
2381 | if ( this.isLoggable( Level.INFO ) ) |
2382 | { |
2383 | this.log( Level.INFO, getMessage( "validatingSpecification", specification.getIdentifier() ), null ); |
2384 | } |
2385 | |
2386 | InputStream in = null; |
2387 | JavaClass javaClass = null; |
2388 | boolean suppressExceptionOnClose = true; |
2389 | |
2390 | try |
2391 | { |
2392 | in = classUrl.openStream(); |
2393 | javaClass = new ClassParser( in, classUrl.toExternalForm() ).parse(); |
2394 | suppressExceptionOnClose = false; |
2395 | } |
2396 | finally |
2397 | { |
2398 | try |
2399 | { |
2400 | if ( in != null ) |
2401 | { |
2402 | in.close(); |
2403 | } |
2404 | } |
2405 | catch ( final IOException e ) |
2406 | { |
2407 | if ( suppressExceptionOnClose ) |
2408 | { |
2409 | this.log( Level.SEVERE, getMessage( e ), e ); |
2410 | } |
2411 | else |
2412 | { |
2413 | throw e; |
2414 | } |
2415 | } |
2416 | } |
2417 | |
2418 | report.getDetails().addAll( |
2419 | this.validateModelObjects( specification, unmarshaller, javaClass ).getDetails() ); |
2420 | |
2421 | } |
2422 | |
2423 | return report; |
2424 | } |
2425 | |
2426 | private ModelValidationReport validateModelObjects( final Implementation implementation, |
2427 | final Unmarshaller unmarshaller, |
2428 | final ModelContext context ) throws IOException, ModelException |
2429 | { |
2430 | final ModelValidationReport report = new ModelValidationReport(); |
2431 | |
2432 | if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null ) |
2433 | { |
2434 | final String classLocation = implementation.getJavaTypeName().getClassName().replace( '.', '/' ) + ".class"; |
2435 | final URL classUrl = context.findResource( classLocation ); |
2436 | |
2437 | if ( classUrl == null ) |
2438 | { |
2439 | throw new IOException( getMessage( "resourceNotFound", classLocation ) ); |
2440 | } |
2441 | |
2442 | if ( this.isLoggable( Level.INFO ) ) |
2443 | { |
2444 | this.log( Level.INFO, getMessage( "validatingImplementation", implementation.getIdentifier() ), null ); |
2445 | } |
2446 | |
2447 | InputStream in = null; |
2448 | JavaClass javaClass = null; |
2449 | boolean suppressExceptionOnClose = true; |
2450 | |
2451 | try |
2452 | { |
2453 | in = classUrl.openStream(); |
2454 | javaClass = new ClassParser( in, classUrl.toExternalForm() ).parse(); |
2455 | suppressExceptionOnClose = false; |
2456 | } |
2457 | finally |
2458 | { |
2459 | try |
2460 | { |
2461 | if ( in != null ) |
2462 | { |
2463 | in.close(); |
2464 | } |
2465 | } |
2466 | catch ( final IOException e ) |
2467 | { |
2468 | if ( suppressExceptionOnClose ) |
2469 | { |
2470 | this.log( Level.SEVERE, getMessage( e ), e ); |
2471 | } |
2472 | else |
2473 | { |
2474 | throw e; |
2475 | } |
2476 | } |
2477 | } |
2478 | |
2479 | report.getDetails().addAll( |
2480 | this.validateModelObjects( implementation, unmarshaller, javaClass ).getDetails() ); |
2481 | |
2482 | } |
2483 | |
2484 | return report; |
2485 | } |
2486 | |
2487 | private void transformModelObjects( final Specifications specifications, final Implementations implementations, |
2488 | final Unmarshaller unmarshaller, final Marshaller marshaller, |
2489 | final File classesDirectory, final List<Transformer> transformers ) |
2490 | throws IOException, ModelObjectException |
2491 | { |
2492 | if ( specifications != null ) |
2493 | { |
2494 | for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ ) |
2495 | { |
2496 | this.transformModelObjects( specifications.getSpecification().get( i ), marshaller, unmarshaller, |
2497 | classesDirectory, transformers ); |
2498 | |
2499 | } |
2500 | } |
2501 | |
2502 | if ( implementations != null ) |
2503 | { |
2504 | for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ ) |
2505 | { |
2506 | this.transformModelObjects( implementations.getImplementation().get( i ), marshaller, unmarshaller, |
2507 | classesDirectory, transformers ); |
2508 | |
2509 | } |
2510 | } |
2511 | } |
2512 | |
2513 | private void transformModelObjects( final Specification specification, final Marshaller marshaller, |
2514 | final Unmarshaller unmarshaller, final File classesDirectory, |
2515 | final List<Transformer> transformers ) throws IOException, ModelObjectException |
2516 | { |
2517 | if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null ) |
2518 | { |
2519 | final String classLocation = |
2520 | specification.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class"; |
2521 | |
2522 | final File classFile = new File( classesDirectory, classLocation ); |
2523 | |
2524 | if ( !classesDirectory.isDirectory() ) |
2525 | { |
2526 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
2527 | } |
2528 | if ( !classFile.isFile() ) |
2529 | { |
2530 | throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) ); |
2531 | } |
2532 | if ( !( classFile.canRead() && classFile.canWrite() ) ) |
2533 | { |
2534 | throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) ); |
2535 | } |
2536 | |
2537 | if ( this.isLoggable( Level.INFO ) ) |
2538 | { |
2539 | this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null ); |
2540 | } |
2541 | |
2542 | final JavaClass javaClass = this.readJavaClass( classFile ); |
2543 | this.transformModelObjects( specification, marshaller, unmarshaller, javaClass, transformers ); |
2544 | this.writeJavaClass( javaClass, classFile ); |
2545 | } |
2546 | } |
2547 | |
2548 | private void transformModelObjects( final Implementation implementation, final Marshaller marshaller, |
2549 | final Unmarshaller unmarshaller, final File classesDirectory, |
2550 | final List<Transformer> transformers ) throws IOException, ModelObjectException |
2551 | { |
2552 | if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null ) |
2553 | { |
2554 | final String classLocation = |
2555 | implementation.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class"; |
2556 | |
2557 | final File classFile = new File( classesDirectory, classLocation ); |
2558 | |
2559 | if ( !classesDirectory.isDirectory() ) |
2560 | { |
2561 | throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) ); |
2562 | } |
2563 | if ( !classFile.isFile() ) |
2564 | { |
2565 | throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) ); |
2566 | } |
2567 | if ( !( classFile.canRead() && classFile.canWrite() ) ) |
2568 | { |
2569 | throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) ); |
2570 | } |
2571 | |
2572 | if ( this.isLoggable( Level.INFO ) ) |
2573 | { |
2574 | this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null ); |
2575 | } |
2576 | |
2577 | final JavaClass javaClass = this.readJavaClass( classFile ); |
2578 | this.transformModelObjects( implementation, marshaller, unmarshaller, javaClass, transformers ); |
2579 | this.writeJavaClass( javaClass, classFile ); |
2580 | } |
2581 | } |
2582 | |
2583 | private JavaClass readJavaClass( final File classFile ) throws IOException |
2584 | { |
2585 | FileInputStream in = null; |
2586 | FileChannel fileChannel = null; |
2587 | FileLock fileLock = null; |
2588 | boolean suppressExceptionOnClose = true; |
2589 | |
2590 | try |
2591 | { |
2592 | in = new FileInputStream( classFile ); |
2593 | fileChannel = in.getChannel(); |
2594 | fileLock = fileChannel.lock( 0, classFile.length(), true ); |
2595 | |
2596 | final JavaClass javaClass = new ClassParser( in, classFile.getAbsolutePath() ).parse(); |
2597 | suppressExceptionOnClose = false; |
2598 | return javaClass; |
2599 | } |
2600 | finally |
2601 | { |
2602 | this.releaseAndClose( fileLock, fileChannel, in, suppressExceptionOnClose ); |
2603 | } |
2604 | } |
2605 | |
2606 | private void writeJavaClass( final JavaClass javaClass, final File classFile ) throws IOException |
2607 | { |
2608 | RandomAccessFile randomAccessFile = null; |
2609 | FileChannel fileChannel = null; |
2610 | FileLock fileLock = null; |
2611 | boolean suppressExceptionOnClose = true; |
2612 | |
2613 | final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); |
2614 | javaClass.dump( byteStream ); |
2615 | byteStream.close(); |
2616 | |
2617 | final byte[] bytes = byteStream.toByteArray(); |
2618 | |
2619 | try |
2620 | { |
2621 | randomAccessFile = new RandomAccessFile( classFile, "rw" ); |
2622 | fileChannel = randomAccessFile.getChannel(); |
2623 | fileLock = fileChannel.lock(); |
2624 | fileChannel.truncate( bytes.length ); |
2625 | fileChannel.position( 0L ); |
2626 | fileChannel.write( ByteBuffer.wrap( bytes ) ); |
2627 | fileChannel.force( true ); |
2628 | suppressExceptionOnClose = false; |
2629 | } |
2630 | finally |
2631 | { |
2632 | this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose ); |
2633 | } |
2634 | } |
2635 | |
2636 | private void releaseAndClose( final FileLock fileLock, final FileChannel fileChannel, |
2637 | final Closeable closeable, final boolean suppressExceptions ) |
2638 | throws IOException |
2639 | { |
2640 | try |
2641 | { |
2642 | if ( fileLock != null ) |
2643 | { |
2644 | fileLock.release(); |
2645 | } |
2646 | } |
2647 | catch ( final IOException e ) |
2648 | { |
2649 | if ( suppressExceptions ) |
2650 | { |
2651 | this.log( Level.SEVERE, null, e ); |
2652 | } |
2653 | else |
2654 | { |
2655 | throw e; |
2656 | } |
2657 | } |
2658 | finally |
2659 | { |
2660 | try |
2661 | { |
2662 | if ( fileChannel != null ) |
2663 | { |
2664 | fileChannel.close(); |
2665 | } |
2666 | } |
2667 | catch ( final IOException e ) |
2668 | { |
2669 | if ( suppressExceptions ) |
2670 | { |
2671 | this.log( Level.SEVERE, null, e ); |
2672 | } |
2673 | else |
2674 | { |
2675 | throw e; |
2676 | } |
2677 | } |
2678 | finally |
2679 | { |
2680 | try |
2681 | { |
2682 | if ( closeable != null ) |
2683 | { |
2684 | closeable.close(); |
2685 | } |
2686 | } |
2687 | catch ( final IOException e ) |
2688 | { |
2689 | if ( suppressExceptions ) |
2690 | { |
2691 | this.log( Level.SEVERE, null, e ); |
2692 | } |
2693 | else |
2694 | { |
2695 | throw e; |
2696 | } |
2697 | } |
2698 | } |
2699 | } |
2700 | } |
2701 | |
2702 | private static String getMessage( final String key, final Object... arguments ) |
2703 | { |
2704 | return MessageFormat.format( ResourceBundle.getBundle( |
2705 | ClassFileProcessor.class.getName().replace( '.', '/' ) ).getString( key ), arguments ); |
2706 | |
2707 | } |
2708 | |
2709 | private static String getMessage( final Throwable t ) |
2710 | { |
2711 | return t != null |
2712 | ? t.getMessage() != null && t.getMessage().trim().length() > 0 |
2713 | ? t.getMessage() |
2714 | : getMessage( t.getCause() ) |
2715 | : null; |
2716 | |
2717 | } |
2718 | |
2719 | } |