/*
* Copyright 2013 The Http Server & Proxy
*
* The Http Server & Proxy Project 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 com.sohail.alam.http.common.utils;
import com.sohail.alam.http.common.php.PhpProcessor;
import com.sohail.alam.http.common.php.PhpProcessorCallback;
import com.sohail.alam.http.common.smartcache.SmartCache;
import com.sohail.alam.http.common.smartcache.SmartCachePojo;
import com.sohail.alam.http.server.ServerProperties;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import static com.sohail.alam.http.common.LoggerManager.LOGGER;
import static com.sohail.alam.http.server.ServerProperties.PROP;
/**
* User: Sohail Alam
* Version: 1.0.0
* Date: 21/9/13
* Time: 8:37 PM
*/
public class LocalFileFetcher {
public static final LocalFileFetcher FETCHER = new LocalFileFetcher();
/**
* Instantiates a new Local file fetcher.
*/
private LocalFileFetcher() {
LOGGER.trace("LocalFileFetcher Constructor Initialized");
}
/**
* Parse file type.
*
* @param pathInfo the path info
*
* @return the string
*/
private String parseFileType(String pathInfo) {
String fileName = pathInfo.substring(pathInfo.lastIndexOf("/") + 1);
return fileName.substring(fileName.lastIndexOf("."));
}
/**
* Normalize a given relative path String to get the actual path String
*
* @param path the path
*
* @return the normalized path
*/
public String normalizePath(String path) {
String normalizedPath = new String();
// Make Sure Path Starts with a slash (/)
if (!path.startsWith("/")) {
path = "/" + path;
}
// If path ends with a "/" then append the default page to it (Eg. index.html)
if (path.endsWith("/")) {
path = path + PROP.DEFAULT_INDEX_PAGE;
}
// ./www/somePath
if (path.startsWith("/" + ServerProperties.PROP.WEBAPP_PATH)) {
normalizedPath = "." + path;
} else {
normalizedPath = ServerProperties.PROP.WEBAPP_PATH + path;
}
LOGGER.debug("Normalizing Path '{}' to '{}'", path, normalizedPath);
return normalizedPath;
}
/**
* Process php file.
*
* @param phpFilePath the php file path
* @param callback the callback
*/
private <T extends LocalFileFetcherCallback> void processPhpFile(final String phpFilePath, final T callback) {
PhpProcessor.processPhp(phpFilePath, new PhpProcessorCallback() {
@Override
public void success(String fileName, byte[] data, int dataLength) {
LOGGER.debug("Successfully processed PHP File '{}' - {} bytes", fileName, dataLength);
callback.fetchSuccess(phpFilePath, data, MediaType.getType(".html"), dataLength);
}
@Override
public void failure(String fileName, byte[] data, int dataLength) {
LOGGER.debug("Failed to processed PHP File '{}' - {} bytes", fileName, dataLength);
callback.fetchSuccess(phpFilePath, data, MediaType.getType(".html"), dataLength);
}
@Override
public void fileNotFound(String fileName, Throwable cause) {
LOGGER.debug("File Not Found: {}", cause.getMessage());
callback.fileNotFound(fileName, cause);
}
@Override
public void exceptionCaught(String fileName, Throwable cause) {
LOGGER.debug("Exception Caught while processing PHP File '{}': ", fileName, cause.getMessage());
callback.exceptionCaught(phpFilePath, cause);
}
});
}
/**
* Get bytes of the file.
*
* @param path the relative path of the file, which will be normalized automatically
* @param callback the callback
*
* @return the byte[] containing the file data
*/
public <T extends LocalFileFetcherCallback> void fetch(String path, T callback) {
final byte[] fileBytes;
final File file = new File(this.normalizePath(path));
FileInputStream is = null;
SmartCachePojo pojo;
if ((pojo = SmartCache.cache().get(file.getAbsolutePath())) != null) {
LOGGER.debug("Fetched file from Cache => {}", file.getAbsoluteFile());
callback.fetchSuccess(path, pojo.fileData, pojo.mediaType, pojo.fileSize);
return;
}
try {
// If the file referred is a PHP File then
// parse using PHP Processor, if PHP Processing is enabled
// FileNotFound is taken care of here instead of PhpProcessor
if (PROP.ENABLE_PHP && file.getName().endsWith(".php")) {
processPhpFile(file.getAbsolutePath(), callback);
} else {
String mediaType = MediaType.getType(parseFileType(file.getName()));
is = new FileInputStream(file);
fileBytes = new byte[is.available()];
int length = is.read(fileBytes);
LOGGER.debug("File '{}' Fetched Successfully - {} bytes", file.getAbsoluteFile(), length);
pojo = new SmartCachePojo(file, fileBytes, length, mediaType);
SmartCache.cache().put(file.getAbsolutePath(), pojo);
callback.fetchSuccess(path, fileBytes, mediaType, length);
}
} catch (FileNotFoundException e) {
LOGGER.debug("Exception Caught: {}", e.getMessage());
callback.fileNotFound(path, e);
} catch (IOException e) {
LOGGER.debug("Exception Caught: {}", e.getMessage());
callback.exceptionCaught(path, e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ignored) {
LOGGER.debug("IO Exception Caught while closing Input Stream in finally, Nothing can be done here");
}
}
}
}
}