001/*
002 * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. 
003 * Use is subject to license terms.
004 *
005 * Redistribution and use in source and binary forms, with or without modification, are 
006 * permitted provided that the following conditions are met: Redistributions of source code 
007 * must retain the above copyright notice, this list of conditions and the following disclaimer.
008 * Redistributions in binary form must reproduce the above copyright notice, this list of 
009 * conditions and the following disclaimer in the documentation and/or other materials 
010 * provided with the distribution. Neither the name of the Sun Microsystems nor the names of 
011 * is contributors may be used to endorse or promote products derived from this software 
012 * without specific prior written permission. 
013
014 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
015 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
016 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
017 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
018 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
019 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
020 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
021 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
022 * POSSIBILITY OF SUCH DAMAGE.
023 */
024
025/*
026 * MemoryJavaFileManager.java
027 * @author A. Sundararajan
028 */
029
030package org.kepler.scriptengine.java;
031
032import java.io.ByteArrayOutputStream;
033import java.io.File;
034import java.io.FilterOutputStream;
035import java.io.IOException;
036import java.io.OutputStream;
037import java.net.URI;
038import java.nio.CharBuffer;
039import java.util.HashMap;
040import java.util.Map;
041
042import javax.tools.FileObject;
043import javax.tools.ForwardingJavaFileManager;
044import javax.tools.JavaFileManager;
045import javax.tools.JavaFileObject;
046import javax.tools.JavaFileObject.Kind;
047import javax.tools.SimpleJavaFileObject;
048
049/**
050 * JavaFileManager that keeps compiled .class bytes in memory.
051 */
052public final class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {                 
053
054    /** Java source file extension. */
055    private final static String EXT = ".java";
056
057    private Map<String, byte[]> classBytes;
058    
059    public MemoryJavaFileManager(JavaFileManager fileManager) {
060        super(fileManager);
061        classBytes = new HashMap<String, byte[]>();
062    }
063
064    public Map<String, byte[]> getClassBytes() {
065        return classBytes;
066    }
067   
068    @Override
069        public void close() throws IOException {
070        classBytes = new HashMap<String, byte[]>();
071    }
072
073    @Override
074        public void flush() throws IOException {
075    }
076
077    /**
078     * A file object used to represent Java source coming from a string.
079     */
080    private static class StringInputBuffer extends SimpleJavaFileObject {
081        final String code;
082        
083        StringInputBuffer(String name, String code) {
084            super(toURI(name), Kind.SOURCE);
085            this.code = code;
086        }
087        
088        @Override
089                public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
090            return CharBuffer.wrap(code);
091        }
092
093        /*
094        public Reader openReader() {
095            return new StringReader(code);
096        }
097        */
098    }
099
100    /**
101     * A file object that stores Java bytecode into the classBytes map.
102     */
103    private class ClassOutputBuffer extends SimpleJavaFileObject {
104        private String name;
105
106        ClassOutputBuffer(String name) { 
107            super(toURI(name), Kind.CLASS);
108            this.name = name;
109        }
110
111        @Override
112                public OutputStream openOutputStream() {
113            return new FilterOutputStream(new ByteArrayOutputStream()) {
114                @Override
115                                public void close() throws IOException {
116                    out.close();
117                    ByteArrayOutputStream bos = (ByteArrayOutputStream)out;
118                    classBytes.put(name, bos.toByteArray());
119                }
120            };
121        }
122    }
123    
124    @Override
125        public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location,
126                                    String className,
127                                    Kind kind,
128                                    FileObject sibling) throws IOException {
129        if (kind == Kind.CLASS) {
130            return new ClassOutputBuffer(className);
131        } else {
132            return super.getJavaFileForOutput(location, className, kind, sibling);
133        }
134    }
135
136    static JavaFileObject makeStringSource(String name, String code) {
137        return new StringInputBuffer(name, code);
138    }
139
140    static URI toURI(String name) {
141        File file = new File(name);
142        if (file.exists()) {
143            return file.toURI();
144        } else {
145            try {
146                final StringBuilder newUri = new StringBuilder();
147                newUri.append("mfm:///");
148                newUri.append(name.replace('.', '/'));
149                if(name.endsWith(EXT)) newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT);
150                return URI.create(newUri.toString());
151            } catch (Exception exp) {
152                return URI.create("mfm:///com/sun/script/java/java_source");
153            }
154        }
155    }
156}