001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.util.jar;
021
022import ca.uhn.fhir.util.XmlUtil;
023
024import java.io.InputStream;
025import java.net.MalformedURLException;
026import java.net.URL;
027import java.util.jar.Attributes;
028import java.util.jar.Manifest;
029
030public class DependencyLogImpl implements IDependencyLog {
031        private static final Attributes.Name BUNDLE_SYMBOLIC_NAME = new Attributes.Name("Bundle-SymbolicName");
032        private static final Attributes.Name BUNDLE_VENDOR = new Attributes.Name("Bundle-Vendor");
033        private static final Attributes.Name BUNDLE_VERSION = new Attributes.Name("Bundle-Version");
034        private static final Attributes.Name IMPLEMENTATION_TITLE = new Attributes.Name("Implementation-Title");
035        private static final Attributes.Name IMPLEMENTATION_VENDOR = new Attributes.Name("Implementation-Vendor");
036        private static final Attributes.Name IMPLEMENTATION_VERSION = new Attributes.Name("Implementation-Version");
037        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlUtil.class);
038
039        @Override
040        public void logStaxImplementation(Class<?> theClass) {
041                try {
042                        URL rootUrl = getRootUrlForClass(theClass);
043                        if (rootUrl == null) {
044                                ourLog.info("Unable to determine location of StAX implementation containing class");
045                        } else {
046                                Manifest manifest;
047                                URL metaInfUrl = new URL(rootUrl, "META-INF/MANIFEST.MF");
048                                InputStream is = metaInfUrl.openStream();
049                                try {
050                                        manifest = new Manifest(is);
051                                } finally {
052                                        is.close();
053                                }
054                                Attributes attrs = manifest.getMainAttributes();
055                                String title = attrs.getValue(IMPLEMENTATION_TITLE);
056                                String symbolicName = attrs.getValue(BUNDLE_SYMBOLIC_NAME);
057                                if (symbolicName != null) {
058                                        int i = symbolicName.indexOf(';');
059                                        if (i != -1) {
060                                                symbolicName = symbolicName.substring(0, i);
061                                        }
062                                }
063                                String vendor = attrs.getValue(IMPLEMENTATION_VENDOR);
064                                if (vendor == null) {
065                                        vendor = attrs.getValue(BUNDLE_VENDOR);
066                                }
067                                String version = attrs.getValue(IMPLEMENTATION_VERSION);
068                                if (version == null) {
069                                        version = attrs.getValue(BUNDLE_VERSION);
070                                }
071                                if (ourLog.isDebugEnabled()) {
072                                        ourLog.debug(
073                                                        "FHIR XML procesing will use StAX implementation at {}\n  Title:         {}\n  Symbolic name: {}\n  Vendor:        {}\n  Version:       {}",
074                                                        new Object[] {rootUrl, title, symbolicName, vendor, version});
075                                } else {
076                                        ourLog.info("FHIR XML procesing will use StAX implementation '{}' version '{}'", title, version);
077                                }
078                        }
079                } catch (Throwable e) {
080                        ourLog.info("Unable to determine StAX implementation: " + e.getMessage());
081                }
082        }
083
084        private static URL getRootUrlForClass(Class<?> cls) {
085                ClassLoader classLoader = cls.getClassLoader();
086                String resource = cls.getName().replace('.', '/') + ".class";
087                if (classLoader == null) {
088                        // A null class loader means the bootstrap class loader. In this case we use the
089                        // system class loader. This is safe since we can assume that the system class
090                        // loader uses parent first as delegation policy.
091                        classLoader = ClassLoader.getSystemClassLoader();
092                }
093                URL url = classLoader.getResource(resource);
094                if (url == null) {
095                        return null;
096                }
097                String file = url.getFile();
098                if (file.endsWith(resource)) {
099                        try {
100                                return new URL(
101                                                url.getProtocol(),
102                                                url.getHost(),
103                                                url.getPort(),
104                                                file.substring(0, file.length() - resource.length()));
105                        } catch (MalformedURLException ex) {
106                                return null;
107                        }
108                }
109                return null;
110        }
111}