• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eXist-db / exist / 40657517912

28 Oct 2026 08:32AM UTC coverage: 58.121% (-0.08%) from 58.196%
40657517912

push

github

web-flow
Merge pull request #6938 from eXist-db/dependabot/github_actions/actions-0c219a018e

Bump docker/login-action from 4.6.0 to 4.7.0 in the actions group

32462 of 61752 branches covered (52.57%)

Branch coverage included in aggregate %.

85521 of 141244 relevant lines covered (60.55%)

2.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

13.22
/exist-core/src/main/java/org/exist/repo/ClasspathHelper.java
1
/*
2
 * eXist-db Open Source Native XML Database
3
 * Copyright (C) 2001 The eXist-db Authors
4
 *
5
 * info@exist-db.org
6
 * http://www.exist-db.org
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
 */
22
package org.exist.repo;
23

24
import org.apache.logging.log4j.LogManager;
25
import org.apache.logging.log4j.Logger;
26
import org.exist.SystemProperties;
27
import org.exist.start.classloader.Classpath;
28
import org.exist.start.classloader.EXistClassLoader;
29
import org.exist.storage.BrokerPool;
30
import org.exist.storage.BrokerPoolService;
31
import org.expath.pkg.repo.FileSystemStorage;
32
import org.expath.pkg.repo.Package;
33
import org.expath.pkg.repo.PackageException;
34
import org.expath.pkg.repo.Packages;
35
import org.expath.pkg.repo.deps.ProcessorDependency;
36

37
import java.io.BufferedReader;
38
import java.io.IOException;
39
import java.net.URI;
40
import java.nio.file.Files;
41
import java.nio.file.Path;
42
import java.util.Collection;
43
import java.util.Optional;
44
import java.util.Set;
45

46
/**
47
 * Helper class to construct classpath for expath modules containing
48
 * jar files. Part of start.jar
49
 */
