From 9806e95cf20331f0f7a277c5b0f8a02aad6f184b Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Tue, 15 Jan 2019 12:08:04 +0100 Subject: [PATCH] first steps to create symbols for XML-defined beans --- .../boot/java/utils/SpringIndexerXML.java | 60 +++++++++------ .../SpringIndexerXMLNamespaceHandler.java | 24 ++++++ ...SpringIndexerXMLNamespaceHandlerBeans.java | 73 +++++++++++++++++++ .../boot/java/utils/SpringSymbolIndex.java | 7 +- .../test/SpringIndexerXMLProjectTest.java | 6 +- 5 files changed, 143 insertions(+), 27 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandler.java create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java index a1b5d798c..7674dd7cd 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java @@ -10,11 +10,13 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.utils; +import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import javax.xml.stream.XMLEventReader; @@ -27,6 +29,7 @@ import javax.xml.stream.events.XMLEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.util.UriUtil; /** * @author Martin Lippert @@ -36,9 +39,11 @@ public class SpringIndexerXML implements SpringIndexer { private static final Logger log = LoggerFactory.getLogger(SpringIndexerJava.class); private final SymbolHandler handler; + private final Map namespaceHandler; - public SpringIndexerXML(SymbolHandler handler) { + public SpringIndexerXML(SymbolHandler handler, Map namespaceHandler) { this.handler = handler; + this.namespaceHandler = namespaceHandler; } @Override @@ -68,11 +73,11 @@ public class SpringIndexerXML implements SpringIndexer { private void scanProject(IJavaProject project, String[] files) { for (String file : files) { - scanFile(file); + scanFile(project, file); } } - private void scanFile(String file) { + private void scanFile(IJavaProject project, String file) { System.out.println("XML parsing for: " + file); @@ -82,27 +87,36 @@ public class SpringIndexerXML implements SpringIndexer { XMLInputFactory inputFactory = XMLInputFactory.newInstance(); XMLEventReader eventReader = inputFactory.createXMLEventReader(xmlInputStream); - while(eventReader.hasNext()){ - XMLEvent event = eventReader.nextEvent(); - switch (event.getEventType()) { - case XMLEvent.START_ELEMENT: - StartElement startElement = event.asStartElement(); + while (eventReader.hasNext()) { + XMLEvent event = eventReader.nextEvent(); + switch (event.getEventType()) { - System.out.print("<"+startElement.getName().toString()+">"); - break; - case XMLEvent.CHARACTERS: - Characters characters = event.asCharacters(); - System.out.print(characters.getData()); - break; - case XMLEvent.END_ELEMENT: - EndElement endElement = event.asEndElement(); - System.out.println(""); - break; - default: - //do nothing - break; - } - } + case XMLEvent.START_ELEMENT: + StartElement startElement = event.asStartElement(); + + String namespaceURI = startElement.getName().getNamespaceURI(); + if (namespaceURI != null && this.namespaceHandler.containsKey(namespaceURI)) { + SpringIndexerXMLNamespaceHandler namespaceHandler = this.namespaceHandler.get(namespaceURI); + + String docURI = UriUtil.toUri(new File(file)).toString(); + namespaceHandler.processStartElement(project, docURI, startElement, this.handler); + } + + break; + + case XMLEvent.CHARACTERS: + Characters characters = event.asCharacters(); + System.out.print(characters.getData()); + break; + case XMLEvent.END_ELEMENT: + EndElement endElement = event.asEndElement(); + System.out.println(""); + break; + default: + // do nothing + break; + } + } } catch (Exception e) { log.error("error parsing XML file: ", e); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandler.java new file mode 100644 index 000000000..de06859a9 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandler.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2019 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.utils; + +import javax.xml.stream.events.StartElement; + +import org.springframework.ide.vscode.commons.java.IJavaProject; + +/** + * @author Martin Lippert + */ +public interface SpringIndexerXMLNamespaceHandler { + + void processStartElement(IJavaProject project, String docURI, StartElement startElement, SymbolHandler handler); + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java new file mode 100644 index 000000000..2a356b62d --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2019 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.utils; + +import java.util.Iterator; + +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.StartElement; + +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; +import org.springframework.ide.vscode.commons.java.IJavaProject; + +/** + * @author Martin Lippert + */ +public class SpringIndexerXMLNamespaceHandlerBeans implements SpringIndexerXMLNamespaceHandler { + + @Override + public void processStartElement(IJavaProject project, String docURI, StartElement startElement, SymbolHandler handler) { + String localPart = startElement.getName().getLocalPart(); + if (localPart != null && "bean".equals(localPart)) { + createBeanSymbol(project, docURI, startElement, handler); + } + } + + private void createBeanSymbol(IJavaProject project, String docURI, StartElement startElement, SymbolHandler handler) { + String beanID = null; + String beanClass = null; + + Iterator attributes = startElement.getAttributes(); + while (attributes.hasNext()) { + Attribute attribute = (Attribute) attributes.next(); + + String name = attribute.getName().getLocalPart(); + if (name != null && name.equals("id")) { + beanID = attribute.getValue(); + } + else if (name != null && name.equals("class")) { + String value = attribute.getValue(); + beanClass = value.substring(value.lastIndexOf(".") + 1); + } + } + + if (beanID != null && beanClass != null) { + Range range = new Range(); + range.setStart(new Position(startElement.getLocation().getLineNumber(), startElement.getLocation().getColumnNumber())); + range.setEnd(new Position(startElement.getLocation().getLineNumber(), startElement.getLocation().getColumnNumber() + 1)); + + Location location = new Location(); + location.setUri(docURI); + location.setRange(range); + + SymbolInformation symbol = new SymbolInformation("@+ '" + beanID + "' " + beanClass, SymbolKind.Interface, new Location(docURI, range)); + + EnhancedSymbolInformation fullSymbol = new EnhancedSymbolInformation(symbol, null); + handler.addSymbol(project, docURI, fullSymbol); + } + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringSymbolIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringSymbolIndex.java index b5a9f0e7a..d3a885132 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringSymbolIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringSymbolIndex.java @@ -15,8 +15,10 @@ import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -120,7 +122,10 @@ public class SpringSymbolIndex { } }; -// this.indexer = new SpringIndexer[] {new SpringIndexerJava(handler, specificProviders), new SpringIndexerXML(handler) }; +// Map namespaceHandler = new HashMap<>(); +// namespaceHandler.put("http://www.springframework.org/schema/beans", new SpringIndexerXMLNamespaceHandlerBeans()); +// SpringIndexerXML springIndexerXML = new SpringIndexerXML(handler, namespaceHandler); +// this.indexer = new SpringIndexer[] {new SpringIndexerJava(handler, specificProviders), springIndexerXML }; this.indexer = new SpringIndexer[] {new SpringIndexerJava(handler, specificProviders)}; this.updateQueue = Executors.newSingleThreadExecutor(); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerXMLProjectTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerXMLProjectTest.java index 1aeb38e05..a9c9be0d4 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerXMLProjectTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerXMLProjectTest.java @@ -72,9 +72,9 @@ public class SpringIndexerXMLProjectTest { // assertEquals(3, allSymbols.size()); // // String docUri = directory.toPath().resolve("config/simple-spring-config.xml").toUri().toString(); -// assertTrue(containsSymbol(allSymbols, "@+ 'transactionManager' DataSourceTransactionManager", docUri, 6, 8, 7, 46)); -// assertTrue(containsSymbol(allSymbols, "@+ 'jdbcTemplate' JdbcTemplate", docUri, 11, 1, 11, 28)); -// assertTrue(containsSymbol(allSymbols, "@+ 'namedParameterJdbcTemplate' NamedParameterJdbcTemplate", docUri, 11, 1, 11, 28)); +// assertTrue(containsSymbol(allSymbols, "@+ 'transactionManager' DataSourceTransactionManager", docUri, 7, 143, 7, 144)); +// assertTrue(containsSymbol(allSymbols, "@+ 'jdbcTemplate' JdbcTemplate", docUri, 9, 84, 9, 85)); +// assertTrue(containsSymbol(allSymbols, "@+ 'namedParameterJdbcTemplate' NamedParameterJdbcTemplate", docUri, 14, 91, 14, 92)); } private boolean containsSymbol(List symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) {