From 7288dd0bc5309b9f5135d0a6e751f3148a89b3db Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 9 Nov 2022 15:23:28 -0800 Subject: [PATCH 1/4] add initial AppServer implementation (GlassFish) and supporting code. --- .../AppServerServiceNameDetector.java | 106 +++++++++ .../CommonAppServersServiceNameDetector.java | 30 ++- .../resourceproviders/GlassfishAppServer.java | 47 ++++ .../resourceproviders/ParseBuddy.java | 212 ++++++++++++++++++ .../resourceproviders/ResourceLocator.java | 26 +++ .../AppServerServiceNameDetectorTest.java | 126 +++++++++++ .../resourceproviders/ParseBuddyTest.java | 124 ++++++++++ 7 files changed, 669 insertions(+), 2 deletions(-) create mode 100644 resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java create mode 100644 resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java create mode 100644 resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java create mode 100644 resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java create mode 100644 resource-providers/src/test/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetectorTest.java create mode 100644 resource-providers/src/test/java/io/opentelemetry/resourceproviders/ParseBuddyTest.java diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java new file mode 100644 index 000000000..4b9e9e919 --- /dev/null +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java @@ -0,0 +1,106 @@ +/* + * Copyright Splunk Inc. + * + * 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/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 io.opentelemetry.resourceproviders; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.logging.Level.FINE; + +final class AppServerServiceNameDetector implements ServiceNameDetector { + + private static final Logger logger = + Logger.getLogger(AppServerServiceNameDetector.class.getName()); + + private final AppServer appServer; + private final ParseBuddy parseBuddy; + private final DirectoryTool dirTool; + + AppServerServiceNameDetector(AppServer appServer) { + this(appServer, new ParseBuddy(appServer), new DirectoryTool()); + } + + // Exists for testing + AppServerServiceNameDetector(AppServer appServer, ParseBuddy parseBuddy, DirectoryTool dirTool) { + this.appServer = appServer; + this.parseBuddy = parseBuddy; + this.dirTool = dirTool; + } + + @Override + public @Nullable String detect() throws Exception { + if (appServer.getServerClass() == null) { + return null; + } + + Path deploymentDir = appServer.getDeploymentDir(); + if (deploymentDir == null) { + return null; + } + + if (!dirTool.isDirectory(deploymentDir)) { + logger.log(FINE, "Deployment dir '{0}' doesn't exist.", deploymentDir); + return null; + } + + logger.log(FINE, "Looking for deployments in '{0}'.", deploymentDir); + try (Stream stream = dirTool.list(deploymentDir)) { + return stream.map(this::detectName) + .filter(Objects::nonNull) + .findFirst().orElse(null); + } + } + + private String detectName(Path path) { + if (!appServer.isValidAppName(path)) { + logger.log(FINE, "Skipping '{0}'.", path); + return null; + } + + logger.log(FINE, "Attempting service name detection in '{0}'.", path); + String name = path.getFileName().toString(); + if (dirTool.isDirectory(path)) { + return parseBuddy.handleExplodedApp(path); + } + if (name.endsWith(".war")) { + return parseBuddy.handlePackagedWar(path); + } + if (appServer.supportsEar() && name.endsWith(".ear")) { + return parseBuddy.handlePackagedEar(path); + } + + return null; + } + + // Exists for testing + static class DirectoryTool { + boolean isDirectory(Path path){ + return Files.isDirectory(path); + } + + Stream list(Path path) throws IOException { + return Files.list(path); + } + + } +} diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java index e6fceaf34..d034490ce 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java @@ -5,6 +5,8 @@ package io.opentelemetry.resourceproviders; +import java.net.URL; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -21,7 +23,31 @@ static ServiceNameDetector create() { private CommonAppServersServiceNameDetector() {} private static List detectors() { - // TBD: This will contain common app server detector implementations - return Collections.emptyList(); + ResourceLocator locator = new ResourceLocatorImpl(); + // Additional implementations will be added to this list. + return Collections.singletonList( + detectorFor(new GlassfishAppServer(locator))); } + + private static AppServerServiceNameDetector detectorFor(AppServer appServer) { + return new AppServerServiceNameDetector(appServer); + } + + private static class ResourceLocatorImpl implements ResourceLocator { + + @Override + public Class findClass(String className) { + try { + return Class.forName(className, false, ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException | LinkageError exception) { + return null; + } + } + + @Override + public URL getClassLocation(Class clazz) { + return clazz.getProtectionDomain().getCodeSource().getLocation(); + } + } + } diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java new file mode 100644 index 000000000..1d3fac0b4 --- /dev/null +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java @@ -0,0 +1,47 @@ +/* + * Copyright Splunk Inc. + * + * 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/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 io.opentelemetry.resourceproviders; + +import java.nio.file.Path; +import java.nio.file.Paths; + +class GlassfishAppServer implements AppServer { + + private final String SERVICE_CLASS_NAME = "com.sun.enterprise.glassfish.bootstrap.ASMain"; + private final ResourceLocator locator; + + GlassfishAppServer(ResourceLocator locator) { + this.locator = locator; + } + + @Override + public Path getDeploymentDir() { + String instanceRoot = System.getProperty("com.sun.aas.instanceRoot"); + if (instanceRoot == null) { + return null; + } + + // besides autodeploy directory it is possible to deploy applications through admin console and + // asadmin script, to detect those we would need to parse config/domain.xml + return Paths.get(instanceRoot, "autodeploy"); + } + + @Override + public Class getServerClass() { + return locator.findClass(SERVICE_CLASS_NAME); + } +} diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java new file mode 100644 index 000000000..18ad424d2 --- /dev/null +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java @@ -0,0 +1,212 @@ +/* + * Copyright Splunk Inc. + * + * 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/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 io.opentelemetry.resourceproviders; + +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.WARNING; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** Helper class for parsing webserver xml files from various locations. */ +class ParseBuddy { + + private static final Logger logger = Logger.getLogger(ParseBuddy.class.getName()); + + private final AppServer appServer; + private final Filesystem filesystem; + + ParseBuddy(AppServer appServer) { + this(appServer, new Filesystem()); + } + + // Exists for testing + ParseBuddy(AppServer appServer, Filesystem filesystem) { + this.appServer = appServer; + this.filesystem = filesystem; + } + + String handleExplodedApp(Path path) { + String warResult = handleExplodedWar(path); + if (warResult != null) { + return warResult; + } + if (appServer.supportsEar()) { + return handleExplodedEar(path); + } + return null; + } + + String handlePackagedWar(Path path) { + return handlePackaged(path, "WEB-INF/web.xml", newWebXmlHandler()); + } + + String handlePackagedEar(Path path) { + return handlePackaged(path, "META-INF/application.xml", newAppXmlHandler()); + } + + private String handlePackaged(Path path, String descriptorPath, DescriptorHandler handler) { + try (ZipFile zip = filesystem.openZipFile(path)) { + ZipEntry zipEntry = zip.getEntry(descriptorPath); + if (zipEntry != null) { + return handle(() -> zip.getInputStream(zipEntry), path, handler); + } + } catch (IOException exception) { + if (logger.isLoggable(WARNING)) { + logger.log( + WARNING, "Failed to read '" + descriptorPath + "' from zip '" + path + "'.", exception); + } + } + + return null; + } + + String handleExplodedWar(Path path) { + return handleExploded(path, path.resolve("WEB-INF/web.xml"), newWebXmlHandler()); + } + + String handleExplodedEar(Path path) { + return handleExploded( + path, path.resolve("META-INF/application.xml"), newAppXmlHandler()); + } + + private String handleExploded(Path path, Path descriptor, DescriptorHandler handler) { + if (filesystem.isRegularFile(descriptor)) { + return handle(() -> filesystem.newInputStream(descriptor), path, handler); + } + + return null; + } + + private String handle(InputStreamSupplier supplier, Path path, DescriptorHandler handler) { + try { + try (InputStream inputStream = supplier.supply()) { + String candidate = parseDescriptor(inputStream, handler); + if (appServer.isValidResult(path, candidate)) { + return candidate; + } + } + } catch (Exception exception) { + logger.log(WARNING, "Failed to parse descriptor", exception); + } + + return null; + } + + private static String parseDescriptor(InputStream inputStream, DescriptorHandler handler) + throws ParserConfigurationException, SAXException, IOException { + if (SaxParserFactoryHolder.saxParserFactory == null) { + return null; + } + SAXParser saxParser = SaxParserFactoryHolder.saxParserFactory.newSAXParser(); + saxParser.parse(inputStream, handler); + return handler.displayName; + } + + private interface InputStreamSupplier { + InputStream supply() throws IOException; + } + + private static DescriptorHandler newWebXmlHandler(){ + return new DescriptorHandler("web-app"); + } + + private static DescriptorHandler newAppXmlHandler(){ + return new DescriptorHandler("application"); + } + + private final static class DescriptorHandler extends DefaultHandler { + private final String rootElementName; + private final Deque currentElement = new ArrayDeque<>(); + private boolean setDisplayName; + String displayName; + + DescriptorHandler(String rootElementName) { + this.rootElementName = rootElementName; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) { + if (displayName == null + && rootElementName.equals(currentElement.peek()) + && "display-name".equals(qName)) { + String lang = attributes.getValue("xml:lang"); + if (lang == null || "".equals(lang)) { + lang = "en"; // en is the default language + } + if ("en".equals(lang)) { + setDisplayName = true; + } + } + currentElement.push(qName); + } + + @Override + public void endElement(String uri, String localName, String qName) { + currentElement.pop(); + setDisplayName = false; + } + + @Override + public void characters(char[] ch, int start, int length) { + if (setDisplayName) { + displayName = new String(ch, start, length); + } + } + } + + private static class SaxParserFactoryHolder { + private static final SAXParserFactory saxParserFactory = getSaxParserFactory(); + + private static SAXParserFactory getSaxParserFactory() { + try { + return SAXParserFactory.newInstance(); + } catch (Throwable throwable) { + logger.log(FINE, "XML parser not available.", throwable); + } + return null; + } + } + + // Exists for testing + static class Filesystem { + boolean isRegularFile(Path path) { + return Files.isRegularFile(path); + } + + InputStream newInputStream(Path path) throws IOException { + return Files.newInputStream(path); + } + + ZipFile openZipFile(Path path) throws IOException { + return new ZipFile(path.toFile()); + } + } +} diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java new file mode 100644 index 000000000..5ada8a7b7 --- /dev/null +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java @@ -0,0 +1,26 @@ +/* + * Copyright Splunk Inc. + * + * 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/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 io.opentelemetry.resourceproviders; + +import java.net.URL; + +interface ResourceLocator { + + Class findClass(String className); + + URL getClassLocation(Class clazz); +} diff --git a/resource-providers/src/test/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetectorTest.java b/resource-providers/src/test/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetectorTest.java new file mode 100644 index 000000000..88e049110 --- /dev/null +++ b/resource-providers/src/test/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetectorTest.java @@ -0,0 +1,126 @@ +package io.opentelemetry.resourceproviders; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class AppServerServiceNameDetectorTest { + + @Mock + private AppServer appServer; + @Mock + private AppServerServiceNameDetector.DirectoryTool dirTool; + @Mock + private ParseBuddy parseBuddy; + + @Test + void detectNullServerClass() throws Exception { + AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer); + assertThat(detector.detect()).isNull(); + } + + @Test + void nullDeploymentDir() throws Exception { + doReturn(AppServer.class).when(appServer).getServerClass(); + AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer); + assertThat(detector.detect()).isNull(); + } + + @Test + void detectMissingDir() throws Exception { + Path deploymentDir = Paths.get("/fake", "location"); + + doReturn(AppServer.class).when(appServer).getServerClass(); + when(appServer.getDeploymentDir()).thenReturn(deploymentDir); + when(dirTool.isDirectory(deploymentDir)).thenReturn(false); + + AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, null, dirTool); + assertThat(detector.detect()).isNull(); + } + + @Test + void detect_explodedApp() throws Exception { + Path deploymentDir = Paths.get("/fake", "location"); + Path path1 = Paths.get("path1.xml"); + Path path2 = Paths.get("something/"); + + doReturn(AppServer.class).when(appServer).getServerClass(); + when(appServer.getDeploymentDir()).thenReturn(deploymentDir); + when(appServer.isValidAppName(path1)).thenReturn(false); + when(appServer.isValidAppName(path2)).thenReturn(true); + when(dirTool.isDirectory(deploymentDir)).thenReturn(true); + when(dirTool.list(deploymentDir)).thenReturn(Stream.of(path1, path2)); + when(dirTool.isDirectory(path2)).thenReturn(true); + when(parseBuddy.handleExplodedApp(path2)).thenReturn("RadicalService99"); + + AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); + assertThat(detector.detect()).isEqualTo("RadicalService99"); + } + + @Test + void detect_packagedWar() throws Exception { + Path deploymentDir = Paths.get("/fake", "location"); + Path path1 = Paths.get("meh"); + Path path2 = Paths.get("excellent.war"); + + doReturn(AppServer.class).when(appServer).getServerClass(); + when(appServer.getDeploymentDir()).thenReturn(deploymentDir); + when(appServer.isValidAppName(path1)).thenReturn(false); + when(appServer.isValidAppName(path2)).thenReturn(true); + when(dirTool.isDirectory(deploymentDir)).thenReturn(true); + when(dirTool.list(deploymentDir)).thenReturn(Stream.of(path1, path2)); + when(dirTool.isDirectory(path2)).thenReturn(false); + when(parseBuddy.handlePackagedWar(path2)).thenReturn("WhatIsItGoodFor"); + + AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); + assertThat(detector.detect()).isEqualTo("WhatIsItGoodFor"); + } + + @Test + void detect_packagedEar() throws Exception { + Path deploymentDir = Paths.get("/fake", "location"); + Path path1 = Paths.get("meh"); + Path path2 = Paths.get("excellent.ear"); + + doReturn(AppServer.class).when(appServer).getServerClass(); + when(appServer.getDeploymentDir()).thenReturn(deploymentDir); + when(appServer.isValidAppName(path1)).thenReturn(false); + when(appServer.isValidAppName(path2)).thenReturn(true); + when(appServer.supportsEar()).thenReturn(true); + + when(dirTool.isDirectory(deploymentDir)).thenReturn(true); + when(dirTool.list(deploymentDir)).thenReturn(Stream.of(path1, path2)); + when(dirTool.isDirectory(path2)).thenReturn(false); + when(parseBuddy.handlePackagedEar(path2)).thenReturn("Cochlea"); + + AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); + assertThat(detector.detect()).isEqualTo("Cochlea"); + } + + @Test + void detect_nothing() throws Exception { + Path deploymentDir = Paths.get("/fake", "location"); + Path path1 = Paths.get("meh"); + + doReturn(AppServer.class).when(appServer).getServerClass(); + when(appServer.getDeploymentDir()).thenReturn(deploymentDir); + when(appServer.isValidAppName(path1)).thenReturn(true); + when(appServer.supportsEar()).thenReturn(true); + + when(dirTool.isDirectory(deploymentDir)).thenReturn(true); + when(dirTool.list(deploymentDir)).thenReturn(Stream.of(path1)); + + AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); + assertThat(detector.detect()).isNull(); + } + +} \ No newline at end of file diff --git a/resource-providers/src/test/java/io/opentelemetry/resourceproviders/ParseBuddyTest.java b/resource-providers/src/test/java/io/opentelemetry/resourceproviders/ParseBuddyTest.java new file mode 100644 index 000000000..5fe3469d9 --- /dev/null +++ b/resource-providers/src/test/java/io/opentelemetry/resourceproviders/ParseBuddyTest.java @@ -0,0 +1,124 @@ +package io.opentelemetry.resourceproviders; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ParseBuddyTest { + + final Path path = Paths.get("dir/"); + final Path webXml = Paths.get("dir/WEB-INF/web.xml"); + final Path applicationXml = Paths.get("dir/META-INF/application.xml"); + final InputStream webXmlStream = new ByteArrayInputStream( + "goats".getBytes(UTF_8)); + final InputStream appXmlStream = new ByteArrayInputStream( + "piglet".getBytes(UTF_8)); + + @Mock + private AppServer appServer; + @Mock + private ParseBuddy.Filesystem filesystem; + + @Test + void explodedApp_war() throws Exception { + + when(filesystem.isRegularFile(webXml)).thenReturn(true); + when(filesystem.newInputStream(webXml)).thenReturn(webXmlStream); + when(appServer.isValidResult(path, "goats")).thenReturn(true); + + ParseBuddy parseBuddy = new ParseBuddy(appServer, filesystem); + + String result = parseBuddy.handleExplodedApp(path); + assertThat(result).isEqualTo("goats"); + } + + @Test + void explodedApp_malformedWarXml() throws Exception { + InputStream stream = new ByteArrayInputStream("".getBytes(UTF_8)); + + when(filesystem.isRegularFile(webXml)).thenReturn(true); + when(filesystem.newInputStream(webXml)).thenReturn(stream); + + ParseBuddy parseBuddy = new ParseBuddy(appServer, filesystem); + + String result = parseBuddy.handleExplodedApp(path); + assertThat(result).isNull(); + } + + @Test + void explodedApp_ear() throws Exception { + + when(filesystem.isRegularFile(webXml)).thenReturn(false); + when(filesystem.isRegularFile(applicationXml)).thenReturn(true); + when(filesystem.newInputStream(applicationXml)).thenReturn(appXmlStream); + when(appServer.supportsEar()).thenReturn(true); + when(appServer.isValidResult(path, "piglet")).thenReturn(true); + + ParseBuddy parseBuddy = new ParseBuddy(appServer, filesystem); + + String result = parseBuddy.handleExplodedApp(path); + assertThat(result).isEqualTo("piglet"); + } + + @Test + void packagedWar() throws Exception { + Path warFile = Paths.get("/path/to/amaze.war"); + + ZipFile zipFile = mock(ZipFile.class); + ZipEntry zipEntry = mock(ZipEntry.class); + + when(zipFile.getEntry("WEB-INF/web.xml")).thenReturn(zipEntry); + when(appServer.isValidResult(warFile, "goats")).thenReturn(true); + when(filesystem.openZipFile(warFile)).thenReturn(zipFile); + when(zipFile.getInputStream(zipEntry)).thenReturn(webXmlStream); + + ParseBuddy parseBuddy = new ParseBuddy(appServer, filesystem); + + String result = parseBuddy.handlePackagedWar(warFile); + assertThat(result).isEqualTo("goats"); + } + + @Test + void handlePackagedThrows() throws Exception { + Path warFile = Paths.get("/path/to/amaze.war"); + + when(filesystem.openZipFile(warFile)).thenThrow(new IOException("boom")); + + ParseBuddy parseBuddy = new ParseBuddy(appServer, filesystem); + + String result = parseBuddy.handlePackagedWar(warFile); + assertThat(result).isNull(); + } + + @Test + void packagedEar() throws Exception { + Path earFile = Paths.get("/path/to/amaze.ear"); + + ZipFile zipFile = mock(ZipFile.class); + ZipEntry zipEntry = mock(ZipEntry.class); + + when(zipFile.getEntry("META-INF/application.xml")).thenReturn(zipEntry); + when(appServer.isValidResult(earFile, "piglet")).thenReturn(true); + when(filesystem.openZipFile(earFile)).thenReturn(zipFile); + when(zipFile.getInputStream(zipEntry)).thenReturn(appXmlStream); + + ParseBuddy parseBuddy = new ParseBuddy(appServer, filesystem); + + String result = parseBuddy.handlePackagedEar(earFile); + assertThat(result).isEqualTo("piglet"); + } +} \ No newline at end of file From 4e82d622b5229e4ad6b18cdd469396e0b45d59b7 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Wed, 9 Nov 2022 15:25:41 -0800 Subject: [PATCH 2/4] spotless --- .../AppServerServiceNameDetector.java | 29 ++++------------- .../CommonAppServersServiceNameDetector.java | 5 +-- .../resourceproviders/GlassfishAppServer.java | 15 ++------- .../resourceproviders/ParseBuddy.java | 24 ++++---------- .../resourceproviders/ResourceLocator.java | 15 ++------- .../AppServerServiceNameDetectorTest.java | 32 +++++++++++-------- .../resourceproviders/ParseBuddyTest.java | 23 +++++++------ 7 files changed, 51 insertions(+), 92 deletions(-) diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java index 4b9e9e919..8920ae46d 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java @@ -1,31 +1,19 @@ /* - * Copyright Splunk Inc. - * - * 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/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. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ package io.opentelemetry.resourceproviders; -import javax.annotation.Nullable; +import static java.util.logging.Level.FINE; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Objects; import java.util.logging.Logger; -import java.util.stream.Collectors; import java.util.stream.Stream; - -import static java.util.logging.Level.FINE; +import javax.annotation.Nullable; final class AppServerServiceNameDetector implements ServiceNameDetector { @@ -65,9 +53,7 @@ final class AppServerServiceNameDetector implements ServiceNameDetector { logger.log(FINE, "Looking for deployments in '{0}'.", deploymentDir); try (Stream stream = dirTool.list(deploymentDir)) { - return stream.map(this::detectName) - .filter(Objects::nonNull) - .findFirst().orElse(null); + return stream.map(this::detectName).filter(Objects::nonNull).findFirst().orElse(null); } } @@ -94,13 +80,12 @@ private String detectName(Path path) { // Exists for testing static class DirectoryTool { - boolean isDirectory(Path path){ + boolean isDirectory(Path path) { return Files.isDirectory(path); } Stream list(Path path) throws IOException { return Files.list(path); } - } } diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java index d034490ce..0745ff846 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java @@ -6,7 +6,6 @@ package io.opentelemetry.resourceproviders; import java.net.URL; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -25,8 +24,7 @@ private CommonAppServersServiceNameDetector() {} private static List detectors() { ResourceLocator locator = new ResourceLocatorImpl(); // Additional implementations will be added to this list. - return Collections.singletonList( - detectorFor(new GlassfishAppServer(locator))); + return Collections.singletonList(detectorFor(new GlassfishAppServer(locator))); } private static AppServerServiceNameDetector detectorFor(AppServer appServer) { @@ -49,5 +47,4 @@ public URL getClassLocation(Class clazz) { return clazz.getProtectionDomain().getCodeSource().getLocation(); } } - } diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java index 1d3fac0b4..a7318944c 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java @@ -1,17 +1,6 @@ /* - * Copyright Splunk Inc. - * - * 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/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. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ package io.opentelemetry.resourceproviders; diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java index 18ad424d2..745ab88c6 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java @@ -1,17 +1,6 @@ /* - * Copyright Splunk Inc. - * - * 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/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. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ package io.opentelemetry.resourceproviders; @@ -93,8 +82,7 @@ String handleExplodedWar(Path path) { } String handleExplodedEar(Path path) { - return handleExploded( - path, path.resolve("META-INF/application.xml"), newAppXmlHandler()); + return handleExploded(path, path.resolve("META-INF/application.xml"), newAppXmlHandler()); } private String handleExploded(Path path, Path descriptor, DescriptorHandler handler) { @@ -134,15 +122,15 @@ private interface InputStreamSupplier { InputStream supply() throws IOException; } - private static DescriptorHandler newWebXmlHandler(){ + private static DescriptorHandler newWebXmlHandler() { return new DescriptorHandler("web-app"); } - private static DescriptorHandler newAppXmlHandler(){ + private static DescriptorHandler newAppXmlHandler() { return new DescriptorHandler("application"); } - private final static class DescriptorHandler extends DefaultHandler { + private static final class DescriptorHandler extends DefaultHandler { private final String rootElementName; private final Deque currentElement = new ArrayDeque<>(); private boolean setDisplayName; diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java index 5ada8a7b7..ed69bb7b2 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java @@ -1,17 +1,6 @@ /* - * Copyright Splunk Inc. - * - * 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/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. + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 */ package io.opentelemetry.resourceproviders; diff --git a/resource-providers/src/test/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetectorTest.java b/resource-providers/src/test/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetectorTest.java index 88e049110..776fa2cf7 100644 --- a/resource-providers/src/test/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetectorTest.java +++ b/resource-providers/src/test/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetectorTest.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.resourceproviders; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @@ -15,12 +20,9 @@ @ExtendWith(MockitoExtension.class) class AppServerServiceNameDetectorTest { - @Mock - private AppServer appServer; - @Mock - private AppServerServiceNameDetector.DirectoryTool dirTool; - @Mock - private ParseBuddy parseBuddy; + @Mock private AppServer appServer; + @Mock private AppServerServiceNameDetector.DirectoryTool dirTool; + @Mock private ParseBuddy parseBuddy; @Test void detectNullServerClass() throws Exception { @@ -43,7 +45,8 @@ void detectMissingDir() throws Exception { when(appServer.getDeploymentDir()).thenReturn(deploymentDir); when(dirTool.isDirectory(deploymentDir)).thenReturn(false); - AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, null, dirTool); + AppServerServiceNameDetector detector = + new AppServerServiceNameDetector(appServer, null, dirTool); assertThat(detector.detect()).isNull(); } @@ -62,7 +65,8 @@ void detect_explodedApp() throws Exception { when(dirTool.isDirectory(path2)).thenReturn(true); when(parseBuddy.handleExplodedApp(path2)).thenReturn("RadicalService99"); - AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); + AppServerServiceNameDetector detector = + new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); assertThat(detector.detect()).isEqualTo("RadicalService99"); } @@ -81,7 +85,8 @@ void detect_packagedWar() throws Exception { when(dirTool.isDirectory(path2)).thenReturn(false); when(parseBuddy.handlePackagedWar(path2)).thenReturn("WhatIsItGoodFor"); - AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); + AppServerServiceNameDetector detector = + new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); assertThat(detector.detect()).isEqualTo("WhatIsItGoodFor"); } @@ -102,7 +107,8 @@ void detect_packagedEar() throws Exception { when(dirTool.isDirectory(path2)).thenReturn(false); when(parseBuddy.handlePackagedEar(path2)).thenReturn("Cochlea"); - AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); + AppServerServiceNameDetector detector = + new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); assertThat(detector.detect()).isEqualTo("Cochlea"); } @@ -119,8 +125,8 @@ void detect_nothing() throws Exception { when(dirTool.isDirectory(deploymentDir)).thenReturn(true); when(dirTool.list(deploymentDir)).thenReturn(Stream.of(path1)); - AppServerServiceNameDetector detector = new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); + AppServerServiceNameDetector detector = + new AppServerServiceNameDetector(appServer, parseBuddy, dirTool); assertThat(detector.detect()).isNull(); } - -} \ No newline at end of file +} diff --git a/resource-providers/src/test/java/io/opentelemetry/resourceproviders/ParseBuddyTest.java b/resource-providers/src/test/java/io/opentelemetry/resourceproviders/ParseBuddyTest.java index 5fe3469d9..338098fd9 100644 --- a/resource-providers/src/test/java/io/opentelemetry/resourceproviders/ParseBuddyTest.java +++ b/resource-providers/src/test/java/io/opentelemetry/resourceproviders/ParseBuddyTest.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.resourceproviders; import static java.nio.charset.StandardCharsets.UTF_8; @@ -23,15 +28,15 @@ class ParseBuddyTest { final Path path = Paths.get("dir/"); final Path webXml = Paths.get("dir/WEB-INF/web.xml"); final Path applicationXml = Paths.get("dir/META-INF/application.xml"); - final InputStream webXmlStream = new ByteArrayInputStream( - "goats".getBytes(UTF_8)); - final InputStream appXmlStream = new ByteArrayInputStream( - "piglet".getBytes(UTF_8)); + final InputStream webXmlStream = + new ByteArrayInputStream( + "goats".getBytes(UTF_8)); + final InputStream appXmlStream = + new ByteArrayInputStream( + "piglet".getBytes(UTF_8)); - @Mock - private AppServer appServer; - @Mock - private ParseBuddy.Filesystem filesystem; + @Mock private AppServer appServer; + @Mock private ParseBuddy.Filesystem filesystem; @Test void explodedApp_war() throws Exception { @@ -121,4 +126,4 @@ void packagedEar() throws Exception { String result = parseBuddy.handlePackagedEar(earFile); assertThat(result).isEqualTo("piglet"); } -} \ No newline at end of file +} From 73bd957c9bc8ffc25009225f769b70c7ec27dd9c Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Thu, 10 Nov 2022 09:30:43 -0800 Subject: [PATCH 3/4] errorprone @Nullable party --- .../resourceproviders/AppServer.java | 2 ++ .../AppServerServiceNameDetector.java | 6 +++++- .../CommonAppServersServiceNameDetector.java | 2 ++ .../resourceproviders/GlassfishAppServer.java | 5 ++++- .../resourceproviders/ParseBuddy.java | 15 +++++++++++++-- .../resourceproviders/ResourceLocator.java | 2 ++ 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServer.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServer.java index 671bc57ee..679dd5c96 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServer.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServer.java @@ -14,12 +14,14 @@ interface AppServer { /** Path to directory to be scanned for deployments. */ + @Nullable Path getDeploymentDir() throws Exception; /** * Returns a single class that, when present, determines that the given application server is * active/running. */ + @Nullable Class getServerClass(); /** diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java index 8920ae46d..94aafc7ba 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/AppServerServiceNameDetector.java @@ -7,6 +7,7 @@ import static java.util.logging.Level.FINE; +import com.google.errorprone.annotations.MustBeClosed; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -36,7 +37,8 @@ final class AppServerServiceNameDetector implements ServiceNameDetector { } @Override - public @Nullable String detect() throws Exception { + @Nullable + public String detect() throws Exception { if (appServer.getServerClass() == null) { return null; } @@ -57,6 +59,7 @@ final class AppServerServiceNameDetector implements ServiceNameDetector { } } + @Nullable private String detectName(Path path) { if (!appServer.isValidAppName(path)) { logger.log(FINE, "Skipping '{0}'.", path); @@ -84,6 +87,7 @@ boolean isDirectory(Path path) { return Files.isDirectory(path); } + @MustBeClosed Stream list(Path path) throws IOException { return Files.list(path); } diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java index 0745ff846..9006199f4 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/CommonAppServersServiceNameDetector.java @@ -8,6 +8,7 @@ import java.net.URL; import java.util.Collections; import java.util.List; +import javax.annotation.Nullable; /** * This class is just a factory that provides a ServiceNameDetector that knows how to find and parse @@ -34,6 +35,7 @@ private static AppServerServiceNameDetector detectorFor(AppServer appServer) { private static class ResourceLocatorImpl implements ResourceLocator { @Override + @Nullable public Class findClass(String className) { try { return Class.forName(className, false, ClassLoader.getSystemClassLoader()); diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java index a7318944c..1387cea12 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/GlassfishAppServer.java @@ -7,16 +7,18 @@ import java.nio.file.Path; import java.nio.file.Paths; +import javax.annotation.Nullable; class GlassfishAppServer implements AppServer { - private final String SERVICE_CLASS_NAME = "com.sun.enterprise.glassfish.bootstrap.ASMain"; + private static final String SERVICE_CLASS_NAME = "com.sun.enterprise.glassfish.bootstrap.ASMain"; private final ResourceLocator locator; GlassfishAppServer(ResourceLocator locator) { this.locator = locator; } + @Nullable @Override public Path getDeploymentDir() { String instanceRoot = System.getProperty("com.sun.aas.instanceRoot"); @@ -30,6 +32,7 @@ public Path getDeploymentDir() { } @Override + @Nullable public Class getServerClass() { return locator.findClass(SERVICE_CLASS_NAME); } diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java index 745ab88c6..8b809f139 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ParseBuddy.java @@ -17,6 +17,7 @@ import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import javax.annotation.Nullable; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; @@ -42,6 +43,7 @@ class ParseBuddy { this.filesystem = filesystem; } + @Nullable String handleExplodedApp(Path path) { String warResult = handleExplodedWar(path); if (warResult != null) { @@ -53,14 +55,17 @@ String handleExplodedApp(Path path) { return null; } + @Nullable String handlePackagedWar(Path path) { return handlePackaged(path, "WEB-INF/web.xml", newWebXmlHandler()); } + @Nullable String handlePackagedEar(Path path) { return handlePackaged(path, "META-INF/application.xml", newAppXmlHandler()); } + @Nullable private String handlePackaged(Path path, String descriptorPath, DescriptorHandler handler) { try (ZipFile zip = filesystem.openZipFile(path)) { ZipEntry zipEntry = zip.getEntry(descriptorPath); @@ -77,14 +82,17 @@ private String handlePackaged(Path path, String descriptorPath, DescriptorHandle return null; } + @Nullable String handleExplodedWar(Path path) { return handleExploded(path, path.resolve("WEB-INF/web.xml"), newWebXmlHandler()); } + @Nullable String handleExplodedEar(Path path) { return handleExploded(path, path.resolve("META-INF/application.xml"), newAppXmlHandler()); } + @Nullable private String handleExploded(Path path, Path descriptor, DescriptorHandler handler) { if (filesystem.isRegularFile(descriptor)) { return handle(() -> filesystem.newInputStream(descriptor), path, handler); @@ -93,6 +101,7 @@ private String handleExploded(Path path, Path descriptor, DescriptorHandler hand return null; } + @Nullable private String handle(InputStreamSupplier supplier, Path path, DescriptorHandler handler) { try { try (InputStream inputStream = supplier.supply()) { @@ -108,6 +117,7 @@ private String handle(InputStreamSupplier supplier, Path path, DescriptorHandler return null; } + @Nullable private static String parseDescriptor(InputStream inputStream, DescriptorHandler handler) throws ParserConfigurationException, SAXException, IOException { if (SaxParserFactoryHolder.saxParserFactory == null) { @@ -134,7 +144,7 @@ private static final class DescriptorHandler extends DefaultHandler { private final String rootElementName; private final Deque currentElement = new ArrayDeque<>(); private boolean setDisplayName; - String displayName; + @Nullable private String displayName; DescriptorHandler(String rootElementName) { this.rootElementName = rootElementName; @@ -171,8 +181,9 @@ public void characters(char[] ch, int start, int length) { } private static class SaxParserFactoryHolder { - private static final SAXParserFactory saxParserFactory = getSaxParserFactory(); + @Nullable private static final SAXParserFactory saxParserFactory = getSaxParserFactory(); + @Nullable private static SAXParserFactory getSaxParserFactory() { try { return SAXParserFactory.newInstance(); diff --git a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java index ed69bb7b2..3fdaa79a3 100644 --- a/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java +++ b/resource-providers/src/main/java/io/opentelemetry/resourceproviders/ResourceLocator.java @@ -6,9 +6,11 @@ package io.opentelemetry.resourceproviders; import java.net.URL; +import javax.annotation.Nullable; interface ResourceLocator { + @Nullable Class findClass(String className); URL getClassLocation(Class clazz); From cebc4618a9e4268edd9bbcccfca49b4b34f48a33 Mon Sep 17 00:00:00 2001 From: Jason Plumb Date: Tue, 15 Nov 2022 12:49:26 -0800 Subject: [PATCH 4/4] add notes about operation and start list of appservers --- resource-providers/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/resource-providers/README.md b/resource-providers/README.md index 4c1882edf..8eb8fd346 100644 --- a/resource-providers/README.md +++ b/resource-providers/README.md @@ -10,10 +10,14 @@ to populate the `service.name` resource attribute based on the runtime configura of an app server. This is useful when a user has not yet specified the `service.name` resource attribute manually. -It is capable of detecting common scenarios among the following popular application servers: +This `ResourceProvider` supports `.ear` and `.war` archives as well as exploded directory +versions of each. For `.war` files, it attempts to parse the `` element +from `WEB-INF/web.xml`. For `.ear` files the `` element of `META-INF/application.xml`. -* tbd (will be filled in as implementations are added) +It is capable of detecting common scenarios among the popular application servers listed below: +* GlassFish +* _remaining are tbd_ ## Component owners