blob: 8069cb0974352b6221fccb4aaa3008bc4e943f26 [file] [log] [blame]
/*******************************************************************************
* 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.java.compiler;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.sling.scripting.sightly.compiler.backend.BackendCompiler;
import org.apache.sling.scripting.sightly.compiler.commands.CommandStream;
import org.apache.sling.scripting.sightly.compiler.commands.StatefulVisitor;
import org.apache.sling.scripting.sightly.java.compiler.impl.CodeGenVisitor;
import org.apache.sling.scripting.sightly.java.compiler.impl.CommandVisitorHandler;
import org.apache.sling.scripting.sightly.java.compiler.impl.JavaClassTemplate;
import org.apache.sling.scripting.sightly.java.compiler.impl.UnitBuilder;
/**
* {@link BackendCompiler} that generates a Java class.
*/
public final class JavaClassBackendCompiler implements BackendCompiler {
private static final String COMPILED_UNIT_TEMPLATE = "templates/compiled_unit_template.txt";
private static final String SUBTEMPLATE = "templates/subtemplate.txt";
private static final String mainTemplate;
private static final String childTemplate;
private UnitBuilder unitBuilder;
private final JavaImportsAnalyzer JAVA_IMPORTS_ANALYZER;
static {
try {
mainTemplate = IOUtils
.toString(JavaClassTemplate.class.getClassLoader().getResourceAsStream(COMPILED_UNIT_TEMPLATE), "UTF-8");
childTemplate = IOUtils.toString(JavaClassTemplate.class.getClassLoader().getResourceAsStream(SUBTEMPLATE), "UTF-8");
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
public JavaClassBackendCompiler() {
this(new JavaImportsAnalyzer() {});
}
public JavaClassBackendCompiler(JavaImportsAnalyzer javaImportsAnalyzer) {
JAVA_IMPORTS_ANALYZER = javaImportsAnalyzer;
unitBuilder = new UnitBuilder(JAVA_IMPORTS_ANALYZER);
}
@Override
public void handle(CommandStream stream) {
StatefulVisitor statefulVisitor = new StatefulVisitor();
final CodeGenVisitor visitor = new CodeGenVisitor(unitBuilder, statefulVisitor.getControl());
statefulVisitor.initializeWith(visitor);
stream.addHandler(new CommandVisitorHandler(statefulVisitor) {
@Override
public void onDone() {
super.onDone();
visitor.finish();
}
});
}
/**
* Provided the class information, this method will build the source code for the generated Java class.
*
* @param classInfo the class information
* @return the generated Java class' source code
*/
public String build(ClassInfo classInfo) {
CompilationOutput compilationOutput = unitBuilder.build();
JavaClassTemplate mainTemplate = newMainTemplate();
mainTemplate.setPackageName(classInfo.getPackageName());
mainTemplate.setClassName(classInfo.getSimpleClassName());
StringBuilder imports = new StringBuilder();
for (String importClass : unitBuilder.getImports()) {
if (JAVA_IMPORTS_ANALYZER.allowImport(importClass)) {
imports.append("import ").append(importClass).append(";").append(System.lineSeparator());
}
}
mainTemplate.setImports(imports.toString());
processCompilationResult(compilationOutput, mainTemplate);
return mainTemplate.toString();
}
private void processCompilationResult(CompilationOutput result, JavaClassTemplate mainTemplate) {
mainTemplate.writeMainBody(result.getMainBody());
for (Map.Entry<String, CompilationOutput> entry : result.getSubTemplates().entrySet()) {
JavaClassTemplate childTemplate = newChildTemplate();
processCompilationResult(entry.getValue(), childTemplate);
mainTemplate.writeSubTemplate(entry.getKey(), childTemplate.toString());
}
}
private JavaClassTemplate newMainTemplate() {
return new JavaClassTemplate(mainTemplate);
}
private JavaClassTemplate newChildTemplate() {
return new JavaClassTemplate(childTemplate);
}
}