/*
* Copyright (C) 2015 Sebastian Daschner, sebastian-daschner.com
*
* 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/LICENSE2.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 com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode;
import com.sebastian_daschner.jaxrs_analyzer.analysis.JobRegistry;
import com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodPool;
import com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation.MethodSimulator;
import com.sebastian_daschner.jaxrs_analyzer.model.JavaUtils;
import com.sebastian_daschner.jaxrs_analyzer.model.elements.Element;
import com.sebastian_daschner.jaxrs_analyzer.model.instructions.Instruction;
import com.sebastian_daschner.jaxrs_analyzer.model.methods.ProjectMethod;
import com.sebastian_daschner.jaxrs_analyzer.model.results.ClassResult;
import com.sebastian_daschner.jaxrs_analyzer.model.results.MethodResult;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static java.util.Collections.singleton;
/**
* Analyzes sub-resource-locator methods. This class is thread-safe.
*
* @author Sebastian Daschner
*/
class SubResourceLocatorMethodContentAnalyzer extends MethodContentAnalyzer {
private final Lock lock = new ReentrantLock();
private final MethodSimulator simulator = new MethodSimulator();
/**
* Analyzes the sub-resource locator method as a class result (which will be the content of a method result).
*
* @param methodResult The method result of the sub-resource locator (containing the instructions, and a sub-resource class result)
*/
void analyze(final MethodResult methodResult) {
lock.lock();
try {
buildPackagePrefix(methodResult.getParentResource().getOriginalClass());
determineReturnTypes(methodResult).stream()
// FEATURE handle several sub-resource impl's
.reduce((l, r) -> JavaUtils.determineMostSpecificType(l, r))
.ifPresent(t -> registerSubResourceJob(t, methodResult.getSubResource()));
} finally {
lock.unlock();
}
}
/**
* Determines the possible return types of the sub-resource-locator by analyzing the bytecode.
* This will analyze the concrete returned types (which then are further analyzed).
*/
private Set<String> determineReturnTypes(final MethodResult result) {
final List<Instruction> visitedInstructions = interpretRelevantInstructions(result.getInstructions());
// find project defined methods in invoke occurrences
final Set<ProjectMethod> projectMethods = findProjectMethods(visitedInstructions);
// add project methods to global method pool
projectMethods.forEach(MethodPool.getInstance()::addProjectMethod);
final Element returnedElement = simulator.simulate(visitedInstructions);
if (returnedElement == null) {
// happens for abstract methods or if there is no return
return singleton(result.getOriginalMethodSignature().getReturnType());
}
return returnedElement.getTypes();
}
private void registerSubResourceJob(final String type, final ClassResult classResult) {
final String className = JavaUtils.toClassName(type);
JobRegistry.getInstance().analyzeResourceClass(className, classResult);
}
}