org.apache.sling.scripting.sightly.impl.engine.compiled.SourceIdentifier.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.scripting.sightly.impl.engine.compiled.SourceIdentifier.java

Source

/*******************************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.sling.scripting.sightly.impl.engine.compiled;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.scripting.sightly.impl.engine.SightlyEngineConfiguration;
import org.apache.sling.scripting.sightly.java.compiler.ClassInfo;

/**
 * Identifies a Java source file based on a {@link Resource}. Depending on the used constructor this class might provide the abstraction
 * for either a Java source file generated for a HTL script or for a HTL {@link Resource}-based Java Use-API Object.
 */
public class SourceIdentifier implements ClassInfo {

    private static final Set<String> javaKeywords = new HashSet<String>() {
        {
            add("abstract");
            add("assert");
            add("boolean");
            add("break");
            add("byte");
            add("case");
            add("catch");
            add("char");
            add("class");
            add("const");
            add("continue");
            add("default");
            add("do");
            add("double");
            add("else");
            add("enum");
            add("extends");
            add("final");
            add("finally");
            add("float");
            add("for");
            add("goto");
            add("if");
            add("implements");
            add("import");
            add("instanceof");
            add("int");
            add("interface");
            add("long");
            add("native");
            add("new");
            add("package");
            add("private");
            add("protected");
            add("public");
            add("return");
            add("short");
            add("static");
            add("strictfp");
            add("super");
            add("switch");
            add("synchronized");
            add("this");
            add("throws");
            add("transient");
            add("try");
            add("void");
            add("volatile");
            add("while");
        }
    };

    public static final Pattern MANGLED_CHAR_PATTER = Pattern.compile("(.*)(__[0-9a-f]{4}__)(.*)");

    private SightlyEngineConfiguration engineConfiguration;
    private String scriptName;
    private String simpleClassName;
    private String packageName;
    private String fullyQualifiedClassName;

    public SourceIdentifier(SightlyEngineConfiguration engineConfiguration, String scriptName) {
        this.engineConfiguration = engineConfiguration;
        this.scriptName = scriptName;
    }

    @Override
    public String getSimpleClassName() {
        if (simpleClassName == null) {
            int lastSlashIndex = scriptName.lastIndexOf("/");
            String processingScriptName = scriptName;
            if (scriptName.endsWith(".java")) {
                processingScriptName = scriptName.substring(0, scriptName.length() - 5);
            }
            if (lastSlashIndex != -1) {
                simpleClassName = makeJavaPackage(processingScriptName.substring(lastSlashIndex));
            } else {
                simpleClassName = makeJavaPackage(processingScriptName);
            }
        }
        return simpleClassName;
    }

    @Override
    public String getPackageName() {
        if (packageName == null) {
            int lastSlashIndex = scriptName.lastIndexOf("/");
            String processingScriptName = scriptName;
            boolean javaFile = scriptName.endsWith(".java");
            if (javaFile) {
                processingScriptName = scriptName.substring(0, scriptName.length() - 5);
            }
            if (lastSlashIndex != -1) {
                packageName = makeJavaPackage(processingScriptName.substring(0, lastSlashIndex));
            } else {
                packageName = makeJavaPackage(processingScriptName);
            }
            if (!javaFile) {
                packageName = engineConfiguration.getBundleSymbolicName() + "." + packageName;
            }
        }
        return packageName;
    }

    @Override
    public String getFullyQualifiedClassName() {
        if (fullyQualifiedClassName == null) {
            fullyQualifiedClassName = getPackageName() + "." + getSimpleClassName();
        }
        return fullyQualifiedClassName;
    }

    /**
     * Converts the given identifier to a legal Java identifier
     *
     * @param identifier the identifier to convert
     * @return legal Java identifier corresponding to the given identifier
     */
    public static String makeJavaIdentifier(String identifier) {
        StringBuilder modifiedIdentifier = new StringBuilder(identifier.length());
        if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
            modifiedIdentifier.append('_');
        }
        for (int i = 0; i < identifier.length(); i++) {
            char ch = identifier.charAt(i);
            if (Character.isJavaIdentifierPart(ch) && ch != '_') {
                modifiedIdentifier.append(ch);
            } else if (ch == '.') {
                modifiedIdentifier.append('_');
            } else {
                modifiedIdentifier.append(mangleChar(ch));
            }
        }
        if (isJavaKeyword(modifiedIdentifier.toString())) {
            modifiedIdentifier.append('_');
        }
        return modifiedIdentifier.toString();
    }

    /**
     * Converts the given scriptName to a Java package or fully-qualified class name
     *
     * @param scriptName the scriptName to convert
     * @return Java package corresponding to the given scriptName
     */
    public static String makeJavaPackage(String scriptName) {
        String classNameComponents[] = StringUtils.split(scriptName, '/');
        StringBuilder legalClassNames = new StringBuilder();
        for (int i = 0; i < classNameComponents.length; i++) {
            legalClassNames.append(makeJavaIdentifier(classNameComponents[i]));
            if (i < classNameComponents.length - 1) {
                legalClassNames.append('.');
            }
        }
        return legalClassNames.toString();
    }

    public static String getScriptName(String slashSubpackage, String fullyQualifiedClassName) {
        String className = fullyQualifiedClassName;
        StringBuilder pathElements = new StringBuilder("/");
        if (StringUtils.isNotEmpty(slashSubpackage) && className.contains(slashSubpackage)) {
            className = className.replaceAll(slashSubpackage + "\\.", "");
        }
        String[] classElements = StringUtils.split(className, '.');
        for (int i = 0; i < classElements.length; i++) {
            String classElem = classElements[i];
            Matcher matcher = MANGLED_CHAR_PATTER.matcher(classElem);
            if (matcher.matches()) {
                String group = matcher.group(2);
                char unmangled = unmangle(group);
                classElem = classElem.replaceAll(group, Character.toString(unmangled));
                while (matcher.find()) {
                    group = matcher.group(2);
                    unmangled = unmangle(group);
                    classElem = classElem.replaceAll(group, Character.toString(unmangled));
                }
            } else {
                int underscoreIndex = classElem.indexOf('_');
                if (underscoreIndex > -1) {
                    if (underscoreIndex == classElem.length() - 1) {
                        classElem = classElem.substring(0, classElem.length() - 1);
                    } else {
                        classElem = classElem.replaceAll("_", ".");
                    }
                }
            }
            pathElements.append(classElem);
            if (i < classElements.length - 1) {
                pathElements.append("/");
            }
        }
        return pathElements.toString();
    }

    /**
     * Mangle the specified character to create a legal Java class name.
     *
     * @param ch the character to mangle
     * @return the mangled
     */
    public static String mangleChar(char ch) {
        return String.format("__%04x__", (int) ch);
    }

    /**
     * Provided a mangled string (obtained by calling {@link #mangleChar(char)}) it will will return the character that was mangled.
     *
     * @param mangled the mangled string
     * @return the original character
     */
    public static char unmangle(String mangled) {
        String toProcess = mangled.replaceAll("__", "");
        return (char) Integer.parseInt(toProcess, 16);
    }

    /**
     * Test whether the argument is a Java keyword.
     *
     * @param key the String to test
     * @return {@code true} if the String is a Java keyword, {@code false} otherwise
     */
    public static boolean isJavaKeyword(String key) {
        return javaKeywords.contains(key);
    }
}