| /* |
| * 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.netbeans.modules.micronaut; |
| |
| import com.sun.source.tree.AnnotationTree; |
| import com.sun.source.tree.AssignmentTree; |
| import com.sun.source.tree.ExpressionTree; |
| import com.sun.source.tree.IdentifierTree; |
| import com.sun.source.tree.LiteralTree; |
| import com.sun.source.tree.Tree; |
| import com.sun.source.util.TreePath; |
| import com.sun.source.util.TreePathScanner; |
| import com.sun.source.util.Trees; |
| import java.io.ByteArrayInputStream; |
| import java.io.InputStream; |
| import java.nio.charset.StandardCharsets; |
| import java.util.EnumSet; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.atomic.AtomicReference; |
| import java.util.stream.Collectors; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ElementKind; |
| import javax.lang.model.element.TypeElement; |
| import org.json.JSONArray; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| import org.netbeans.api.java.classpath.ClassPath; |
| import org.netbeans.api.java.project.JavaProjectConstants; |
| import org.netbeans.api.java.source.ClassIndex; |
| import org.netbeans.api.java.source.ClasspathInfo; |
| import org.netbeans.api.java.source.CompilationController; |
| import org.netbeans.api.java.source.ElementHandle; |
| import org.netbeans.api.java.source.JavaSource; |
| import org.netbeans.api.java.source.TypeUtilities; |
| import org.netbeans.api.project.Project; |
| import org.netbeans.api.project.ProjectUtils; |
| import org.netbeans.api.project.SourceGroup; |
| import org.netbeans.modules.parsing.api.ParserManager; |
| import org.netbeans.modules.parsing.api.ResultIterator; |
| import org.netbeans.modules.parsing.api.Source; |
| import org.netbeans.modules.parsing.api.UserTask; |
| import org.netbeans.modules.parsing.spi.ParseException; |
| import org.openide.filesystems.FileObject; |
| import org.openide.util.Exceptions; |
| import org.springframework.boot.configurationmetadata.ConfigurationMetadataGroup; |
| import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; |
| import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; |
| import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder; |
| |
| /** |
| * |
| * @author Dusan Balek |
| */ |
| public final class MicronautConfigProperties { |
| |
| private static final String CONFIG_METADATA_JSON = "META-INF/spring-configuration-metadata.json"; |
| private static final ElementHandle<TypeElement> PROPERTY_HANDLE = ElementHandle.createTypeElementHandle(ElementKind.ANNOTATION_TYPE, "io.micronaut.context.annotation.Property"); |
| |
| private MicronautConfigProperties() { |
| } |
| |
| public static boolean hasConfigMetadata(Project project) { |
| ClassPath cp = getExecuteClasspath(project); |
| return cp != null && !cp.findAllResources(CONFIG_METADATA_JSON).isEmpty(); |
| } |
| |
| public static Map<String, ConfigurationMetadataProperty> getProperties(Project project) { |
| Map<String, ConfigurationMetadataProperty> props = new LinkedHashMap<>(); |
| ClassPath cp = getExecuteClasspath(project); |
| if (cp != null) { |
| for (FileObject fo : cp.findAllResources(CONFIG_METADATA_JSON)) { |
| try { |
| ConfigurationMetadataRepository repository = ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(fo.getInputStream()).build(); |
| props.putAll(repository.getAllProperties()); |
| } catch (Exception ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| String customRepository = getCustomRepository(project); |
| if (customRepository != null) { |
| try { |
| InputStream stream = new ByteArrayInputStream(customRepository.getBytes(StandardCharsets.UTF_8)); |
| ConfigurationMetadataRepository repository = ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(stream).build(); |
| props.putAll(repository.getAllProperties()); |
| } catch (Exception ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| } |
| return props; |
| } |
| |
| public static Map<String, ConfigurationMetadataGroup> getGroups(Project project) { |
| Map<String, ConfigurationMetadataGroup> groups = new LinkedHashMap<>(); |
| ClassPath cp = getExecuteClasspath(project); |
| if (cp != null) { |
| for (FileObject fo : cp.findAllResources(CONFIG_METADATA_JSON)) { |
| try { |
| ConfigurationMetadataRepository repository = ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(fo.getInputStream()).build(); |
| groups.putAll(repository.getAllGroups()); |
| } catch (Exception ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| String customRepository = getCustomRepository(project); |
| if (customRepository != null) { |
| try { |
| InputStream stream = new ByteArrayInputStream(customRepository.getBytes(StandardCharsets.UTF_8)); |
| ConfigurationMetadataRepository repository = ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(stream).build(); |
| groups.putAll(repository.getAllGroups()); |
| } catch (Exception ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| } |
| return groups; |
| } |
| |
| private static String getCustomRepository(Project project) { |
| AtomicReference<String> ret = new AtomicReference<>(); |
| SourceGroup[] srcGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); |
| for (int i = 0; i < srcGroups.length; i++) { |
| SourceGroup srcGroup = srcGroups[i]; |
| ClassIndex ci = ClasspathInfo.create(srcGroup.getRootFolder()).getClassIndex(); |
| Set<FileObject> resources = ci.getResources(PROPERTY_HANDLE, |
| EnumSet.of(ClassIndex.SearchKind.TYPE_REFERENCES), EnumSet.of(ClassIndex.SearchScope.SOURCE)); |
| try { |
| ParserManager.parse(resources.stream().map(resource -> Source.create(resource)).collect(Collectors.toList()), new UserTask() { |
| @Override |
| public void run(ResultIterator resultIterator) throws Exception { |
| CompilationController cc = CompilationController.get(resultIterator.getParserResult()); |
| cc.toPhase(JavaSource.Phase.RESOLVED); |
| Trees trees = cc.getTrees(); |
| TypeElement te = PROPERTY_HANDLE.resolve(cc); |
| new TreePathScanner<Void, Void>() { |
| @Override |
| public Void visitAnnotation(AnnotationTree node, Void p) { |
| if (te == trees.getElement(new TreePath(getCurrentPath(), node.getAnnotationType()))) { |
| for (ExpressionTree argument : node.getArguments()) { |
| if (argument.getKind() == Tree.Kind.ASSIGNMENT) { |
| ExpressionTree variable = ((AssignmentTree) argument).getVariable(); |
| ExpressionTree expression = ((AssignmentTree) argument).getExpression(); |
| if (expression.getKind() == Tree.Kind.STRING_LITERAL && variable.getKind() == Tree.Kind.IDENTIFIER && "name".contentEquals(((IdentifierTree) variable).getName())) { |
| try { |
| String value = (String) ((LiteralTree) expression).getValue(); |
| JSONObject group = new JSONObject(); |
| JSONObject property = new JSONObject(); |
| group.put("name", value); |
| property.put("name", value); |
| final TreePath grandParentPath = getCurrentPath().getParentPath().getParentPath(); |
| if (grandParentPath.getLeaf().getKind() == Tree.Kind.VARIABLE) { |
| Element el = trees.getElement(grandParentPath); |
| if (el != null && el.getKind().isField()) { |
| String typeName = cc.getTypeUtilities().getTypeName(el.asType(), TypeUtilities.TypeNameOptions.PRINT_FQN).toString(); |
| String sourceTypeName = cc.getElementUtilities().getElementName(el.getEnclosingElement(), true).toString(); |
| property.put("type", typeName); |
| property.put("sourceType", sourceTypeName); |
| group.put("type", sourceTypeName); |
| } |
| } |
| JSONArray groups = new JSONArray(); |
| groups.put(group); |
| JSONArray properties = new JSONArray(); |
| properties.put(property); |
| JSONObject data = new JSONObject(); |
| data.put("groups", groups); |
| data.put("properties", properties); |
| ret.set(data.toString()); |
| } catch (JSONException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| } |
| } |
| } |
| return super.visitAnnotation(node, p); |
| } |
| }.scan(new TreePath(cc.getCompilationUnit()), null); |
| } |
| }); |
| } catch (ParseException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| return ret.get(); |
| } |
| |
| private static ClassPath getExecuteClasspath(Project project) { |
| SourceGroup[] srcGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); |
| if (srcGroups.length > 0) { |
| return ClassPath.getClassPath(srcGroups[0].getRootFolder(), ClassPath.EXECUTE); |
| } |
| return null; |
| } |
| } |