0001: /*
0002: * Copyright 1999,2004 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.apache.jasper;
0018:
0019: import java.io.BufferedReader;
0020: import java.io.CharArrayWriter;
0021: import java.io.File;
0022: import java.io.FileInputStream;
0023: import java.io.FileNotFoundException;
0024: import java.io.FileOutputStream;
0025: import java.io.FileReader;
0026: import java.io.FileWriter;
0027: import java.io.IOException;
0028: import java.io.PrintWriter;
0029: import java.io.Writer;
0030: import java.net.MalformedURLException;
0031: import java.net.URL;
0032: import java.net.URLClassLoader;
0033: import java.util.ArrayList;
0034: import java.util.Enumeration;
0035: import java.util.Stack;
0036: import java.util.StringTokenizer;
0037: import java.util.Vector;
0038:
0039: import org.apache.commons.logging.Log;
0040: import org.apache.commons.logging.LogFactory;
0041: import org.apache.jasper.compiler.Compiler;
0042: import org.apache.jasper.compiler.JspConfig;
0043: import org.apache.jasper.compiler.JspRuntimeContext;
0044: import org.apache.jasper.compiler.Localizer;
0045: import org.apache.jasper.compiler.TagPluginManager;
0046: import org.apache.jasper.compiler.TldLocationsCache;
0047: import org.apache.jasper.servlet.JspCServletContext;
0048: import org.apache.tools.ant.AntClassLoader;
0049:
0050: /**
0051: * Shell for the jspc compiler. Handles all options associated with the
0052: * command line and creates compilation contexts which it then compiles
0053: * according to the specified options.
0054: *
0055: * This version can process files from a _single_ webapp at once, i.e.
0056: * a single docbase can be specified.
0057: *
0058: * It can be used as an Ant task using:
0059: * <pre>
0060: * <taskdef classname="org.apache.jasper.JspC" name="jasper2" >
0061: * <classpath>
0062: * <pathelement location="${java.home}/../lib/tools.jar"/>
0063: * <fileset dir="${ENV.CATALINA_HOME}/server/lib">
0064: * <include name="*.jar"/>
0065: * </fileset>
0066: * <fileset dir="${ENV.CATALINA_HOME}/common/lib">
0067: * <include name="*.jar"/>
0068: * </fileset>
0069: * <path refid="myjars"/>
0070: * </classpath>
0071: * </taskdef>
0072: *
0073: * <jasper2 verbose="0"
0074: * package="my.package"
0075: * uriroot="${webapps.dir}/${webapp.name}"
0076: * webXmlFragment="${build.dir}/generated_web.xml"
0077: * outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
0078: * </pre>
0079: *
0080: * @author Danno Ferrin
0081: * @author Pierre Delisle
0082: * @author Costin Manolache
0083: */
0084: public class JspC implements Options {
0085:
0086: public static final String DEFAULT_IE_CLASS_ID = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
0087:
0088: // Logger
0089: private static Log log = LogFactory.getLog(JspC.class);
0090:
0091: private static final String SWITCH_VERBOSE = "-v";
0092: private static final String SWITCH_HELP = "-help";
0093: private static final String SWITCH_QUIET = "-q";
0094: private static final String SWITCH_OUTPUT_DIR = "-d";
0095: private static final String SWITCH_IE_CLASS_ID = "-ieplugin";
0096: private static final String SWITCH_PACKAGE_NAME = "-p";
0097: private static final String SWITCH_CLASS_NAME = "-c";
0098: private static final String SWITCH_FULL_STOP = "--";
0099: private static final String SWITCH_COMPILE = "-compile";
0100: private static final String SWITCH_URI_BASE = "-uribase";
0101: private static final String SWITCH_URI_ROOT = "-uriroot";
0102: private static final String SWITCH_FILE_WEBAPP = "-webapp";
0103: private static final String SWITCH_WEBAPP_INC = "-webinc";
0104: private static final String SWITCH_WEBAPP_XML = "-webxml";
0105: private static final String SWITCH_MAPPED = "-mapped";
0106: private static final String SWITCH_XPOWERED_BY = "-xpoweredBy";
0107: private static final String SWITCH_TRIM_SPACES = "-trimSpaces";
0108: private static final String SWITCH_CLASSPATH = "-classpath";
0109: private static final String SWITCH_DIE = "-die";
0110: private static final String SWITCH_POOLING = "-poolingEnabled";
0111: private static final String SWITCH_ENCODING = "-javaEncoding";
0112: private static final String SHOW_SUCCESS = "-s";
0113: private static final String LIST_ERRORS = "-l";
0114: private static final int NO_WEBXML = 0;
0115: private static final int INC_WEBXML = 10;
0116: private static final int ALL_WEBXML = 20;
0117: private static final int DEFAULT_DIE_LEVEL = 1;
0118: private static final int NO_DIE_LEVEL = 0;
0119:
0120: private static final String[] insertBefore = { "</web-app>",
0121: "<servlet-mapping>", "<session-config>", "<mime-mapping>",
0122: "<welcome-file-list>", "<error-page>", "<taglib>",
0123: "<resource-env-ref>", "<resource-ref>",
0124: "<security-constraint>", "<login-config>",
0125: "<security-role>", "<env-entry>", "<ejb-ref>",
0126: "<ejb-local-ref>" };
0127:
0128: private static int die;
0129: private String classPath = null;
0130: private URLClassLoader loader = null;
0131: private boolean trimSpaces = false;
0132: private boolean genStringAsCharArray = false;
0133: private boolean xpoweredBy;
0134: private boolean mappedFile = false;
0135: private boolean poolingEnabled = true;
0136: private File scratchDir;
0137: private String ieClassId = DEFAULT_IE_CLASS_ID;
0138: private String targetPackage;
0139: private String targetClassName;
0140: private String uriBase;
0141: private String uriRoot;
0142: private int dieLevel;
0143: private boolean helpNeeded = false;
0144: private boolean compile = false;
0145: private String compiler = null;
0146: private boolean classDebugInfo = true;
0147: private Vector extensions;
0148: private Vector pages = new Vector();
0149: private boolean errorOnUseBeanInvalidClassAttribute = true;
0150:
0151: /**
0152: * The java file encoding. Default
0153: * is UTF-8. Added per bugzilla 19622.
0154: */
0155: private String javaEncoding = "UTF-8";
0156:
0157: // Generation of web.xml fragments
0158: private String webxmlFile;
0159: private int webxmlLevel;
0160: private boolean addWebXmlMappings = false;
0161:
0162: private Writer mapout;
0163: private CharArrayWriter servletout;
0164: private CharArrayWriter mappingout;
0165:
0166: private JspCServletContext context;
0167:
0168: // Maintain a dummy JspRuntimeContext for compiling tag files
0169: private JspRuntimeContext rctxt;
0170:
0171: /**
0172: * Cache for the TLD locations
0173: */
0174: private TldLocationsCache tldLocationsCache = null;
0175:
0176: private JspConfig jspConfig = null;
0177: private TagPluginManager tagPluginManager = null;
0178:
0179: private boolean verbose = false;
0180: private boolean listErrors = false;
0181: private boolean showSuccess = false;
0182: private int argPos;
0183: private boolean fullstop = false;
0184: private String args[];
0185:
0186: public static void main(String arg[]) {
0187: if (arg.length == 0) {
0188: System.out.println(Localizer.getMessage("jspc.usage"));
0189: } else {
0190: try {
0191: JspC jspc = new JspC();
0192: jspc.setArgs(arg);
0193: if (jspc.helpNeeded) {
0194: System.out.println(Localizer
0195: .getMessage("jspc.usage"));
0196: } else {
0197: jspc.execute();
0198: }
0199: } catch (JasperException je) {
0200: System.err.println(je);
0201: //System.err.println(je.getMessage());
0202: if (die != NO_DIE_LEVEL) {
0203: System.exit(die);
0204: }
0205: }
0206: }
0207: }
0208:
0209: public void setArgs(String[] arg) throws JasperException {
0210: args = arg;
0211: String tok;
0212:
0213: dieLevel = NO_DIE_LEVEL;
0214: die = dieLevel;
0215:
0216: while ((tok = nextArg()) != null) {
0217: if (tok.equals(SWITCH_VERBOSE)) {
0218: verbose = true;
0219: showSuccess = true;
0220: listErrors = true;
0221: } else if (tok.equals(SWITCH_OUTPUT_DIR)) {
0222: tok = nextArg();
0223: setOutputDir(tok);
0224: } else if (tok.equals(SWITCH_PACKAGE_NAME)) {
0225: targetPackage = nextArg();
0226: } else if (tok.equals(SWITCH_COMPILE)) {
0227: compile = true;
0228: } else if (tok.equals(SWITCH_CLASS_NAME)) {
0229: targetClassName = nextArg();
0230: } else if (tok.equals(SWITCH_URI_BASE)) {
0231: uriBase = nextArg();
0232: } else if (tok.equals(SWITCH_URI_ROOT)) {
0233: setUriroot(nextArg());
0234: } else if (tok.equals(SWITCH_FILE_WEBAPP)) {
0235: setUriroot(nextArg());
0236: } else if (tok.equals(SHOW_SUCCESS)) {
0237: showSuccess = true;
0238: } else if (tok.equals(LIST_ERRORS)) {
0239: listErrors = true;
0240: } else if (tok.equals(SWITCH_WEBAPP_INC)) {
0241: webxmlFile = nextArg();
0242: if (webxmlFile != null) {
0243: webxmlLevel = INC_WEBXML;
0244: }
0245: } else if (tok.equals(SWITCH_WEBAPP_XML)) {
0246: webxmlFile = nextArg();
0247: if (webxmlFile != null) {
0248: webxmlLevel = ALL_WEBXML;
0249: }
0250: } else if (tok.equals(SWITCH_MAPPED)) {
0251: mappedFile = true;
0252: } else if (tok.equals(SWITCH_XPOWERED_BY)) {
0253: xpoweredBy = true;
0254: } else if (tok.equals(SWITCH_TRIM_SPACES)) {
0255: setTrimSpaces(true);
0256: } else if (tok.equals(SWITCH_CLASSPATH)) {
0257: setClassPath(nextArg());
0258: } else if (tok.startsWith(SWITCH_DIE)) {
0259: try {
0260: dieLevel = Integer.parseInt(tok
0261: .substring(SWITCH_DIE.length()));
0262: } catch (NumberFormatException nfe) {
0263: dieLevel = DEFAULT_DIE_LEVEL;
0264: }
0265: die = dieLevel;
0266: } else if (tok.equals(SWITCH_HELP)) {
0267: helpNeeded = true;
0268: } else if (tok.equals(SWITCH_POOLING)) {
0269: tok = nextArg();
0270: if ("false".equals(tok)) {
0271: poolingEnabled = false;
0272: } else {
0273: poolingEnabled = true;
0274: }
0275: } else if (tok.equals(SWITCH_ENCODING)) {
0276: setJavaEncoding(nextArg());
0277: } else {
0278: if (tok.startsWith("-")) {
0279: throw new JasperException("Unrecognized option: "
0280: + tok + ". Use -help for help.");
0281: }
0282: if (!fullstop) {
0283: argPos--;
0284: }
0285: // Start treating the rest as JSP Pages
0286: break;
0287: }
0288: }
0289:
0290: // Add all extra arguments to the list of files
0291: while (true) {
0292: String file = nextFile();
0293: if (file == null)
0294: break;
0295: pages.addElement(file);
0296: }
0297: }
0298:
0299: public boolean getKeepGenerated() {
0300: // isn't this why we are running jspc?
0301: return true;
0302: }
0303:
0304: public boolean getTrimSpaces() {
0305: return trimSpaces;
0306: }
0307:
0308: public void setTrimSpaces(boolean ts) {
0309: this .trimSpaces = ts;
0310: }
0311:
0312: public boolean isPoolingEnabled() {
0313: return poolingEnabled;
0314: }
0315:
0316: public void setPoolingEnabled(boolean poolingEnabled) {
0317: this .poolingEnabled = poolingEnabled;
0318: }
0319:
0320: public boolean isXpoweredBy() {
0321: return xpoweredBy;
0322: }
0323:
0324: public void setXpoweredBy(boolean xpoweredBy) {
0325: this .xpoweredBy = xpoweredBy;
0326: }
0327:
0328: public boolean getErrorOnUseBeanInvalidClassAttribute() {
0329: return errorOnUseBeanInvalidClassAttribute;
0330: }
0331:
0332: public void setErrorOnUseBeanInvalidClassAttribute(boolean b) {
0333: errorOnUseBeanInvalidClassAttribute = b;
0334: }
0335:
0336: public int getTagPoolSize() {
0337: return Constants.MAX_POOL_SIZE;
0338: }
0339:
0340: /**
0341: * Are we supporting HTML mapped servlets?
0342: */
0343: public boolean getMappedFile() {
0344: return mappedFile;
0345: }
0346:
0347: // Off-line compiler, no need for security manager
0348: public Object getProtectionDomain() {
0349: return null;
0350: }
0351:
0352: public boolean getSendErrorToClient() {
0353: // implied send to System.err
0354: return true;
0355: }
0356:
0357: public void setClassDebugInfo(boolean b) {
0358: classDebugInfo = b;
0359: }
0360:
0361: public boolean getClassDebugInfo() {
0362: // compile with debug info
0363: return classDebugInfo;
0364: }
0365:
0366: /**
0367: * Background compilation check intervals in seconds
0368: */
0369: public int getCheckInterval() {
0370: return 300;
0371: }
0372:
0373: /**
0374: * Is Jasper being used in development mode?
0375: */
0376: public boolean getDevelopment() {
0377: return false;
0378: }
0379:
0380: /**
0381: * JSP reloading check ?
0382: */
0383: public boolean getReloading() {
0384: return true;
0385: }
0386:
0387: /**
0388: * Is the generation of SMAP info for JSR45 debuggin suppressed?
0389: */
0390: public boolean isSmapSuppressed() {
0391: return true;
0392: }
0393:
0394: /**
0395: * Should SMAP info for JSR45 debugging be dumped to a file?
0396: */
0397: public boolean isSmapDumped() {
0398: return false;
0399: }
0400:
0401: /**
0402: * Determines whether text strings are to be generated as char arrays,
0403: * which improves performance in some cases.
0404: *
0405: * @param genStringAsCharArray true if text strings are to be generated as
0406: * char arrays, false otherwise
0407: */
0408: public void setGenStringAsCharArray(boolean genStringAsCharArray) {
0409: this .genStringAsCharArray = genStringAsCharArray;
0410: }
0411:
0412: /**
0413: * Indicates whether text strings are to be generated as char arrays.
0414: *
0415: * @return true if text strings are to be generated as char arrays, false
0416: * otherwise
0417: */
0418: public boolean genStringAsCharArray() {
0419: return genStringAsCharArray;
0420: }
0421:
0422: /**
0423: * Sets the class-id value to be sent to Internet Explorer when using
0424: * <jsp:plugin> tags.
0425: *
0426: * @param ieClassId Class-id value
0427: */
0428: public void setIeClassId(String ieClassId) {
0429: this .ieClassId = ieClassId;
0430: }
0431:
0432: /**
0433: * Gets the class-id value that is sent to Internet Explorer when using
0434: * <jsp:plugin> tags.
0435: *
0436: * @return Class-id value
0437: */
0438: public String getIeClassId() {
0439: return ieClassId;
0440: }
0441:
0442: public File getScratchDir() {
0443: return scratchDir;
0444: }
0445:
0446: public Class getJspCompilerPlugin() {
0447: // we don't compile, so this is meanlingless
0448: return null;
0449: }
0450:
0451: public String getJspCompilerPath() {
0452: // we don't compile, so this is meanlingless
0453: return null;
0454: }
0455:
0456: /**
0457: * Compiler to use.
0458: */
0459: public String getCompiler() {
0460: return compiler;
0461: }
0462:
0463: public void setCompiler(String c) {
0464: compiler = c;
0465: }
0466:
0467: public TldLocationsCache getTldLocationsCache() {
0468: return tldLocationsCache;
0469: }
0470:
0471: /**
0472: * Returns the encoding to use for
0473: * java files. The default is UTF-8.
0474: *
0475: * @return String The encoding
0476: */
0477: public String getJavaEncoding() {
0478: return javaEncoding;
0479: }
0480:
0481: /**
0482: * Sets the encoding to use for
0483: * java files.
0484: *
0485: * @param encodingName The name, e.g. "UTF-8"
0486: */
0487: public void setJavaEncoding(String encodingName) {
0488: javaEncoding = encodingName;
0489: }
0490:
0491: public boolean getFork() {
0492: return false;
0493: }
0494:
0495: public String getClassPath() {
0496: if (classPath != null)
0497: return classPath;
0498: return System.getProperty("java.class.path");
0499: }
0500:
0501: public void setClassPath(String s) {
0502: classPath = s;
0503: }
0504:
0505: /**
0506: * Base dir for the webapp. Used to generate class names and resolve
0507: * includes
0508: */
0509: public void setUriroot(String s) {
0510: if (s == null) {
0511: uriRoot = s;
0512: return;
0513: }
0514: try {
0515: uriRoot = new File(s).getCanonicalPath();
0516: } catch (Exception ex) {
0517: uriRoot = s;
0518: }
0519: }
0520:
0521: /*
0522: * Parses comma-separated list of JSP files to be processed.
0523: *
0524: * <p>Each file is interpreted relative to uriroot, unless it is absolute,
0525: * in which case it must start with uriroot.
0526: *
0527: * @param jspFiles Comma-separated list of JSP files to be processed
0528: */
0529: public void setJspFiles(String jspFiles) {
0530: StringTokenizer tok = new StringTokenizer(jspFiles, " ,");
0531: while (tok.hasMoreTokens()) {
0532: pages.addElement(tok.nextToken());
0533: }
0534: }
0535:
0536: public void setCompile(boolean b) {
0537: compile = b;
0538: }
0539:
0540: public void setVerbose(int level) {
0541: if (level > 0) {
0542: verbose = true;
0543: showSuccess = true;
0544: listErrors = true;
0545: }
0546: }
0547:
0548: public void setValidateXml(boolean b) {
0549: org.apache.jasper.xmlparser.ParserUtils.validating = b;
0550: }
0551:
0552: public void setListErrors(boolean b) {
0553: listErrors = b;
0554: }
0555:
0556: public void setOutputDir(String s) {
0557: if (s != null) {
0558: scratchDir = new File(s).getAbsoluteFile();
0559: } else {
0560: scratchDir = null;
0561: }
0562: }
0563:
0564: public void setPackage(String p) {
0565: targetPackage = p;
0566: }
0567:
0568: /**
0569: * Class name of the generated file ( without package ).
0570: * Can only be used if a single file is converted.
0571: * XXX Do we need this feature ?
0572: */
0573: public void setClassName(String p) {
0574: targetClassName = p;
0575: }
0576:
0577: /**
0578: * File where we generate a web.xml fragment with the class definitions.
0579: */
0580: public void setWebXmlFragment(String s) {
0581: webxmlFile = s;
0582: webxmlLevel = INC_WEBXML;
0583: }
0584:
0585: /**
0586: * File where we generate a complete web.xml with the class definitions.
0587: */
0588: public void setWebXml(String s) {
0589: webxmlFile = s;
0590: webxmlLevel = ALL_WEBXML;
0591: }
0592:
0593: public void setAddWebXmlMappings(boolean b) {
0594: addWebXmlMappings = b;
0595: }
0596:
0597: /**
0598: * Obtain JSP configuration informantion specified in web.xml.
0599: */
0600: public JspConfig getJspConfig() {
0601: return jspConfig;
0602: }
0603:
0604: public TagPluginManager getTagPluginManager() {
0605: return tagPluginManager;
0606: }
0607:
0608: public void generateWebMapping(String file,
0609: JspCompilationContext clctxt) throws IOException {
0610: String className = clctxt.getServletClassName();
0611: String packageName = clctxt.getServletPackageName();
0612:
0613: String this ServletName;
0614: if ("".equals(packageName)) {
0615: this ServletName = className;
0616: } else {
0617: this ServletName = packageName + '.' + className;
0618: }
0619:
0620: if (servletout != null) {
0621: servletout.write("\n <servlet>\n <servlet-name>");
0622: servletout.write(this ServletName);
0623: servletout
0624: .write("</servlet-name>\n <servlet-class>");
0625: servletout.write(this ServletName);
0626: servletout.write("</servlet-class>\n </servlet>\n");
0627: }
0628: if (mappingout != null) {
0629: mappingout
0630: .write("\n <servlet-mapping>\n <servlet-name>");
0631: mappingout.write(this ServletName);
0632: mappingout.write("</servlet-name>\n <url-pattern>");
0633: mappingout.write(file.replace('\\', '/'));
0634: mappingout
0635: .write("</url-pattern>\n </servlet-mapping>\n");
0636:
0637: }
0638: }
0639:
0640: /**
0641: * Include the generated web.xml inside the webapp's web.xml.
0642: */
0643: protected void mergeIntoWebXml() throws IOException {
0644:
0645: File webappBase = new File(uriRoot);
0646: File webXml = new File(webappBase, "WEB-INF/web.xml");
0647: File webXml2 = new File(webappBase, "WEB-INF/web2.xml");
0648: String insertStartMarker = Localizer
0649: .getMessage("jspc.webinc.insertStart");
0650: String insertEndMarker = Localizer
0651: .getMessage("jspc.webinc.insertEnd");
0652:
0653: BufferedReader reader = new BufferedReader(new FileReader(
0654: webXml));
0655: BufferedReader fragmentReader = new BufferedReader(
0656: new FileReader(webxmlFile));
0657: PrintWriter writer = new PrintWriter(new FileWriter(webXml2));
0658:
0659: // Insert the <servlet> and <servlet-mapping> declarations
0660: int pos = -1;
0661: String line = null;
0662: while (true) {
0663: line = reader.readLine();
0664: if (line == null) {
0665: break;
0666: }
0667: // Skip anything previously generated by JSPC
0668: if (line.indexOf(insertStartMarker) >= 0) {
0669: while (true) {
0670: line = reader.readLine();
0671: if (line == null) {
0672: return;
0673: }
0674: if (line.indexOf(insertEndMarker) >= 0) {
0675: line = reader.readLine();
0676: if (line == null) {
0677: return;
0678: }
0679: break;
0680: }
0681: }
0682: }
0683: for (int i = 0; i < insertBefore.length; i++) {
0684: pos = line.indexOf(insertBefore[i]);
0685: if (pos >= 0)
0686: break;
0687: }
0688: if (pos >= 0) {
0689: writer.println(line.substring(0, pos));
0690: break;
0691: } else {
0692: writer.println(line);
0693: }
0694: }
0695:
0696: writer.println(insertStartMarker);
0697: while (true) {
0698: String line2 = fragmentReader.readLine();
0699: if (line2 == null) {
0700: writer.println();
0701: break;
0702: }
0703: writer.println(line2);
0704: }
0705: writer.println(insertEndMarker);
0706: writer.println();
0707:
0708: for (int i = 0; i < pos; i++) {
0709: writer.print(" ");
0710: }
0711: writer.println(line.substring(pos));
0712:
0713: while (true) {
0714: line = reader.readLine();
0715: if (line == null) {
0716: break;
0717: }
0718: writer.println(line);
0719: }
0720: writer.close();
0721:
0722: reader.close();
0723: fragmentReader.close();
0724:
0725: FileInputStream fis = new FileInputStream(webXml2);
0726: FileOutputStream fos = new FileOutputStream(webXml);
0727:
0728: byte buf[] = new byte[512];
0729: while (true) {
0730: int n = fis.read(buf);
0731: if (n < 0) {
0732: break;
0733: }
0734: fos.write(buf, 0, n);
0735: }
0736:
0737: fis.close();
0738: fos.close();
0739:
0740: webXml2.delete();
0741: (new File(webxmlFile)).delete();
0742:
0743: }
0744:
0745: private void processFile(String file) throws JasperException {
0746: try {
0747: // set up a scratch/output dir if none is provided
0748: if (scratchDir == null) {
0749: String temp = System.getProperty("java.io.tmpdir");
0750: if (temp == null) {
0751: temp = "";
0752: }
0753: scratchDir = new File(new File(temp).getAbsolutePath());
0754: }
0755:
0756: String jspUri = file.replace('\\', '/');
0757: JspCompilationContext clctxt = new JspCompilationContext(
0758: jspUri, false, this , context, null, rctxt);
0759:
0760: /* Override the defaults */
0761: if ((targetClassName != null)
0762: && (targetClassName.length() > 0)) {
0763: clctxt.setServletClassName(targetClassName);
0764: targetClassName = null;
0765: }
0766: if (targetPackage != null) {
0767: clctxt.setServletPackageName(targetPackage);
0768: }
0769:
0770: if (loader == null)
0771: initClassLoader(clctxt);
0772:
0773: clctxt.setClassLoader(loader);
0774: clctxt.setClassPath(classPath);
0775:
0776: Compiler clc = clctxt.createCompiler();
0777:
0778: // If compile is set, generate both .java and .class, if
0779: // .jsp file is newer than .class file;
0780: // Otherwise only generate .java, if .jsp file is newer than
0781: // the .java file
0782: if (clc.isOutDated(compile)) {
0783: clc.compile(compile, true);
0784: }
0785:
0786: // Generate mapping
0787: generateWebMapping(file, clctxt);
0788: if (showSuccess) {
0789: log.info("Built File: " + file);
0790: }
0791:
0792: } catch (JasperException je) {
0793: Throwable rootCause = je;
0794: while (rootCause instanceof JasperException
0795: && ((JasperException) rootCause).getRootCause() != null) {
0796: rootCause = ((JasperException) rootCause)
0797: .getRootCause();
0798: }
0799: if (rootCause != je) {
0800: log
0801: .error(Localizer.getMessage(
0802: "jspc.error.generalException", file),
0803: rootCause);
0804: }
0805: throw je;
0806:
0807: } catch (Exception e) {
0808: if ((e instanceof FileNotFoundException)
0809: && log.isWarnEnabled()) {
0810: log.warn(Localizer.getMessage(
0811: "jspc.error.fileDoesNotExist", e.getMessage()));
0812: }
0813: throw new JasperException(e);
0814: }
0815: }
0816:
0817: /**
0818: * Locate all jsp files in the webapp. Used if no explicit
0819: * jsps are specified.
0820: */
0821: public void scanFiles(File base) throws JasperException {
0822: Stack dirs = new Stack();
0823: dirs.push(base);
0824: if (extensions == null) {
0825: extensions = new Vector();
0826: extensions.addElement("jsp");
0827: extensions.addElement("jspx");
0828: }
0829: while (!dirs.isEmpty()) {
0830: String s = dirs.pop().toString();
0831: File f = new File(s);
0832: if (f.exists() && f.isDirectory()) {
0833: String[] files = f.list();
0834: String ext;
0835: for (int i = 0; (files != null) && i < files.length; i++) {
0836: File f2 = new File(s, files[i]);
0837: if (f2.isDirectory()) {
0838: dirs.push(f2.getPath());
0839: } else {
0840: String path = f2.getPath();
0841: String uri = path.substring(uriRoot.length());
0842: ext = files[i].substring(files[i]
0843: .lastIndexOf('.') + 1);
0844: if (extensions.contains(ext)
0845: || jspConfig.isJspPage(uri)) {
0846: pages.addElement(path);
0847: }
0848: }
0849: }
0850: }
0851: }
0852: }
0853:
0854: public void execute() throws JasperException {
0855:
0856: try {
0857: if (uriRoot == null) {
0858: if (pages.size() == 0) {
0859: throw new JasperException(Localizer
0860: .getMessage("jsp.error.jspc.missingTarget"));
0861: }
0862: String firstJsp = (String) pages.elementAt(0);
0863: File firstJspF = new File(firstJsp);
0864: if (!firstJspF.exists()) {
0865: throw new JasperException(Localizer.getMessage(
0866: "jspc.error.fileDoesNotExist", firstJsp));
0867: }
0868: locateUriRoot(firstJspF);
0869: }
0870:
0871: if (uriRoot == null) {
0872: throw new JasperException(Localizer
0873: .getMessage("jsp.error.jspc.no_uriroot"));
0874: }
0875:
0876: if (context == null) {
0877: initServletContext();
0878: }
0879:
0880: // No explicit pages, we'll process all .jsp in the webapp
0881: if (pages.size() == 0) {
0882: scanFiles(new File(uriRoot));
0883: }
0884:
0885: File uriRootF = new File(uriRoot);
0886: if (!uriRootF.exists() || !uriRootF.isDirectory()) {
0887: throw new JasperException(Localizer
0888: .getMessage("jsp.error.jspc.uriroot_not_dir"));
0889: }
0890:
0891: initWebXml();
0892:
0893: Enumeration e = pages.elements();
0894: while (e.hasMoreElements()) {
0895: String nextjsp = e.nextElement().toString();
0896: File fjsp = new File(nextjsp);
0897: if (!fjsp.isAbsolute()) {
0898: fjsp = new File(uriRootF, nextjsp);
0899: }
0900: if (!fjsp.exists()) {
0901: if (log.isWarnEnabled()) {
0902: log.warn(Localizer.getMessage(
0903: "jspc.error.fileDoesNotExist", fjsp
0904: .toString()));
0905: }
0906: continue;
0907: }
0908: String s = fjsp.getAbsolutePath();
0909: if (s.startsWith(uriRoot)) {
0910: nextjsp = s.substring(uriRoot.length());
0911: }
0912: if (nextjsp.startsWith("." + File.separatorChar)) {
0913: nextjsp = nextjsp.substring(2);
0914: }
0915: processFile(nextjsp);
0916: }
0917:
0918: completeWebXml();
0919:
0920: if (addWebXmlMappings) {
0921: mergeIntoWebXml();
0922: }
0923:
0924: } catch (IOException ioe) {
0925: throw new JasperException(ioe);
0926:
0927: } catch (JasperException je) {
0928: Throwable rootCause = je;
0929: while (rootCause instanceof JasperException
0930: && ((JasperException) rootCause).getRootCause() != null) {
0931: rootCause = ((JasperException) rootCause)
0932: .getRootCause();
0933: }
0934: if (rootCause != je) {
0935: rootCause.printStackTrace();
0936: }
0937: throw je;
0938: }
0939: }
0940:
0941: // ==================== Private utility methods ====================
0942:
0943: private String nextArg() {
0944: if ((argPos >= args.length)
0945: || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) {
0946: return null;
0947: } else {
0948: return args[argPos++];
0949: }
0950: }
0951:
0952: private String nextFile() {
0953: if (fullstop)
0954: argPos++;
0955: if (argPos >= args.length) {
0956: return null;
0957: } else {
0958: return args[argPos++];
0959: }
0960: }
0961:
0962: private void initWebXml() {
0963: try {
0964: if (webxmlLevel >= INC_WEBXML) {
0965: File fmapings = new File(webxmlFile);
0966: mapout = new FileWriter(fmapings);
0967: servletout = new CharArrayWriter();
0968: mappingout = new CharArrayWriter();
0969: } else {
0970: mapout = null;
0971: servletout = null;
0972: mappingout = null;
0973: }
0974: if (webxmlLevel >= ALL_WEBXML) {
0975: mapout
0976: .write(Localizer
0977: .getMessage("jspc.webxml.header"));
0978: mapout.flush();
0979: } else if ((webxmlLevel >= INC_WEBXML)
0980: && !addWebXmlMappings) {
0981: mapout
0982: .write(Localizer
0983: .getMessage("jspc.webinc.header"));
0984: mapout.flush();
0985: }
0986: } catch (IOException ioe) {
0987: mapout = null;
0988: servletout = null;
0989: mappingout = null;
0990: }
0991: }
0992:
0993: private void completeWebXml() {
0994: if (mapout != null) {
0995: try {
0996: servletout.writeTo(mapout);
0997: mappingout.writeTo(mapout);
0998: if (webxmlLevel >= ALL_WEBXML) {
0999: mapout.write(Localizer
1000: .getMessage("jspc.webxml.footer"));
1001: } else if ((webxmlLevel >= INC_WEBXML)
1002: && !addWebXmlMappings) {
1003: mapout.write(Localizer
1004: .getMessage("jspc.webinc.footer"));
1005: }
1006: mapout.close();
1007: } catch (IOException ioe) {
1008: // noting to do if it fails since we are done with it
1009: }
1010: }
1011: }
1012:
1013: private void initServletContext() {
1014: try {
1015: context = new JspCServletContext(
1016: new PrintWriter(System.out), new URL("file:"
1017: + uriRoot.replace('\\', '/') + '/'));
1018: tldLocationsCache = new TldLocationsCache(context, true);
1019: } catch (MalformedURLException me) {
1020: System.out.println("**" + me);
1021: }
1022: rctxt = new JspRuntimeContext(context, this );
1023: jspConfig = new JspConfig(context);
1024: tagPluginManager = new TagPluginManager(context);
1025: }
1026:
1027: private void initClassLoader(JspCompilationContext clctxt)
1028: throws IOException {
1029:
1030: classPath = getClassPath();
1031:
1032: ClassLoader jspcLoader = getClass().getClassLoader();
1033: if (jspcLoader instanceof AntClassLoader) {
1034: classPath += File.pathSeparator
1035: + ((AntClassLoader) jspcLoader).getClasspath();
1036: }
1037:
1038: // Turn the classPath into URLs
1039: ArrayList urls = new ArrayList();
1040: StringTokenizer tokenizer = new StringTokenizer(classPath,
1041: File.pathSeparator);
1042: while (tokenizer.hasMoreTokens()) {
1043: String path = tokenizer.nextToken();
1044: try {
1045: File libFile = new File(path);
1046: urls.add(libFile.toURL());
1047: } catch (IOException ioe) {
1048: // Failing a toCanonicalPath on a file that
1049: // exists() should be a JVM regression test,
1050: // therefore we have permission to freak uot
1051: throw new RuntimeException(ioe.toString());
1052: }
1053: }
1054:
1055: File webappBase = new File(uriRoot);
1056: if (webappBase.exists()) {
1057: File classes = new File(webappBase, "/WEB-INF/classes");
1058: try {
1059: if (classes.exists()) {
1060: classPath = classPath + File.pathSeparator
1061: + classes.getCanonicalPath();
1062: urls.add(classes.getCanonicalFile().toURL());
1063: }
1064: } catch (IOException ioe) {
1065: // failing a toCanonicalPath on a file that
1066: // exists() should be a JVM regression test,
1067: // therefore we have permission to freak out
1068: throw new RuntimeException(ioe.toString());
1069: }
1070: File lib = new File(webappBase, "/WEB-INF/lib");
1071: if (lib.exists() && lib.isDirectory()) {
1072: String[] libs = lib.list();
1073: for (int i = 0; i < libs.length; i++) {
1074: if (libs[i].length() < 5)
1075: continue;
1076: String ext = libs[i]
1077: .substring(libs[i].length() - 4);
1078: if (!".jar".equalsIgnoreCase(ext)) {
1079: if (".tld".equalsIgnoreCase(ext)) {
1080: log
1081: .warn("TLD files should not be placed in "
1082: + "/WEB-INF/lib");
1083: }
1084: continue;
1085: }
1086: try {
1087: File libFile = new File(lib, libs[i]);
1088: classPath = classPath + File.pathSeparator
1089: + libFile.getCanonicalPath();
1090: urls.add(libFile.getCanonicalFile().toURL());
1091: } catch (IOException ioe) {
1092: // failing a toCanonicalPath on a file that
1093: // exists() should be a JVM regression test,
1094: // therefore we have permission to freak out
1095: throw new RuntimeException(ioe.toString());
1096: }
1097: }
1098: }
1099: }
1100:
1101: // What is this ??
1102: urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile()
1103: .toURL());
1104:
1105: URL urlsA[] = new URL[urls.size()];
1106: urls.toArray(urlsA);
1107: loader = new URLClassLoader(urlsA, this .getClass()
1108: .getClassLoader());
1109: Thread.currentThread().setContextClassLoader(loader);
1110: }
1111:
1112: /**
1113: * Find the WEB-INF dir by looking up in the directory tree.
1114: * This is used if no explicit docbase is set, but only files.
1115: * XXX Maybe we should require the docbase.
1116: */
1117: private void locateUriRoot(File f) {
1118: String tUriBase = uriBase;
1119: if (tUriBase == null) {
1120: tUriBase = "/";
1121: }
1122: try {
1123: if (f.exists()) {
1124: f = new File(f.getCanonicalPath());
1125: while (f != null) {
1126: File g = new File(f, "WEB-INF");
1127: if (g.exists() && g.isDirectory()) {
1128: uriRoot = f.getCanonicalPath();
1129: uriBase = tUriBase;
1130: if (log.isInfoEnabled()) {
1131: log.info(Localizer.getMessage(
1132: "jspc.implicit.uriRoot", uriRoot));
1133: }
1134: break;
1135: }
1136: if (f.exists() && f.isDirectory()) {
1137: tUriBase = "/" + f.getName() + "/" + tUriBase;
1138: }
1139:
1140: String fParent = f.getParent();
1141: if (fParent == null) {
1142: break;
1143: } else {
1144: f = new File(fParent);
1145: }
1146:
1147: // If there is no acceptible candidate, uriRoot will
1148: // remain null to indicate to the CompilerContext to
1149: // use the current working/user dir.
1150: }
1151:
1152: if (uriRoot != null) {
1153: File froot = new File(uriRoot);
1154: uriRoot = froot.getCanonicalPath();
1155: }
1156: }
1157: } catch (IOException ioe) {
1158: // since this is an optional default and a null value
1159: // for uriRoot has a non-error meaning, we can just
1160: // pass straight through
1161: }
1162: }
1163:
1164: }
|