/** * 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 java.io.IOException ; import java.io.InputStream ; import java.nio.file.Path ; import java.nio.file.Paths ; import javax.servlet.ServletContext ; import javax.servlet.ServletContextEvent ; import javax.servlet.ServletContextListener ; import org.apache.jena.fuseki.Fuseki ; import org.apache.jena.util.FileUtils ; import org.apache.shiro.config.ConfigurationException ; import org.apache.shiro.io.ResourceUtils ; import org.apache.shiro.web.env.EnvironmentLoader ; import org.apache.shiro.web.env.ResourceBasedWebEnvironment ; import org.apache.shiro.web.env.WebEnvironment ; /** A place to perform Fuseki-specific initialization of Apache Shiro. * Runs after listener {@link FusekiServerEnvironmentInit} and before {@link FusekiServerListener}. * This means finding shiro.ini in multiple possible places, based on * different deployment setups. */ public class ShiroEnvironmentLoader extends EnvironmentLoader implements ServletContextListener { private ServletContext servletContext ; public ShiroEnvironmentLoader() {} @Override public void contextInitialized(ServletContextEvent sce) { FusekiServer.formatBaseArea() ; this.servletContext = sce.getServletContext() ; try { // Shiro. initEnvironment(servletContext); } catch (ConfigurationException ex) { Fuseki.configLog.error("Shiro initialization failed: "+ex.getMessage()); // Exit? throw ex ; } } @Override public void contextDestroyed(ServletContextEvent sce) { destroyEnvironment(sce.getServletContext()); } /** * Normal Shiro initialization only supports one location for an INI file. * * When given multiple multiple locations for the shiro.ini file, and * if a {@link ResourceBasedWebEnvironment}, check the list of configuration * locations, testing whether the name identified an existing resource. * For the first resource name found to exist, reset the {@link ResourceBasedWebEnvironment} * to name that resource alone so the normal Shiro initialization */ @Override protected void customizeEnvironment(WebEnvironment environment) { if ( environment instanceof ResourceBasedWebEnvironment ) { ResourceBasedWebEnvironment env = (ResourceBasedWebEnvironment)environment ; String[] locations = env.getConfigLocations() ; String loc = huntForShiroIni(locations) ; Fuseki.configLog.info("Shiro file: "+loc); if (loc != null ) locations = new String[] {loc} ; env.setConfigLocations(locations); } } private static final String FILE = "file" ; /** Look for a Shiro ini file, or return null */ private static String huntForShiroIni(String[] locations) { FusekiEnv.setEnvironment() ; Fuseki.init(); for ( String loc : locations ) { // If file:, look for that file. // If a relative name without scheme, look in FUSEKI_BASE, FUSEKI_HOME, webapp. String scheme = FileUtils.getScheme(loc) ; // Covers C:\\ as a "scheme name" if ( scheme != null ) { if ( scheme.equalsIgnoreCase(FILE)) { // Test file: for exists Path p = Paths.get(loc.substring(FILE.length()+1)) ; if ( ! p.toFile().exists() ) continue ; // Fall through. } // Can't test - try return loc ; } // No scheme . Path p = Paths.get(loc) ; String fn = resolve(FusekiEnv.FUSEKI_BASE, p) ; if ( fn != null ) return "file://"+fn ; fn = resolve(FusekiEnv.FUSEKI_HOME, p) ; if ( fn != null ) return "file://"+fn ; // Try in webapp. try ( InputStream is = ResourceUtils.getInputStreamForPath(loc); ) { boolean exists = (is != null ) ; return loc ; } catch (IOException e) { } } return null ; } /** Directory + name -> filename if it exists */ private static String resolve(Path dir, Path file) { Path p = dir.resolve(file) ; if ( p.toFile().exists() ) return p.normalize().toString() ; return null ; } // /** // * Test whether a name identified an existing resource // * @param resource A String in Shiro-resource name format (e.g. URL scheme names) // * @return True/false as to whether the resource can be found or not. // */ // // private boolean resourceExists(String resource) { // try { // // See IniWebEnvironment.convertPathToIni // if (!ResourceUtils.hasResourcePrefix(resource)) { // //Sort out "path" and open as a webapp resource. // resource = WebUtils.normalize(resource); // URL url = servletContext.getResource(resource) ; // return ( url == null ) ; // } else { // // Treat as a plain name. // InputStream is = ResourceUtils.getInputStreamForPath(resource); // boolean exists = (is != null ) ; // is.close() ; // return exists ; // } // } catch (IOException e) { return false ; } // } }