Avatar billede p_gaard Juniormester
23. oktober 2008 - 13:26 Der er 13 kommentarer og
1 løsning

Java problem i apache webapplikation

Nedenstående java kode fungerer fint når det afvikles inde i eclipse. Der oprettes en klasse i memory som efterfølgende kompileres og der kaldes en metode.

Der opstår til gengæld et problem når jeg kører klassen i Tomcat (WEB-INF/pkkcms_lib). Java version i apache sat til jdk1.6.0_010.

Følgende fremgår af apache's consol:

compile-status:true
NullPointerException
      at SpecialClassLoader.findClass(JC16.java:195)
      at java.lang.classLoader.loadClass(ClassLoader.java:307)
      ...
      ...

- Det ser ud til at klassen kompileres fint. Problemet opstår efterfølgende i linjen "Class<?> c = Class.forName("content", false, xcl);".


---------------------------------------------------------------


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;

import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.io.*;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;

public class JC16x {


    public static void testMemoryMemory() throws Exception {
        //String cx=ReadTextFile.readTextFile(new File("C:/Program Files/Apache Software Foundation/Tomcat 5.5/webapps/pkkcms/WEB-INF/pkkcms_lib/content.java"),"cp1252").toString();
       
        // denne tekstfil skal senere nedlægges og kun oprettes som streng.
        String cx=ReadTextFile.readTextFile(new File("C:/dmi/java2/pkkcms_268/content.java"),"cp1252").toString();
        String src = cx;
        SpecialClassLoader xcl = new SpecialClassLoader();
        compileMemoryMemory(src, "content", xcl, System.err);
        Class<?> c = Class.forName("content", false, xcl);
        Object o = c.newInstance();
        c.getMethod("content", new Class[] {}).invoke(o, new Object[] { });

    }
    public static void compileMemoryMemory(String src, String name, SpecialClassLoader xcl, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        SpecialJavaFileManager xfm = new SpecialJavaFileManager(sjfm, xcl);
        //CompilationTask compile = javac.getTask(null, xfm, diacol, Arrays.asList(new String[] {"-classpath", "C:/Program Files/Apache Software Foundation/Tomcat 5.5/webapps/pkkcms/WEB-INF/pkkcms_lib"}), null,
        //                                        Arrays.asList(new JavaFileObject[] { new MemorySource(name, src) }));
        CompilationTask compile = javac.getTask(null, xfm, diacol, Arrays.asList(new String[] {"-classpath", "C:/dmi/java2/pkkcms_268/"}), null,
                Arrays.asList(new JavaFileObject[] { new MemorySource(name, src) }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
}

class MemorySource extends SimpleJavaFileObject {
    private String src;
    public MemorySource(String name, String src) {
        super(URI.create("string:///" + name + ".java"), Kind.SOURCE);
        this.src = src;
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return src;
    }
    public OutputStream openOutputStream() {
        throw new IllegalStateException();
    }
    public InputStream openInputStream() {
        return new ByteArrayInputStream(src.getBytes());
    }
}

class MemoryByteCode extends SimpleJavaFileObject {
    private ByteArrayOutputStream baos;
    public MemoryByteCode(String name) {
        super(URI.create("byte:///" + name + ".class"), Kind.CLASS);
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        throw new IllegalStateException();
    }
    public OutputStream openOutputStream() {
        baos = new ByteArrayOutputStream();
        return baos;
    }
    public InputStream openInputStream() {
        throw new IllegalStateException();
    }
    public byte[] getBytes() {
        return baos.toByteArray();
    }
}

class SpecialJavaFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
    private SpecialClassLoader xcl;
    public SpecialJavaFileManager(StandardJavaFileManager sjfm, SpecialClassLoader xcl) {
        super(sjfm);
        this.xcl = xcl;
    }
    public JavaFileObject getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
        MemoryByteCode mbc = new MemoryByteCode(name);
        xcl.addClass(name, mbc);
        return mbc;
    }
}

class SpecialClassLoader extends ClassLoader {
    private Map<String,MemoryByteCode> m;
    public SpecialClassLoader() {
        m = new HashMap<String, MemoryByteCode>();
    }
    protected Class<?> findClass(String name) {


        MemoryByteCode mbc = m.get(name);
        return defineClass(name, mbc.getBytes(), 0, mbc.getBytes().length);
    }
    public void addClass(String name, MemoryByteCode mbc) {
        m.put(name, mbc);
    }
}
Avatar billede arne_v Ekspert
25. oktober 2008 - 04:39 #1
Så vidt jeg kan se, så har min kode problemer med både packages og med andre klasser der
skal bruges - sidstnævnte muligvis kun i forbindelse med classloader hierakier.

Jeg har prøvet at lave en fix.
Avatar billede arne_v Ekspert
25. oktober 2008 - 04:40 #2
class MemorySource extends SimpleJavaFileObject {
    private String src;
    public MemorySource(String name, String src) {
        super(URI.create("string:///" + name.replace(".", "/") + ".java"), Kind.SOURCE);
        this.src = src;
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return src;
    }
    public OutputStream openOutputStream() {
        throw new IllegalStateException();
    }
    public InputStream openInputStream() {
        return new ByteArrayInputStream(src.getBytes());
    }
}

class MemoryByteCode extends SimpleJavaFileObject {
    private ByteArrayOutputStream baos;
    public MemoryByteCode(String name) {
        super(URI.create("byte:///" + name.replace(".", "/") + ".class"), Kind.CLASS);
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        throw new IllegalStateException();
    }
    public OutputStream openOutputStream() {
        baos = new ByteArrayOutputStream();
        return baos;
    }
    public InputStream openInputStream() {
        throw new IllegalStateException();
    }
    public byte[] getBytes() {
        return baos.toByteArray();
    }
}

class SpecialJavaFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
    private SpecialClassLoader xcl;
    public SpecialJavaFileManager(StandardJavaFileManager sjfm, SpecialClassLoader xcl) {
        super(sjfm);
        this.xcl = xcl;
    }
    public JavaFileObject getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
        name = sibling.getName().substring(1, sibling.getName().length() - 5).replace("/", ".");
        MemoryByteCode mbc = new MemoryByteCode(name);
        xcl.addClass(name, mbc);
        return mbc;
    }
}

