/*
* 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.tomcat.util.xreflection;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Set;
final class ReflectionLessCodeGenerator {
private static final String INDENT = " ";
static StringBuilder getIndent(int multiplier) {
StringBuilder indent = new StringBuilder();
while ((multiplier--) > 0) {
indent.append(INDENT);
}
return indent;
}
static void generateCode(File directory, String className, String packageName, Set<SetPropertyClass> baseClasses)
throws IOException {
//@formatter:off
// begin - class
StringBuilder code = new StringBuilder(AL20_HEADER)
.append("package ")
.append(packageName)
.append(';')
.append(System.lineSeparator())
.append(System.lineSeparator())
.append("final class ")
.append(className)
.append(" {")
.append(System.lineSeparator())
.append(System.lineSeparator());
// begin - isEnabled method
code.append(getIndent(1))
.append("static boolean isEnabled() {")
.append(System.lineSeparator())
.append(getIndent(2))
.append("return true;")
.append(System.lineSeparator())
.append(getIndent(1))
.append('}')
.append(System.lineSeparator())
.append(System.lineSeparator())
;
// end - isEnabled method
// begin - getInetAddress method
code.append(getIndent(1))
.append("private static java.net.InetAddress getInetAddress(String value) {")
.append(System.lineSeparator())
.append(getIndent(2))
.append("try {")
.append(System.lineSeparator())
.append(getIndent(3))
.append("return java.net.InetAddress.getByName(value);")
.append(System.lineSeparator())
.append(getIndent(2))
.append("} catch (java.net.UnknownHostException x) { throw new RuntimeException(x); }")
.append(System.lineSeparator())
.append(getIndent(1))
.append('}')
.append(System.lineSeparator())
.append(System.lineSeparator())
;
// end - getInetAddress method
// begin - getPropertyInternal method
code.append(getIndent(1))
.append("static Object getPropertyInternal(Object ")
.append(SetPropertyClass.OBJECT_VAR_NAME)
.append(", String ")
.append(SetPropertyClass.NAME_VAR_NAME)
.append(") {")
.append(System.lineSeparator())
.append(getIndent(2))
.append("Class<?> checkThisClass = o.getClass();")
.append(System.lineSeparator())
.append(getIndent(2))
.append("Object result = null;")
.append(System.lineSeparator())
.append(getIndent(2))
.append("while (checkThisClass != Object.class && result == null) {")
.append(System.lineSeparator())
.append(getIndent(3))
.append("switch (checkThisClass.getName()) {")
.append(System.lineSeparator());
// generate case statements for getPropertyInternal
generateCaseStatementsForGetPropertyInternal(baseClasses, code);
code
.append(getIndent(3))
.append('}')
.append(System.lineSeparator())
.append(getIndent(3))
.append("checkThisClass = checkThisClass.getSuperclass();")
.append(System.lineSeparator())
.append(getIndent(2))
.append('}')
.append(System.lineSeparator())
.append(getIndent(2))
.append("return result;")
.append(System.lineSeparator())
.append(getIndent(1))
.append('}')
.append(System.lineSeparator());
// end - getPropertyInternal method
// begin - getPropertyForXXX methods
generateGetPropertyForMethods(baseClasses, code);
// end - getPropertyForXXX methods
// begin - setPropertyInternal method
code.append(getIndent(1))
.append("static boolean setPropertyInternal(Object ")
.append(SetPropertyClass.OBJECT_VAR_NAME)
.append(", String ")
.append(SetPropertyClass.NAME_VAR_NAME)
.append(", String ")
.append(SetPropertyClass.VALUE_VAR_NAME)
.append(", boolean ")
.append(SetPropertyClass.SETP_VAR_NAME)
.append(") {")
.append(System.lineSeparator())
.append(getIndent(2))
.append("Class<?> checkThisClass = o.getClass();")
.append(System.lineSeparator())
.append(getIndent(2))
.append("while (checkThisClass != Object.class) {")
.append(System.lineSeparator())
.append(getIndent(3))
.append("switch (checkThisClass.getName()) {")
.append(System.lineSeparator());
// generate case statements for setPropertyInternal
generateCaseStatementsForSetPropertyInternal(baseClasses, code);
code
.append(getIndent(3))
.append('}')
.append(System.lineSeparator())
.append(getIndent(3))
.append("checkThisClass = checkThisClass.getSuperclass();")
.append(System.lineSeparator())
.append(getIndent(2))
.append('}')
.append(System.lineSeparator())
.append(getIndent(2))
.append("return false;")
.append(System.lineSeparator())
.append(getIndent(1))
.append('}')
.append(System.lineSeparator());
// end - setPropertyInternal method
// begin - setPropertyForXXX methods
generateSetPropertyForMethods(baseClasses, code);
// end - setPropertyForXXX methods
code.append('}')
.append(System.lineSeparator());
// end - class
//@formatter:on
File destination = new File(directory, className + ".java");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(destination, false))) {
writer.write(code.toString());
writer.flush();
}
}
private static void generateCaseStatementForSetPropertyInternal(SetPropertyClass clazz, StringBuilder code) {
for (SetPropertyClass child : clazz.getChildren()) {
generateCaseStatementForSetPropertyInternal(child, code);
}
if (!clazz.isAbstract()) {
code.append(clazz.generateInvocationSetForPropertyCaseStatement(4));
}
}
private static void generateCaseStatementsForSetPropertyInternal(Set<SetPropertyClass> baseClasses,
StringBuilder code) {
for (SetPropertyClass clazz : baseClasses) {
generateCaseStatementForSetPropertyInternal(clazz, code);
}
}
private static void generateSetPropertyForMethod(SetPropertyClass clazz, StringBuilder code) {
for (SetPropertyClass child : clazz.getChildren()) {
generateSetPropertyForMethod(child, code);
}
code.append(clazz.generateSetPropertyForMethod()).append(System.lineSeparator()).append(System.lineSeparator());
}
private static void generateSetPropertyForMethods(Set<SetPropertyClass> baseClasses, StringBuilder code) {
for (SetPropertyClass clazz : baseClasses) {
generateSetPropertyForMethod(clazz, code);
}
}
private static void generateCaseStatementForGetPropertyInternal(SetPropertyClass clazz, StringBuilder code) {
for (SetPropertyClass child : clazz.getChildren()) {
generateCaseStatementForGetPropertyInternal(child, code);
}
if (!clazz.isAbstract()) {
code.append(clazz.generateInvocationGetForPropertyCaseStatement(4));
}
}
private static void generateCaseStatementsForGetPropertyInternal(Set<SetPropertyClass> baseClasses,
StringBuilder code) {
for (SetPropertyClass clazz : baseClasses) {
generateCaseStatementForGetPropertyInternal(clazz, code);
}
}
private static void generateGetPropertyForMethod(SetPropertyClass clazz, StringBuilder code) {
for (SetPropertyClass child : clazz.getChildren()) {
generateGetPropertyForMethod(child, code);
}
code.append(clazz.generateGetPropertyForMethod()).append(System.lineSeparator()).append(System.lineSeparator());
}
private static void generateGetPropertyForMethods(Set<SetPropertyClass> baseClasses, StringBuilder code) {
for (SetPropertyClass clazz : baseClasses) {
generateGetPropertyForMethod(clazz, code);
}
}
private static final String AL20_HEADER = """
/*
* 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.
*/
""";
}