50
public class ClasspathHelper implements BrokerPoolService {
3 ✔
51

52
    private final static Logger LOG = LogManager.getLogger(ClasspathHelper.class);
4 ✔
53

54
    @Override
55
    public void prepare(final BrokerPool brokerPool) {
56
        final ClassLoader loader = brokerPool.getClassLoader();
3 ✔
57
        if (!(loader instanceof EXistClassLoader)) {
3 !
58
            return;
×
59
        }
60
        final Classpath cp = new Classpath();
4 ✔
61
        scanPackages(brokerPool, cp);
3 ✔
62
        ((EXistClassLoader)loader).addURLs(cp);
4 ✔
63
    }
1 ✔
64

65
    public static void updateClasspath(BrokerPool pool, org.expath.pkg.repo.Package pkg) throws PackageException {
66
        final ClassLoader loader = pool.getClassLoader();
×
67
        if (!(loader instanceof EXistClassLoader))
×
68
            {return;}
×
69
        if (!isCompatible(pkg)) {
×
70
            LOG.warn("Package {} is not compatible with this version of eXist. To avoid conflicts, Java libraries shipping with this package are not loaded.", pkg.getName());
×
71
            return;
×
72
        }
73
        final FileSystemStorage.FileSystemResolver resolver = (FileSystemStorage.FileSystemResolver) pkg.getResolver();
×
74
        final Path packageDir = resolver.resolveResourceAsFile(".");
×
75
        final Classpath cp = new Classpath();
×
76
        try {
77
            scanPackageDir(pkg, cp, packageDir);
×
78
            ((EXistClassLoader)loader).addURLs(cp);
×
79
        } catch (final IOException e) {
×
80
            LOG.warn("An error occurred while updating classpath for package {}", pkg.getName(), e);
×
81
        }
82
    }
×
83

84
    private static void scanPackages(BrokerPool pool, Classpath classpath) {
85
        try {
86
            final Optional<ExistRepository> repo = pool.getExpathRepo();
3 ✔
87
            if (repo.isPresent()) {
3 !
88
            for (final Packages pkgs : repo.get().listPackages()) {
10 !
89
                final Package pkg = pkgs.latest();
×
90
                if (!isCompatible(pkg)) {
×
91
                    LOG.warn("Package {} is not compatible with this version of eXist. To avoid conflicts, Java libraries shipping with this package are not loaded.", pkg.getName());
×
92
                } else {
×
93
                    try {
94
                        final FileSystemStorage.FileSystemResolver resolver = (FileSystemStorage.FileSystemResolver) pkg.getResolver();
×
95
                        final Path packageDir = resolver.resolveResourceAsFile(".");
×
96
                        scanPackageDir(pkg, classpath, packageDir);
×
97
                    } catch (final IOException e) {
×
98
                        LOG.warn("An error occurred while updating classpath for package {}", pkg.getName(), e);
×
99
                    }
100
                }
101
            }
102
            }
103
        } catch (final Exception e) {
1 ✔
104
            LOG.warn("An error occurred while updating classpath for packages", e);
×
105
        }
106
    }
1 ✔
107

108
    private static boolean isCompatible(final Package pkg) throws PackageException {
109
        // determine the eXist-db version this package is compatible with
110
        final Collection<ProcessorDependency> processorDeps = pkg.getProcessorDeps();
×
111
        final String procVersion = SystemProperties.getInstance().getSystemProperty("product-version", "1.0");
×
112
        PackageLoader.Version requiresExistVersion = null;
×
113
        for (final ProcessorDependency dependency: processorDeps) {
×
114
            if (Deployment.PROCESSOR_NAME.equals(dependency.getProcessor())) {
×
115
                if (dependency.getSemver() != null) {
×
116
                    requiresExistVersion = new PackageLoader.Version(dependency.getSemver(), true);
×
117
                } else if (dependency.getSemverMax() != null || dependency.getSemverMin() != null) {
×
118
                    requiresExistVersion = new PackageLoader.Version(dependency.getSemverMin(), dependency.getSemverMax());
×
119
                } else if (dependency.getVersions() != null) {
×
120
                    requiresExistVersion = new PackageLoader.Version(dependency.getVersions(), false);
×
121
                }
122
                break;
×
123
            }
124
        }
125
        if (requiresExistVersion == null) {
×
126

127
            // does the package contain XQuery Module(s) implemented in Java?
128
            final ExistPkgInfo existPkgInfo = (ExistPkgInfo) pkg.getInfo("exist");
×
129
            if (existPkgInfo == null) {
×
130
                // no Java modules
131
                return true;
×
132
            }
133

134
            final Set<URI> javaModules = existPkgInfo.getJavaModules();
×
135
            if (javaModules == null || javaModules.isEmpty()) {
×
136
                // no Java modules
137
                return true;
×
138
            }
139

140
            /*
141
                There are eXist-db Java modules in the package,
142
                but the package does not declare which version
143
                of eXist-db (the processor) that it depends upon,
144
                therefore we assume it is incompatible.
145

146
                NOTE - In older versions of eXist-db, if the package
147
                did not declare a dependency on a specific processor
148
                version, we would check whether the version of
149
                eXist-db was between 1.4.0 and 2.2.1
150
                (inclusive). As we are now past eXist-db version
151
                5.2.0, that would always return false!
152
             */
153
            return false;
×
154

155
        } else {
156
            return requiresExistVersion.getDependencyVersion().isCompatible(procVersion);
×
157
        }
158
    }
159

160
    private static void scanPackageDir(Package pkg, Classpath classpath, Path module) throws IOException {
161
        final Path dotExist =  module.resolve(".exist");
×
162
        if (Files.exists(dotExist)) {
×
163
            if (!Files.isDirectory(dotExist)) {
×
164
                throw new IOException("The .exist config dir is not a dir: " + dotExist);
×
165
            }
166

167
            final Path cp = dotExist.resolve("classpath.txt");
×
168
            if (Files.exists(cp)) {
×
169
                try (final BufferedReader reader = Files.newBufferedReader(cp)) {
×
170
                    String line;
171
                    while ((line = reader.readLine()) != null) {
×
172
                        Path p = Path.of(line);
×
173
                        if (!p.isAbsolute()) {
×
174
                            final FileSystemStorage.FileSystemResolver res = (FileSystemStorage.FileSystemResolver) pkg.getResolver();
×
175
                            p = res.resolveComponentAsFile(line);
×
176
                        }
177
                        p = p.normalize().toAbsolutePath();
×
178

179
                        if (Files.exists(p)) {
×
180
                            classpath.addComponent(p.toString());
×
181
                        } else {
×
182
                            LOG.warn("Unable to add '" + p + "' to the classpath for EXPath package: " + pkg.getName() + ", as the file does not exist!");
×
183
                        }
184
                    }
185
                }
186
            }
187
        }
188
    }
×
189
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc