1 /* 2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.codemodel.internal.fmt; 27 28 import java.io.BufferedReader; 29 import java.io.BufferedWriter; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.InputStreamReader; 33 import java.io.OutputStream; 34 import java.io.OutputStreamWriter; 35 import java.io.PrintWriter; 36 import java.net.URL; 37 import java.text.ParseException; 38 import java.util.Iterator; 39 import java.util.List; 40 41 import com.sun.codemodel.internal.JClass; 42 import com.sun.codemodel.internal.JPackage; 43 import com.sun.codemodel.internal.JResourceFile; 44 import com.sun.codemodel.internal.JTypeVar; 45 46 /** 47 * Statically generated Java soruce file. 48 * 49 * <p> 50 * This {@link JResourceFile} implementation will generate a Java source 51 * file by copying the source code from a resource. 52 * <p> 53 * While copying a resource, we look for a package declaration and 54 * replace it with the target package name. This allows the static Java 55 * source code to have an arbitrary package declaration. 56 * <p> 57 * You can also use the getJClass method to obtain a {@link JClass} 58 * object that represents the static file. This allows the client code 59 * to refer to the class from other CodeModel generated code. 60 * <p> 61 * Note that because we don't parse the static Java source code, 62 * the returned {@link JClass} object doesn't respond to methods like 63 * "isInterface" or "_extends", 64 * 65 * @author 66 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 67 */ 68 public final class JStaticJavaFile extends JResourceFile { 69 70 private final JPackage pkg; 71 private final String className; 72 private final URL source; 73 private final JStaticClass clazz; 74 private final LineFilter filter; 75 76 public JStaticJavaFile(JPackage _pkg, String className, String _resourceName) { 77 this( _pkg, className, 78 SecureLoader.getClassClassLoader(JStaticJavaFile.class).getResource(_resourceName), null ); 79 } 80 81 public JStaticJavaFile(JPackage _pkg, String _className, URL _source, LineFilter _filter ) { 82 super(_className+".java"); 83 if(_source==null) throw new NullPointerException(); 84 this.pkg = _pkg; 85 this.clazz = new JStaticClass(); 86 this.className = _className; 87 this.source = _source; 88 this.filter = _filter; 89 } 90 91 /** 92 * Returns a class object that represents a statically generated code. 93 */ 94 public final JClass getJClass() { 95 return clazz; 96 } 97 98 protected boolean isResource() { 99 return false; 100 } 101 102 protected void build(OutputStream os) throws IOException { 103 InputStream is = source.openStream(); 104 105 BufferedReader r = new BufferedReader(new InputStreamReader(is)); 106 PrintWriter w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(os))); 107 LineFilter filter = createLineFilter(); 108 int lineNumber=1; 109 110 try { 111 String line; 112 while((line=r.readLine())!=null) { 113 line = filter.process(line); 114 if(line!=null) 115 w.println(line); 116 lineNumber++; 117 } 118 } catch( ParseException e ) { 119 throw new IOException("unable to process "+source+" line:"+lineNumber+"\n"+e.getMessage()); 120 } 121 122 w.close(); 123 r.close(); 124 } 125 126 /** 127 * Creates a {@link LineFilter}. 128 * <p> 129 * A derived class can override this method to process 130 * the contents of the source file. 131 */ 132 private LineFilter createLineFilter() { 133 // this filter replaces the package declaration. 134 LineFilter f = new LineFilter() { 135 public String process(String line) { 136 if(!line.startsWith("package ")) return line; 137 138 // replace package decl 139 if( pkg.isUnnamed() ) 140 return null; 141 else 142 return "package "+pkg.name()+";"; 143 } 144 }; 145 if( filter!=null ) 146 return new ChainFilter(filter,f); 147 else 148 return f; 149 } 150 151 /** 152 * Filter that alters the Java source code. 153 * <p> 154 * By implementing this interface, derived classes 155 * can modify the Java source file before it's written out. 156 */ 157 public interface LineFilter { 158 /** 159 * @param line 160 * a non-null valid String that corresponds to one line. 161 * No '\n' included. 162 * @return 163 * null to strip the line off. Otherwise the returned 164 * String will be written out. Do not add '\n' at the end 165 * of this string. 166 * 167 * @exception ParseException 168 * when for some reason there's an error in the line. 169 */ 170 String process(String line) throws ParseException; 171 } 172 173 /** 174 * A {@link LineFilter} that combines two {@link LineFilter}s. 175 */ 176 public final static class ChainFilter implements LineFilter { 177 private final LineFilter first,second; 178 public ChainFilter( LineFilter first, LineFilter second ) { 179 this.first=first; 180 this.second=second; 181 } 182 public String process(String line) throws ParseException { 183 line = first.process(line); 184 if(line==null) return null; 185 return second.process(line); 186 } 187 } 188 189 190 private class JStaticClass extends JClass { 191 192 private final JTypeVar[] typeParams; 193 194 JStaticClass() { 195 super(pkg.owner()); 196 // TODO: allow those to be specified 197 typeParams = new JTypeVar[0]; 198 } 199 200 public String name() { 201 return className; 202 } 203 204 public String fullName() { 205 if(pkg.isUnnamed()) 206 return className; 207 else 208 return pkg.name()+'.'+className; 209 } 210 211 public JPackage _package() { 212 return pkg; 213 } 214 215 public JClass _extends() { 216 throw new UnsupportedOperationException(); 217 } 218 219 public Iterator<JClass> _implements() { 220 throw new UnsupportedOperationException(); 221 } 222 223 public boolean isInterface() { 224 throw new UnsupportedOperationException(); 225 } 226 227 public boolean isAbstract() { 228 throw new UnsupportedOperationException(); 229 } 230 231 public JTypeVar[] typeParams() { 232 return typeParams; 233 } 234 235 protected JClass substituteParams(JTypeVar[] variables, List<JClass> bindings) { 236 return this; 237 } 238 }; 239 }