class SpecialClassLoader extends ClassLoader {
    private Map<String,MemoryByteCode> m;
    public SpecialClassLoader() {
        super(SpecialClassLoader.class.getClassLoader());
        m = new HashMap<String, MemoryByteCode>();
    }
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        MemoryByteCode mbc = m.get(name);
        if(mbc != null) {
            return defineClass(name, mbc.getBytes(), 0, mbc.getBytes().length);
        } else {
            throw new ClassNotFoundException(name);
        }
    }
    public void addClass(String name, MemoryByteCode mbc) {
        m.put(name, mbc);
    }
}
Avatar billede arne_v Ekspert
25. oktober 2008 - 04:40 #3
Prøv og se om det virker for dig.
Avatar billede p_gaard Juniormester
27. oktober 2008 - 15:55 #4
Jeg har prøvet det af.

Den melder nu bla.

InvocationTargetException

og

IllegalAccessError: Tried to access field elements.name from class content

Klassen 'content' som indlæses med ClassLoaderen nedarver en del felter fra superklassen 'elements'.

Jeg synes at være et skridt nærmere. Nu er det til at se at den læser klassen content's, men at der er problemer i forb. med nedarvingen.
Avatar billede arne_v Ekspert
27. oktober 2008 - 16:01 #5
Er der public paa det som skal vaere public ?
Avatar billede p_gaard Juniormester
28. oktober 2008 - 10:13 #6
Så kører det! Det kører lidt hurtigere (mindst 1 sek) end den gamle løsning hvor klassen blev skrevet og kompileret på harddisken. Man kan nå at røre en ekstra gang i kaffen mens man venter.

Sidste ting jeg skal have til at falde på plads er kompileringsloggen. Det er vigtigt at systemet skriver en kompileringlog over syntaksfejl i selve klassen der bliver kompileret, klassen 'content'. Det gjorde den gamle løsning som bla. anvendte nedenstående linjer.

//PrintWriter pw13=new PrintWriter("C:/Program files/........./content.log");
//String[] filer = { "-classpath", "C:/Program files/.........../content.java"};
//com.sun.tools.javac.Main.compile(filer, pw13);

Udførlig kompileringslog blev skrevet i looggen via pw13, hvad der var gået galt i klassen og ikke udenfor. Dvs. ikke kun at content.class ej findes efter kompileringsforsøget osv....)
Avatar billede p_gaard Juniormester
28. oktober 2008 - 23:30 #7
Ovenstående fejl er løst nu.

Jeg takker meget for din hjælp!
Avatar billede p_gaard Juniormester
28. oktober 2008 - 23:31 #8
point
Avatar billede arne_v Ekspert
28. oktober 2008 - 23:46 #9
Ja tak.
Avatar billede arne_v Ekspert
28. oktober 2008 - 23:46 #10
Jeg antager at løsningen på den samlede log var at kalde med en PrintWriter som wrappede
en FileOutputStream med append true.
Avatar billede p_gaard Juniormester
04. november 2008 - 11:50 #11
Det skal undersøges nærmere.

Pointgivningsfunktionen er ikke alt for god på eksperten. Jeg skal nu give dig point og har kun mulighed for at markere mig selv 'p_gaard' (hvad menes med det?). Det håber jeg bliver bedre i den nye version.

Får jeg selv disse point er det en fejl og så skal jeg gerne oprette et 'dummy' spørgsmål til Arne V.
Avatar billede arne_v Ekspert
04. november 2008 - 20:49 #12
Jeg skal ligge et rigtigt svar. Så kan du vælge det i combo boxen inden du klikker accepter.

Jeg troede at jeg havde gjordt det 28/10-2008 23:46:05 men ...
Avatar billede arne_v Ekspert
04. november 2008 - 20:49 #13
Så skulle den gerne være på plads.
Avatar billede p_gaard Juniormester
05. november 2008 - 09:57 #14
Tak for hjælpen!
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester