/* * 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.riot.system.stream; import java.io.File ; import java.io.IOException ; import java.io.InputStream ; import java.security.AccessControlException ; import org.apache.jena.atlas.io.IO ; import org.apache.jena.atlas.lib.IRILib ; import org.apache.jena.atlas.web.ContentType ; import org.apache.jena.atlas.web.TypedInputStream ; import org.apache.jena.riot.RDFLanguages ; import org.apache.jena.util.FileUtils ; import org.slf4j.Logger ; import org.slf4j.LoggerFactory ; /** Location files in the filing system. * A FileLocator can have a "current directory" - this is separate from any * location mapping (see @link{LocationMapping}) as it applies only to files. */ public class LocatorFile implements Locator { // Implementation note: // Java7: Path.resolve may provide an answer from the intricies of MS Windows static Logger log = LoggerFactory.getLogger(LocatorFile.class) ; private final String thisDir ; private final String thisDirLogStr ; /** Create a LocatorFile without a specific working directory. * Relative file names are relative to the working directory of the JVM. */ public LocatorFile() { this(null) ; } /** Create a LocatorFile that uses the argument as it's working directory. * <p> * The working directory should be a UNIX style file name, * (relative or absolute), not a URI. * <p> * For MS Window, if asked to {@link #open} a file name with a drive letter, * the code assumes it is not relative to the working directory * of this {@code LocatorFile}. */ public LocatorFile(String dir) { if ( dir != null ) { if ( dir.endsWith("/") || dir.endsWith(java.io.File.separator) ) dir = dir.substring(0,dir.length()-1) ; thisDirLogStr = " ["+dir+"]" ; } else thisDirLogStr = "" ; thisDir = dir ; } /** Processing the filename for file: or relative filename * and return a filename suitable for file operations. */ public String toFileName(String filenameIRI) { // Do not use directly : it will ignore the directory. //IRILib.filenameToIRI String scheme = FileUtils.getScheme(filenameIRI) ; String fn = filenameIRI ; // Windows : C:\\ is not a scheme name! if ( scheme != null ) { if ( scheme.length() == 1 ) { // Not perfect for MS Windows but if thisDir is set then // the main use case is resolving relative (no drive) // filenames against thisDir. Treat the presence of a // drive letter as making this a JVM relative filename. return fn ; } else if ( scheme.length() > 1 ) { if ( ! scheme.equalsIgnoreCase("file") ) // Not file: IRI return null ; fn = IRILib.IRIToFilename(filenameIRI) ; // fall through } } // fn is the file name to use. return absolute(fn) ; } /** Make a filename (no URI scheme, no windows drive) absolute if there is * a setting for directory name thisDir */ private String absolute(String fn) { if ( thisDir != null && ! fn.startsWith("/") && ! fn.startsWith(File.separator) ) fn = thisDir+File.separator+fn ; return fn ; } public String getThisDir() { return thisDir ; } public boolean hasCurrentDir() { return thisDir != null ; } public boolean exists(String fileIRI) { String fn = toFileName(fileIRI) ; if ( fn == null ) return false ; return exists$(fn) ; } private boolean exists$(String fn) { if ( fn.equals("-") ) return true ; return new File(fn).exists() ; } /** Open anything that looks a bit like a file name */ @Override public TypedInputStream open(String filenameIRI) { String fn = toFileName(filenameIRI) ; if ( fn == null ) return null ; try { if ( ! exists$(fn) ) { if ( StreamManager.logAllLookups && log.isTraceEnabled()) log.trace("Not found: "+filenameIRI+thisDirLogStr) ; return null ; } } catch (AccessControlException e) { log.warn("Security problem testing for file", e); return null; } try { InputStream in = IO.openFileEx(fn) ; if ( StreamManager.logAllLookups && log.isTraceEnabled() ) log.trace("Found: "+filenameIRI+thisDirLogStr) ; ContentType ct = RDFLanguages.guessContentType(filenameIRI) ; return new TypedInputStream(in, ct, filenameIRI) ; } catch (IOException ioEx) { // Includes FileNotFoundException // We already tested whether the file exists or not. log.warn("File unreadable (but exists): "+fn+" Exception: "+ioEx.getMessage()) ; return null ; } } @Override public String getName() { String tmp = "LocatorFile" ; if ( thisDir != null ) tmp = tmp+"("+thisDir+")" ; return tmp ; } @Override public int hashCode() { final int prime = 31 ; int result = 1 ; result = prime * result + ((thisDir == null) ? 0 : thisDir.hashCode()) ; result = prime * result + ((thisDirLogStr == null) ? 0 : thisDirLogStr.hashCode()) ; return result ; } @Override public boolean equals(Object obj) { if (this == obj) return true ; if (obj == null) return false ; if (getClass() != obj.getClass()) return false ; LocatorFile other = (LocatorFile)obj ; if (thisDir == null) { if (other.thisDir != null) return false ; } else if (!thisDir.equals(other.thisDir)) return false ; if (thisDirLogStr == null) { if (other.thisDirLogStr != null) return false ; } else if (!thisDirLogStr.equals(other.thisDirLogStr)) return false ; return true ; } }