Skip to content

Commit

Permalink
Merge branch 'develop' into hotfix/eb-4609-transform-globals
Browse files Browse the repository at this point in the history
  • Loading branch information
adamretter committed May 10, 2023
2 parents f209fd7 + ba68294 commit 1086615
Show file tree
Hide file tree
Showing 32 changed files with 922 additions and 366 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/ci-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ jobs:
run: mvn -q -Ddocker.tag=release -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
working-directory: ./exist-docker
# NOTE (DP): This is for debugging, publishes an experimental image from inside PRs against develop
# - name: Publish experimental images
# if: github.base_ref == 'develop'
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
# DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
# run: mvn -Ddocker.tag=experimental -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
# working-directory: ./exist-docker
- name: Publish experimental images
if: github.base_ref == 'develop'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: mvn -q -Ddocker.tag=experimental -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
working-directory: ./exist-docker

6 changes: 3 additions & 3 deletions exist-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
<dependency>
<groupId>com.fasterxml.uuid</groupId>
<artifactId>java-uuid-generator</artifactId>
<version>4.1.0</version>
<version>4.1.1</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -212,8 +212,8 @@
</dependency>

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,8 @@ public static int nodeType2XQuery(final short nodeType) {
return Type.ATTRIBUTE;
case Node.TEXT_NODE:
return Type.TEXT;
case Node.CDATA_SECTION_NODE:
return Type.CDATA_SECTION;
case Node.PROCESSING_INSTRUCTION_NODE:
return Type.PROCESSING_INSTRUCTION;
case Node.COMMENT_NODE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ public ConfigurationDialog(Consumer<Boolean> callback) {
if (ports.containsKey("jetty.port")) {
httpPort.setValue(ports.get("jetty.port"));
}
if (ports.containsKey("jetty.http.port")) {
httpPort.setValue(ports.get("jetty.http.port"));
}
if (ports.containsKey("ssl.port")) {
sslPort.setValue(ports.get("ssl.port"));
}
if (ports.containsKey("jetty.ssl.port")) {
sslPort.setValue(ports.get("jetty.ssl.port"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private static void getJettyPorts(Map<String, Integer> ports, Path jettyConfig)
final int status = reader.next();
if (status == XMLStreamReader.START_ELEMENT && "SystemProperty".equals(reader.getLocalName())) {
final String name = reader.getAttributeValue(null, "name");
if (name != null && (name.equals("jetty.port") || name.equals("jetty.ssl.port"))) {
if (name != null && (name.equals("jetty.http.port") || name.equals("jetty.ssl.port"))) {
final String defaultValue = reader.getAttributeValue(null, "default");
if (defaultValue != null) {
try {
Expand Down
16 changes: 7 additions & 9 deletions exist-core/src/main/java/org/exist/storage/BrokerPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
import org.exist.scheduler.Scheduler;
import org.exist.scheduler.impl.QuartzSchedulerImpl;
import org.exist.scheduler.impl.SystemTaskJobImpl;
import org.exist.security.*;
import org.exist.security.SecurityManager;
import org.exist.security.*;
import org.exist.security.internal.SecurityManagerImpl;
import org.exist.storage.blob.BlobStore;
import org.exist.storage.blob.BlobStoreImplService;
Expand Down Expand Up @@ -116,6 +116,7 @@ public class BrokerPool extends BrokerPools implements BrokerPoolConstants, Data

private final XQuery xqueryService = new XQuery();

private AtomicLazyVal<SaxonConfiguration> saxonConfiguration = new AtomicLazyVal<>(() -> SaxonConfiguration.loadConfiguration(this));

//TODO : make it non-static since every database instance may have its own policy.
//TODO : make a default value that could be overwritten by the configuration
Expand Down Expand Up @@ -374,13 +375,6 @@ public String getStatus() {

private StartupTriggersManager startupTriggersManager;

/**
* Configuration for Saxon.
*
* One instance per-database, lazily initialised.
*/
private AtomicLazyVal<net.sf.saxon.Configuration> saxonConfig = new AtomicLazyVal<>(net.sf.saxon.Configuration::newConfiguration);

/**
* Creates and configures the database instance.
*
Expand Down Expand Up @@ -1926,7 +1920,11 @@ public void registerCollectionTrigger(final Class<? extends CollectionTrigger> c
}

public net.sf.saxon.Configuration getSaxonConfiguration() {
return saxonConfig.get();
return saxonConfiguration.get().getConfiguration();
}

public net.sf.saxon.s9api.Processor getSaxonProcessor() {
return saxonConfiguration.get().getProcessor();
}

/**
Expand Down
14 changes: 14 additions & 0 deletions exist-core/src/main/java/org/exist/util/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ public Configuration(String configFilename, Optional<Path> existHomeDirname) thr
configureTransformer((Element)transformers.item(0));
}

//saxon settings (most importantly license file for PE or EE features)
final NodeList saxon = doc.getElementsByTagName(SaxonConfiguration.SAXON_CONFIGURATION_ELEMENT_NAME);
if( saxon.getLength() > 0 ) {
configureSaxon((Element)saxon.item(0));
}

//parser settings
final NodeList parsers = doc.getElementsByTagName(HtmlToXmlParser.PARSER_ELEMENT_NAME);
if(parsers.getLength() > 0) {
Expand Down Expand Up @@ -538,6 +544,14 @@ private void configureXUpdate( Element xupdate ) throws NumberFormatException
}
}

private void configureSaxon( Element saxon )
{
final String configurationFile = getConfigAttributeValue( saxon,
SaxonConfiguration.SAXON_CONFIGURATION_FILE_ATTRIBUTE);
if (configurationFile != null) {
config.put(SaxonConfiguration.SAXON_CONFIGURATION_FILE_PROPERTY, configurationFile);
}
}

private void configureTransformer( Element transformer )
{
Expand Down
186 changes: 186 additions & 0 deletions exist-core/src/main/java/org/exist/util/SaxonConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* eXist-db Open Source Native XML Database
* Copyright (C) 2001 The eXist-db Authors
*
* [email protected]
* http://www.exist-db.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.exist.util;

import net.jcip.annotations.ThreadSafe;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.trans.XPathException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.storage.BrokerPool;

import javax.xml.transform.stream.StreamSource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;

@ThreadSafe
public final class SaxonConfiguration {

private final static Logger LOG = LogManager.getLogger(SaxonConfiguration.class);

public static final String SAXON_CONFIGURATION_ELEMENT_NAME = "saxon";
public static final String SAXON_CONFIGURATION_FILE_ATTRIBUTE = "configuration-file";
public static final String SAXON_CONFIGURATION_FILE_PROPERTY = "saxon.configuration";
private static final String SAXON_DEFAULT_SAXON_CONFIG_FILE = "saxon-config.xml";

/**
* Holds the Saxon configuration specific to a single broker pool
*/
private final net.sf.saxon.Configuration configuration;
private final Processor processor;

private SaxonConfiguration(final net.sf.saxon.Configuration configuration) {
this.configuration = configuration;
this.processor = new Processor(configuration);
}

/**
* Get the Saxon API's {@link net.sf.saxon.Configuration} object.
*
* @return Saxon internal configuration object
*/
public net.sf.saxon.Configuration getConfiguration() {
return configuration;
}

/**
* Get the Saxon API's {@link Processor} through which Saxon operations
* such as transformation can be effected.
*
* @return the Saxon {@link Processor} associated with the configuration.
*/
public Processor getProcessor() {
return processor;
}

/**
* Load the Saxon {@link net.sf.saxon.Configuration} from a configuration file when it is first needed;
* if we cannot find a configuration file (and license) to give to Saxon, it (Saxon) may still be able to find
* something by searching in more "well-known to Saxon" locations.
*
* @return a freshly loaded Saxon configuration
*/
public static SaxonConfiguration loadConfiguration(final BrokerPool brokerPool) {

final var existConfiguration = brokerPool.getConfiguration();
final var saxonConfigFile = getSaxonConfigFile(existConfiguration);
Optional<net.sf.saxon.Configuration> saxonConfiguration = Optional.empty();
if (saxonConfigFile.isPresent()) {
saxonConfiguration = readSaxonConfigurationFile(saxonConfigFile.get());
}

if (saxonConfiguration.isEmpty()) {
saxonConfiguration = Optional.of(net.sf.saxon.Configuration.newConfiguration());
}

if (saxonConfigFile.isEmpty()) {
LOG.warn("eXist could not find any Saxon configuration:\n" +
"No Saxon configuration file in configuration item " + SAXON_CONFIGURATION_FILE_PROPERTY + "\n" +
"No default eXist Saxon configuration file " + SAXON_DEFAULT_SAXON_CONFIG_FILE);
}

saxonConfiguration.ifPresent(SaxonConfiguration::reportLicensedFeatures);

return new SaxonConfiguration(saxonConfiguration.get());
}

static private Optional<net.sf.saxon.Configuration> readSaxonConfigurationFile(final Path saxonConfigFile) {
try {
return Optional.of(net.sf.saxon.Configuration.readConfiguration(
new StreamSource(Files.newInputStream(saxonConfigFile))));
} catch (final XPathException | IOException e) {
LOG.warn("Saxon could not read the configuration file: " + saxonConfigFile +
", with error: " + e.getMessage(), e);
} catch (RuntimeException runtimeException) {
if (runtimeException.getCause() instanceof ClassNotFoundException e) {
LOG.warn("Saxon could not honour the configuration file: " + saxonConfigFile +
", with class not found error: " + e.getMessage() + ". You may need to install the SaxonPE or SaxonEE JAR in eXist.");
} else {
throw runtimeException;
}
}
return Optional.empty();
}

static private void reportLicensedFeatures(final net.sf.saxon.Configuration configuration) {
configuration.displayLicenseMessage();

final var sb = new StringBuilder();
if (configuration.isLicensedFeature(net.sf.saxon.Configuration.LicenseFeature.SCHEMA_VALIDATION)) {
sb.append(" SCHEMA_VALIDATION");
}
if (configuration.isLicensedFeature(net.sf.saxon.Configuration.LicenseFeature.ENTERPRISE_XSLT)) {
sb.append(" ENTERPRISE_XSLT");
}
if (configuration.isLicensedFeature(net.sf.saxon.Configuration.LicenseFeature.ENTERPRISE_XQUERY)) {
sb.append(" ENTERPRISE_XQUERY");
}
if (configuration.isLicensedFeature(net.sf.saxon.Configuration.LicenseFeature.PROFESSIONAL_EDITION)) {
sb.append(" PROFESSIONAL_EDITION");
}
if (sb.isEmpty()) {
LOG.info("Saxon - no licensed features reported.");
} else {
LOG.info("Saxon - licensed features are" + sb + ".");
}
}

/**
* Resolve a possibly relative configuration file;
* if it is relative, it is relative to the current exist configuration (conf.xml)
*
* @param existConfiguration configuration to which this file may be relative
* @param filename the file we are trying to resolve
* @return the input file, if it is absolute. a file relative to conf.xml, if the input file is relative
*/
private static Path resolveConfigurationFile(final Configuration existConfiguration, final String filename) {
final var configurationFile = Paths.get(filename);
if (configurationFile.isAbsolute()) {
return configurationFile;
}

final var configPath = existConfiguration.getConfigFilePath();
return configPath.map(p -> p.getParent().resolve(configurationFile)).orElse(configurationFile);
}

private static Optional<Path> getSaxonConfigFile(final Configuration existConfiguration) {
if (existConfiguration.getProperty(SAXON_CONFIGURATION_FILE_PROPERTY) instanceof String saxonConfigurationFile) {
final var configurationFile = resolveConfigurationFile(existConfiguration, saxonConfigurationFile);
if (Files.isReadable(configurationFile)) {
return Optional.of(configurationFile);
} else {
LOG.warn("Configuration item " + SAXON_CONFIGURATION_FILE_PROPERTY + " : " + configurationFile +
" does not refer to a readable file. Continuing search for Saxon configuration.");
}
}

final var configurationFile = resolveConfigurationFile(existConfiguration, SAXON_DEFAULT_SAXON_CONFIG_FILE);
if (Files.isReadable(configurationFile)) {
return Optional.of(configurationFile);
}

return Optional.empty();
}
}
Loading

0 comments on commit 1086615

Please sign in to comment.