alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *  Copyright 1999-2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.apache.jasper.compiler;

import java.io.File;

import org.apache.tomcat.util.JavaGeneratorTool;
import org.apache.tomcat.util.io.FileUtil;


/** Mangler implementation - use the directory of the jsp file as a package
    name, minimize "special" encoding - in general, simpler and predictible
    names for the common case.

    This file is also using a special mechanism for the "versioned" classes
    ( based on Anil's idea of generating new class each time the jsp file
    changes - without a context restart that looses data ).

    We use an additional file per jsp saving the current version - at
    startup the file will be read to avoid recompilation. That removes the
    need for a "special" class loader and the hacks in reading internal
    class info.
*/
public class JasperMangler implements Mangler{

    public JasperMangler(String workDir, String docBase, String jspFile)
    {
	this.jspFile=jspFile;
	this.workDir=workDir;
	this.docBase=docBase;
	init();
    }

    /** Versioned class name ( without package ).
     */
    public String getClassName() {
	return JavaGeneratorTool.getVersionedName( baseClassN, version );
    }
    
    /**
     *   Full path to the generated java file ( including version )
     */
    public String getJavaFileName() {
	return javaFileName;
    }

    /** The package name ( "." separated ) of the generated
     *  java file
     */
    public String getPackageName() {
	if( pkgDir!=null ) {
	    return pkgDir.replace('/', '.');
	} else {
	    return null;
	}
    }

    /** Full path to the compiled class file ( including version )
     */
    public String getClassFileName() {
	return classFileName;
    }

    // -------------------- JspInterceptor fields --------------------
    
    /** Returns the jsp file, as declared by  in server.xml
     *  or the context-relative path that was extension mapped to jsp
     */
    public String getJspFile() {
	return jspFile;
    }

    /** Returns the directory where the class is located, using
     *  the normal class loader rules.
     */
    public String getClassDir() {
	return classDir;
    }
    
    /** The class name ( package + class + versioning ) of the
     *  compilation result
     */
    public String getServletClassName() {
	if( pkgDir!=null ) {
	    return getPackageName()  + "." + getClassName();
	} else {
	    return getClassName();
	}
    }

    public int getVersion() {
	return version;
    }

    // In Jasper = not used - it's specific to the class scheme
    // used by JspServlet
    // Full path to the class file - without version.
    

    public String getBaseClassName() {
	return baseClassN;
    }

    public String getPackageDir() {
	return pkgDir;
    }
    
    public String getJspFilePath() {
        // lazy evaluation of full path
        if( jspFilePath == null )
            jspFilePath=FileUtil.safePath( docBase, jspFile, false);
        return jspFilePath;
    }

    private String fixInvalidChars(String className) {
	// Fix for invalid characters. From CommandLineCompiler
	StringBuffer modifiedClassName = new StringBuffer();
	char c='/';
	if( className.length() > 0 && Character.isDigit( className.charAt( 0 )  )) {
	    className="_" +className;
	}
	for (int i = 0; i < className.length(); i++) {
	    char prev=c;
	    c=className.charAt(i);
	    // workaround for common "//" problem. Alternative
	    // would be to encode the dot.
	    if( prev=='/' && c=='/' ) {
		continue;
	    }
	    
	    if (Character.isLetterOrDigit(c) == true ||
		c=='_' ||
		c=='/' )
		modifiedClassName.append(className.substring(i,i+1));
	    else
		modifiedClassName.append(mangleChar(className.charAt(i)));
	}
	return modifiedClassName.toString();
    }

    private static final String mangleChar(char ch) {
        if(ch == File.separatorChar) {
	    ch = '/';
	}
	String s = Integer.toHexString(ch);
	int nzeros = 5 - s.length();
	char[] result = new char[6];
	result[0] = '_';
	for (int i = 1; i <= nzeros; i++)
	    result[i] = '0';
	for (int i = nzeros+1, j = 0; i < 6; i++, j++)
	    result[i] = s.charAt(j);
	return new String(result);
    }


    
    /** compute basic names - pkgDir and baseClassN
     */
    private void init() {
	int lastComp=jspFile.lastIndexOf(  "/" );

	if( lastComp > 0 ) {
	    // has package 
	    // ignore the first "/" of jspFile
	    pkgDir=jspFile.substring( 1, lastComp );
	}
	
	// remove "special" words, replace "."
	if( pkgDir!=null ) {
	    pkgDir=JavaGeneratorTool.manglePackage(pkgDir);
	    pkgDir=pkgDir.replace('.', '_');
	    pkgDir=fixInvalidChars( pkgDir );
	    if ( "/".equals(File.separator) )
		classDir=workDir + File.separator + pkgDir;
            else
		classDir=workDir + File.separator +
                	pkgDir.replace('/',File.separatorChar);
	} else {
	    classDir=workDir;
	}
	
	int extIdx=jspFile.lastIndexOf( "." );

	if( extIdx<0 ) {
	    // no "." 
	    if( lastComp >= 0 )
		baseClassN=jspFile.substring( lastComp+1 );
	    else
		baseClassN=jspFile.substring( 0 );
	} else {
	    if( lastComp >= 0 )
		baseClassN=jspFile.substring( lastComp+1, extIdx );
	    else
		baseClassN=jspFile.substring( 0, extIdx );
	}

	if( JavaGeneratorTool.isKeyword( baseClassN ) )
	    baseClassN="_" + baseClassN;
	
	baseClassN=fixInvalidChars( baseClassN );
	
	//	System.out.println("XXXMangler: " + jspFile + " " +
	// pkgDir + " " + baseClassN);

	// extract version from the .class dir, using the base name
	version=JavaGeneratorTool.readVersion(classDir,
					      baseClassN);
	if( version==-1 ) {
	    version=0;
	} 
	updateVersionPaths();
    }

    private void updateVersionPaths() {
	// version dependent stuff
	String baseName=classDir + File.separator + JavaGeneratorTool.
	    getVersionedName( baseClassN, version);
	
	javaFileName= baseName + ".java";

	classFileName=baseName +  ".class";
    }
    
    /** Move to a new class name, if a changes has been detected.
     */
    public void nextVersion() {
	version++;
	JavaGeneratorTool.writeVersion( getClassDir(), baseClassN, version);
	updateVersionPaths();
    }

    // context-relative jsp path 
    // extracted from the  or the result of a *.jsp mapping
    private String jspFile; 
    private String jspFilePath=null;
    // version of the compiled java file
    private int version;
    private String workDir;
    private String docBase;
    // the "/" separted version
    private String pkgDir;
    // class name without package and version
    private String baseClassN;
    private String classDir;
    private String javaFileName;
    private String classFileName;
}

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.