/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.jena.fuseki.server; import static java.lang.String.format ; import java.io.IOException ; import java.nio.file.DirectoryStream ; import java.nio.file.Files ; import java.nio.file.Path ; import java.nio.file.Paths ; import java.util.ArrayList ; import java.util.List ; import org.apache.jena.atlas.lib.InternalErrorException ; import org.apache.jena.fuseki.servlets.HttpAction ; import org.apache.jena.fuseki.servlets.ServletOps ; /** * Separate initialization for FUSEKI_HOME and FUSEKI_BASE so that * Fusekilogging can use these values. * This code must not touch Jena. * * @see FusekiServer */ public class FusekiEnv { // Initialization logging happens via stdout/stderr directly. // Fuseki logging is not initialized to avoid going in circles. private static final boolean LogInit = false ; /** Unused */ // public static final String DFT_FUSEKI_HOME = isWindows // ? /*What's correct here?*/ "/usr/share/fuseki" // : "/usr/share/fuseki" ; static final boolean isWindows = determineIfWindows() ; static final String DFT_FUSEKI_BASE = isWindows ? /* What's correct here? */"/etc/fuseki" : "/etc/fuseki" ; /** Initialization mode, depending on the way Fuseki is started: <ul> <li>{@code WAR} - Running as a WAR file.</li> <li>{@code EMBEDDED}</li> <li>{@code STANDALONE} - Running as the standalone server in Jetty</li> <li>{@code TEST} - Running inside maven/JUnit and as the standalone server</li> <li>{@code UNSET} - Initial state.</li> </ul> <p> If at server initialization, the MODE is UNSET, then assume WAR setup. A WAR file does not have the opportunity to set the mode. <p> TEST: (better to set FUSEKI_HOME, FUSEKI_BASE from the test environment</li> */ public enum INIT { // Default values of FUSEKI_HOME, and FUSEKI_BASE. WAR (null, "/etc/fuseki") , EMBEDDED (null, null) , STANDALONE (".", "run") , TEST ("src/main/webapp", "target/run") , UNSET (null, null) ; final String dftFusekiHome ; final String dftFusekiBase ; INIT(String home, String base) { this.dftFusekiHome = home ; this.dftFusekiBase = base ; } } public static INIT mode = INIT.UNSET ; /** Root of the Fuseki installation for fixed files. * This may be null (e.g. running inside a web application container) */ public static Path FUSEKI_HOME = null ; /** Root of the varying files in this deployment. Often $FUSEKI_HOME/run. * This is not null - it may be /etc/fuseki, which must be writable. */ public static Path FUSEKI_BASE = null ; // Copied from SystemTDB to avoid dependency. // This code must not touch Jena. private static boolean determineIfWindows() { String s = System.getProperty("os.name") ; if ( s == null ) return false ; return s.startsWith("Windows ") ; } public static final String ENV_runArea = "run" ; private static boolean initialized = false ; /** Initialize the server : standalone and WAR versions : not embedded */ public static synchronized void setEnvironment() { if ( initialized ) return ; resetEnvironment(); } /** Reset environment - use with care and bfore server start up */ public static synchronized void resetEnvironment() { initialized = true ; logInit("FusekiEnv:Start: ENV_FUSEKI_HOME = %s : ENV_FUSEKI_BASE = %s : MODE = %s", FUSEKI_HOME, FUSEKI_BASE, mode) ; if ( mode == null || mode == INIT.UNSET ) mode = INIT.WAR ; if ( FUSEKI_HOME == null ) { // Make absolute String x1 = getenv("FUSEKI_HOME") ; if ( x1 == null ) x1 = mode.dftFusekiHome ; if ( x1 != null ) FUSEKI_HOME = Paths.get(x1) ; } if ( FUSEKI_BASE == null ) { String x2 = getenv("FUSEKI_BASE") ; if ( x2 == null ) x2 = mode.dftFusekiBase ; if ( x2 != null ) FUSEKI_BASE = Paths.get(x2) ; else { if ( FUSEKI_HOME != null ) FUSEKI_BASE = FUSEKI_HOME.resolve(ENV_runArea) ; else { // This is bad - there should have been a default by now. logInitError("Can't find a setting for FUSEKI_BASE - guessing wildy") ; // Neither FUSEKI_HOME nor FUSEKI_BASE set. FUSEKI_BASE = Paths.get(DFT_FUSEKI_BASE) ; } } } if ( FUSEKI_HOME != null ) FUSEKI_HOME = FUSEKI_HOME.toAbsolutePath() ; FUSEKI_BASE = FUSEKI_BASE.toAbsolutePath() ; logInit("FusekiEnv:Finish: ENV_FUSEKI_HOME = %s : ENV_FUSEKI_BASE = %s", FUSEKI_HOME, FUSEKI_BASE) ; } private static void logInit(String fmt, Object ... args) { if ( LogInit ) { System.out.printf(fmt, args) ; System.out.println() ; } } private static void logInitError(String fmt, Object ... args) { System.err.printf(fmt, args) ; System.err.println() ; } /** Get environment variable value (maybe in system properties) */ public static String getenv(String name) { String x = System.getenv(name) ; if ( x == null ) x = System.getProperty(name) ; return x ; } /** Dataset set name to configuration file name. */ public static String datasetNameToConfigurationFile(HttpAction action, String dsName) { List<String> existing = existingConfigurationFile(dsName) ; if ( ! existing.isEmpty() ) { if ( existing.size() > 1 ) { action.log.warn(format("[%d] Multiple existing configuration files for %s : %s", action.id, dsName, existing)); ServletOps.errorBadRequest("Multiple existing configuration files for "+dsName); return null ; } return existing.get(0) ; } return generateConfigurationFilename(dsName) ; } /** Choose a configuration file name - existign one or ".ttl" form if new */ public static String generateConfigurationFilename(String dsName) { String filename = dsName ; // Without "/" if ( filename.startsWith("/")) filename = filename.substring(1) ; filename = FusekiServer.dirConfiguration.resolve(filename).toString()+".ttl" ; return filename ; } /** Return the filenames of all matching files in the configuration directory */ public static List<String> existingConfigurationFile(String baseFilename) { try { List<String> paths = new ArrayList<>() ; try (DirectoryStream<Path> stream = Files.newDirectoryStream(FusekiServer.dirConfiguration, baseFilename+"*") ) { stream.forEach((p)-> paths.add(p.getFileName().toString())) ; } return paths ; } catch (IOException ex) { throw new InternalErrorException("Failed to read configuration directory "+FusekiServer.dirConfiguration) ; } } }