Details

    • Type: Improvement Improvement
    • Status: Open Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: GroovyWS
    • Labels:
      None
    • Environment:
      Windows 2000 without JDK
    • Number of attachments :
      0

      Description

      I try to integrate the Groovy WSClient into an application with and installed JRE.
      Since the nature of this application it should be highly dynamic. So far everything is possible now thanks to groovy

      The Problem is, that GroovyWS relies on JAXB and Apache CXF.
      The Apache CXF depends on the JDK since it tries to compile the JAXB Java Files.
      This Call is done true the org.apache.cxf.common.util.Compiler class.
      Due the lack of the JDK on the machine I tried following.
      1. Replace the org.apache.cxf.common.util.Compiler with a preloaded org.apache.cxf.common.util.Compiler.groovy

      package org.apache.cxf.common.util;

      import java.io.File;

      <code>
      public class Compiler

      { static regex = /(?s)@.*\([^)]*}

      )/

      public boolean internalCompile(String[] args, int sourceFileIndex) {
      def jaxbIndexString =args[sourceFileIndex].replaceAll(/-src.*/,"-classes")File.separator"jaxb.index"
      println jaxbIndexString
      def jaxbIndex = new File(jaxbIndexString)

      for (int i = sourceFileIndex;i<args.length;i++) {
      jaxbIndex.withWriterAppend

      { writer -> writer << args[i].find(/\w+.java/).replaceAll(/\.java/,"") << '\n' }

      def source = ""
      new File(args[i]).eachLine

      {source << it+'\n'}

      def replacedSource = source.replaceAll(regex)

      {it.replaceAll(/\{/,'[').replaceAll(/\}/,']')}

      getClass().getClassLoader().parseClass(replacedSource)
      }
      false
      }
      }

      </code>

      (The Code is ugly and just a dirty hack )

      2. Convert the Bean Files for JAXB to Groovy conform Code. (This is the regex wich replaces the {} with [] in the annotations)

      3. Additionally I tried to generate a jaxb.index file

      4. Just parse these Files with the GroovyClassLoader (Same Loader that loads the cxf so the classes should be in the CLASSPATH)

      The Problem is that I get everytime the java.lang.IllegalStateException: Unable to create JAXBContext for generated packages: "org.jbpm.api.task" doesnt contain ObjectFactory.class or jaxb.index Exception...

      There should be a way to use GroovyWS without the javac...

        Activity

        Hide
        Guillaume Laforge added a comment -

        Wrong Guillaume

        Show
        Guillaume Laforge added a comment - Wrong Guillaume
        Hide
        Guillaume ALLEON added a comment -

        I would feel more comfortable in trying to embed the eclipse compiler. I did some early work in that direction some weeks ago but time flies ...
        I am not sure your way will work because the groovy compiler will introduce additional methods.

        Show
        Guillaume ALLEON added a comment - I would feel more comfortable in trying to embed the eclipse compiler. I did some early work in that direction some weeks ago but time flies ... I am not sure your way will work because the groovy compiler will introduce additional methods.
        Hide
        Sebastian Rühl added a comment - - edited

        Good idea...

        Currently I try to compile the files with the org.codehaus.groovy.tools.FileSystemCompiler...
        But you are right... I read that JAXB gets in trouble with the metaclass. (see: http://stackoverflow.com/questions/1161147/how-do-i-get-groovy-and-jaxb-to-play-nice-together)

        For me I'm just asking myself why the GroovyWS should rely on the JAXB at all?
        Since we depend on duck typing cause the JAXB Files will generated during runtime, wouldn't it be a better way to provide the SOAP XML directly to Groovy?

        Show
        Sebastian Rühl added a comment - - edited Good idea... Currently I try to compile the files with the org.codehaus.groovy.tools.FileSystemCompiler... But you are right... I read that JAXB gets in trouble with the metaclass. (see: http://stackoverflow.com/questions/1161147/how-do-i-get-groovy-and-jaxb-to-play-nice-together ) For me I'm just asking myself why the GroovyWS should rely on the JAXB at all? Since we depend on duck typing cause the JAXB Files will generated during runtime, wouldn't it be a better way to provide the SOAP XML directly to Groovy?
        Hide
        Guillaume ALLEON added a comment -

        Yep, the metaclass will mess it up ...
        The JAXB compiler is just used to get the stubs at no cost ...
        Then the stubs need to be compiled and this is were your problem is.

        3 options:
        1- directly deal with the XML/WSDL - that's what GroovySOAP was all about but there are a number of corner cases that show up with complex services,
        2- add a groovy back-end to the JAXB compiler - do-able will remove the dependency on the jdk or any other compiler. We might get rid of the metaclass problem
        3- embed our own compiler (eclipse)

        How large/complicated is your WSDL ?

        Show
        Guillaume ALLEON added a comment - Yep, the metaclass will mess it up ... The JAXB compiler is just used to get the stubs at no cost ... Then the stubs need to be compiled and this is were your problem is. 3 options: 1- directly deal with the XML/WSDL - that's what GroovySOAP was all about but there are a number of corner cases that show up with complex services, 2- add a groovy back-end to the JAXB compiler - do-able will remove the dependency on the jdk or any other compiler. We might get rid of the metaclass problem 3- embed our own compiler (eclipse) How large/complicated is your WSDL ?
        Hide
        Sebastian Rühl added a comment - - edited

        1- Fair enough...
        2- Seems to be a good solution
        3- Is also a good solution as far as the eclipse compiler can be provided trough a maven dependency...

        Currently I have following Solution

        1. Just before I call the class that resolves the Grape to GroovyWS I do following:

        // Load the replacement Compiler (for code see belpw)
        getClass().getClassLoader().loadClass("org.apache.cxf.common.util.Compiler",true,true)
        // Add the tools.jar from Java SDK. (On an Apache Server)
        getClass().getClassLoader().addURL("http://192.168.0.67/scripts/tools.jar".toURL())

        The Load the Class trough reflection

        Following will happen:
        1. The Grapes will be resolved.
        2. The WS will start up and then CXF tries to compile the classes. (The Custom compiler will be used)
        3. The classes will be compiled with the Java-Compiler
        4. A Crash happens in the org.codehaus.groovy.tools.javac.JavacJavaCompiler on line 138
        java.lang.IllegalArgumentException: URI scheme is not "file"
        null
        java.io.File.<init>(File.java:338)
        org.codehaus.groovy.tools.javac.JavacJavaCompiler.makeParameters(JavacJavaCompiler.java:138)

        Thats how far I'm now...

        Im not sure if I'm using the JavaJavacCompiler the right way... Anyway this is just a hack since I need to get it running

        Compiler.groovy
        
        package org.apache.cxf.common.util;
        
        import java.io.File;
        
        import org.codehaus.groovy.control.CompilerConfiguration;
        import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit;
        
        public class Compiler {
        	
        	private File outputDir;
        	
        	public boolean compileFiles(String[] files, File outputDir) {
        		this.outputDir = outputDir;
        		return internalCompile(outputDir, -1);
        	}
        	
        	public boolean internalCompile(String[] args, int sourceFileIndex) {
        		String[] sourceFiles;
        		if (sourceFileIndex == -1) {
        			println "We got called From compileFiles... Nothing to do"
        		} else {
        			findTargetDir: for (int i = 0; i < args.length; i++) {
        				if (args[i] == '-d') {
        					outputDir = new File(args[i+1])
        					println "targetDir is"+ args[i+1]
        					sourceFiles = args
        					break findTargetDir
        				}
        			}
        		}
        		CompilerConfiguration compilerConfiguration = new CompilerConfiguration()
        		
        		compilerConfiguration.setTargetDirectory(outputDir)
        		compilerConfiguration.setJointCompilationOptions([stubDir:outputDir,keepStubs:true])
        		compilerConfiguration.setTargetBytecode "1.5"
        		
        		JavaAwareCompilationUnit cu = new JavaAwareCompilationUnit(compilerConfiguration)
        		
        		cu.setClassLoader(this.getClass().getClassLoader())
        		
        		def temp = args[sourceFileIndex..args.length-1]
        		
        		sourceFiles = new String[temp.size()];
        		for (int i = 0; i < sourceFiles.length; i++) {
        			sourceFiles[i] = temp[i]
        		}
        		
        		cu.addSources(sourceFiles)
        		
        		cu.gotoPhase 4
        		
        		return false;
        	}
        	
        }
        
        
        Show
        Sebastian Rühl added a comment - - edited 1- Fair enough... 2- Seems to be a good solution 3- Is also a good solution as far as the eclipse compiler can be provided trough a maven dependency... Currently I have following Solution 1. Just before I call the class that resolves the Grape to GroovyWS I do following: // Load the replacement Compiler (for code see belpw) getClass().getClassLoader().loadClass("org.apache.cxf.common.util.Compiler",true,true) // Add the tools.jar from Java SDK. (On an Apache Server) getClass().getClassLoader().addURL("http://192.168.0.67/scripts/tools.jar".toURL()) The Load the Class trough reflection Following will happen: 1. The Grapes will be resolved. 2. The WS will start up and then CXF tries to compile the classes. (The Custom compiler will be used) 3. The classes will be compiled with the Java-Compiler 4. A Crash happens in the org.codehaus.groovy.tools.javac.JavacJavaCompiler on line 138 java.lang.IllegalArgumentException: URI scheme is not "file" null java.io.File.<init>(File.java:338) org.codehaus.groovy.tools.javac.JavacJavaCompiler.makeParameters(JavacJavaCompiler.java:138) Thats how far I'm now... Im not sure if I'm using the JavaJavacCompiler the right way... Anyway this is just a hack since I need to get it running Compiler.groovy package org.apache.cxf.common.util; import java.io.File; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit; public class Compiler { private File outputDir; public boolean compileFiles( String [] files, File outputDir) { this .outputDir = outputDir; return internalCompile(outputDir, -1); } public boolean internalCompile( String [] args, int sourceFileIndex) { String [] sourceFiles; if (sourceFileIndex == -1) { println "We got called From compileFiles... Nothing to do " } else { findTargetDir: for ( int i = 0; i < args.length; i++) { if (args[i] == '-d') { outputDir = new File(args[i+1]) println "targetDir is" + args[i+1] sourceFiles = args break findTargetDir } } } CompilerConfiguration compilerConfiguration = new CompilerConfiguration() compilerConfiguration.setTargetDirectory(outputDir) compilerConfiguration.setJointCompilationOptions([stubDir:outputDir,keepStubs: true ]) compilerConfiguration.setTargetBytecode "1.5" JavaAwareCompilationUnit cu = new JavaAwareCompilationUnit(compilerConfiguration) cu.setClassLoader( this .getClass().getClassLoader()) def temp = args[sourceFileIndex..args.length-1] sourceFiles = new String [temp.size()]; for ( int i = 0; i < sourceFiles.length; i++) { sourceFiles[i] = temp[i] } cu.addSources(sourceFiles) cu.gotoPhase 4 return false ; } }
        Hide
        Sebastian Rühl added a comment -

        Just an Update:

        I got it finally running.

        1. Put the tools.jar in a local lib folder. (I defined it now as a constraint for the client libs additionally to the groovy-all.jar)

        2. Make sure you preload the Compiler.groovy somehow... (This can be tricky, because this must be done before resolving the grapes)

        Here the final Gompiler.groovy:

        Compiler.groovy
        
        package org.apache.cxf.common.util;
        
        
        import java.io.File;
        
        import org.codehaus.groovy.control.CompilerConfiguration;
        import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit;
        
        /**
         * To enable the use of GroovyClassLoader
         * @author sruehl
         *
         */
        public class Compiler {
        	
        	public boolean compileFiles(String[] files, File outputDir) {
        		def args = ["-d",outputDir.getAbsolutePath()]
        		files.each { args << it }
        		return internalCompile(args as String[], 2);
        	}
        	
        	public boolean internalCompile(String[] args, int sourceFileIndex) {
        		File outputDir;
        		findTargetDir: for (int i = 0; i < args.length; i++) {
        			if (args[i] == '-d') {
        				outputDir = new File(args[i+1])
        				break findTargetDir
        			}
        		}
        		if (outputDir == null) {
        			return false
        		}
        		try {
        			CompilerConfiguration compilerConfiguration = new CompilerConfiguration()
        			
        			compilerConfiguration.targetDirectory = outputDir
        			compilerConfiguration.jointCompilationOptions = [stubDir:outputDir,keepStubs:true]
        			compilerConfiguration.targetBytecode = "1.5"
        			
        			JavaAwareCompilationUnit cu = new JavaAwareCompilationUnit(compilerConfiguration)
        			// Very important
        			cu.classLoader = getClass().getClassLoader();
        			
        			cu.addSources(args[sourceFileIndex..args.length-1] as String[])
        			
        			cu.gotoPhase 4
        			
        			return true
        		} catch (Throwable t) {
        			def traceString = "" << t << "" << t.cause << "\n"
        			t.stackTrace.each {traceElement -> traceString << " |-- $traceElement \n" }
        			println traceString
        			return false
        		}
        	}
        	
        }
        
        
        Show
        Sebastian Rühl added a comment - Just an Update: I got it finally running. 1. Put the tools.jar in a local lib folder. (I defined it now as a constraint for the client libs additionally to the groovy-all.jar) 2. Make sure you preload the Compiler.groovy somehow... (This can be tricky, because this must be done before resolving the grapes) Here the final Gompiler.groovy: Compiler.groovy package org.apache.cxf.common.util; import java.io.File; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit; /** * To enable the use of GroovyClassLoader * @author sruehl * */ public class Compiler { public boolean compileFiles( String [] files, File outputDir) { def args = [ "-d" ,outputDir.getAbsolutePath()] files.each { args << it } return internalCompile(args as String [], 2); } public boolean internalCompile( String [] args, int sourceFileIndex) { File outputDir; findTargetDir: for ( int i = 0; i < args.length; i++) { if (args[i] == '-d') { outputDir = new File(args[i+1]) break findTargetDir } } if (outputDir == null ) { return false } try { CompilerConfiguration compilerConfiguration = new CompilerConfiguration() compilerConfiguration.targetDirectory = outputDir compilerConfiguration.jointCompilationOptions = [stubDir:outputDir,keepStubs: true ] compilerConfiguration.targetBytecode = "1.5" JavaAwareCompilationUnit cu = new JavaAwareCompilationUnit(compilerConfiguration) // Very important cu.classLoader = getClass().getClassLoader(); cu.addSources(args[sourceFileIndex..args.length-1] as String []) cu.gotoPhase 4 return true } catch (Throwable t) { def traceString = "" << t << " " << t.cause << " \n" t.stackTrace.each {traceElement -> traceString << " |-- $traceElement \n" } println traceString return false } } }
        Hide
        Guillaume ALLEON added a comment -

        Thanks Sébastien
        Will have a close look to your proposal and will probably have a match to apply

        Show
        Guillaume ALLEON added a comment - Thanks Sébastien Will have a close look to your proposal and will probably have a match to apply
        Hide
        Sebastian Rühl added a comment -

        So I just have another Idea

        In the org.apache.cxf.endpoint.dynamic.DynamicClientFactory the JAXBContext will be created with the ClassLoader as argument. So this ClassLoader will be used to loadClasses from ObjectFactory or the index File.
        So if we would provide at this place a GroovyClassLoader there are a few things that would become obsolete.

        First we just create groovy files instead of javaFiles... (maybe we won't even need to create them)
        For this we need to adjust the JAXBUtils to create groovy Files ([] vs {} in groovy Annotations)

        Then we just add these to the groovyClassLoader and create the JAXBContext with this...
        So for JAXB it should make no difference if it's a groovy or Java Object (Except from the metaclass Problem)

        This way we would have no dependency on the javac...

        Show
        Sebastian Rühl added a comment - So I just have another Idea In the org.apache.cxf.endpoint.dynamic.DynamicClientFactory the JAXBContext will be created with the ClassLoader as argument. So this ClassLoader will be used to loadClasses from ObjectFactory or the index File. So if we would provide at this place a GroovyClassLoader there are a few things that would become obsolete. First we just create groovy files instead of javaFiles... (maybe we won't even need to create them) For this we need to adjust the JAXBUtils to create groovy Files ([] vs {} in groovy Annotations) Then we just add these to the groovyClassLoader and create the JAXBContext with this... So for JAXB it should make no difference if it's a groovy or Java Object (Except from the metaclass Problem) This way we would have no dependency on the javac...

          People

          • Assignee:
            Guillaume ALLEON
            Reporter:
            Sebastian Rühl
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: