Java tutorial
/* * DSS - Digital Signature Services * * Copyright (C) 2011 European Commission, Directorate-General Internal Market and Services (DG MARKT), B-1049 Bruxelles/Brussel * * Developed by: 2011 ARHS Developments S.A. (rue Nicolas Bov 2B, L-1253 Luxembourg) http://www.arhs-developments.com * * This file is part of the "DSS - Digital Signature Services" project. * * "DSS - Digital Signature Services" 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. * * DSS 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 * "DSS - Digital Signature Services". If not, see <http://www.gnu.org/licenses/>. */ package eu.europa.ec.markt.dss.validation102853.https; import java.io.ByteArrayInputStream; import java.io.File; import java.net.URI; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.InputStreamEntity; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.ResourceLoader; import eu.europa.ec.markt.dss.exception.DSSCannotFetchDataException; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.validation102853.loader.Protocol; /** * This class provides some caching features to handle the resources. The default cache folder is set to {@code java.io.tmpdir}. The urls of the resources is transformed to the * file name by replacing the special characters by {@code _} */ public class FileCacheDataLoader extends CommonsDataLoader { private static final Logger LOG = LoggerFactory.getLogger(FileCacheDataLoader.class); private File fileCacheDirectory = new File(System.getProperty("java.io.tmpdir")); private ResourceLoader resourceLoader = new ResourceLoader(); private List<String> toBeLoaded; private List<String> toIgnored; /** * This method allows to set the file cache directory. If the cache folder does not exists then it's created. * * @param fileCacheDirectory {@code File} pointing the cache folder to be used. */ public void setFileCacheDirectory(final File fileCacheDirectory) { this.fileCacheDirectory = fileCacheDirectory; this.fileCacheDirectory.mkdirs(); } public void setResourceLoader(final ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } /** * This methods allows to indicate if the resource must be obtained. If this method has been invoked then only the provided URL will be processed. * * @param url to be processed */ public void addToBeLoaded(final String url) { if (toBeLoaded == null) { toBeLoaded = new ArrayList<String>(); } if (DSSUtils.isNotBlank(url)) { toBeLoaded.add(url); } } /** * This methods allows to indicate which resources must be ignored. It is useful in a test environment where some of fake sources a not available. It prevents to wait for the * timeout. * * @param urlString to be ignored. It can be the original URL or the cache file name */ public void addToBeIgnored(final String urlString) { if (toIgnored == null) { toIgnored = new ArrayList<String>(); } if (DSSUtils.isNotBlank(urlString)) { final String normalizedFileName = ResourceLoader.getNormalizedFileName(urlString); toIgnored.add(normalizedFileName); } } @Override public byte[] get(final String urlString) throws DSSCannotFetchDataException { if (toBeLoaded != null) { if (!toBeLoaded.contains(urlString)) { return null; } } final String fileName = ResourceLoader.getNormalizedFileName(urlString); final File file = getCacheFile(fileName); if (file.exists()) { LOG.debug("Cached file was used"); final byte[] bytes = DSSUtils.toByteArray(file); return bytes; } else { LOG.debug("There is no cached file!"); } final byte[] bytes; if (!isNetworkProtocol(urlString)) { final String resourcePath = resourceLoader.getAbsoluteResourceFolder(urlString.trim()); final File fileResource = new File(resourcePath); bytes = DSSUtils.toByteArray(fileResource); } else { bytes = super.get(urlString); } if (bytes != null && bytes.length != 0) { final File out = getCacheFile(fileName); DSSUtils.saveToFile(bytes, out); } return bytes; } protected boolean isNetworkProtocol(final String urlString) { final String normalizedUrl = urlString.trim().toLowerCase(); return Protocol.isHttpUrl(normalizedUrl) || Protocol.isLdapUrl(normalizedUrl) || Protocol.isFtpUrl(normalizedUrl); } private File getCacheFile(final String fileName) { final String trimmedFileName = fileName.trim(); if (toIgnored != null && toIgnored.contains(trimmedFileName)) { throw new DSSException("Part of urls to ignore."); } LOG.debug("Cached file: " + fileCacheDirectory + "/" + trimmedFileName); final File file = new File(fileCacheDirectory, trimmedFileName); return file; } /** * Allows to load the file for a given file name from the cache folder. * * @return the content of the file or {@code null} if the file does not exist */ public byte[] loadFileFromCache(final String urlString) { final String fileName = ResourceLoader.getNormalizedFileName(urlString); final File file = getCacheFile(fileName); if (file.exists()) { final byte[] bytes = DSSUtils.toByteArray(file); return bytes; } return null; } /** * Allows to add a given array of {@code byte} as a cache file representing by the {@code urlString}. * * @param urlString the URL to add to the cache * @param bytes the content of the cache file */ public void saveBytesInCache(final String urlString, final byte[] bytes) { final String fileName = ResourceLoader.getNormalizedFileName(urlString); final File out = getCacheFile(fileName); DSSUtils.saveToFile(bytes, out); } @Override public byte[] post(final String urlString, final byte[] content) throws DSSException { final String fileName = ResourceLoader.getNormalizedFileName(urlString); // The length for the InputStreamEntity is needed, because some receivers (on the other side) need this // information. // To determine the length, we cannot read the content-stream up to the end and re-use it afterwards. // This is because, it may not be possible to reset the stream (= go to position 0). // So, the solution is to cache temporarily the complete content data (as we do not expect much here) in a // byte-array. final byte[] digest = DSSUtils.digest(DigestAlgorithm.MD5, content); final String digestHexEncoded = DSSUtils.toHex(digest); final String cacheFileName = fileName + "." + digestHexEncoded; final File file = getCacheFile(cacheFileName); if (file.exists()) { LOG.debug("Cached file was used"); final byte[] byteArray = DSSUtils.toByteArray(file); return byteArray; } else { LOG.debug("There is no cached file!"); } final byte[] returnedBytes; if (!isNetworkProtocol(urlString)) { final String resourcePath = resourceLoader.getAbsoluteResourceFolder(urlString.trim()); final File fileResource = new File(resourcePath); returnedBytes = DSSUtils.toByteArray(fileResource); return returnedBytes; } HttpPost httpRequest = null; HttpResponse httpResponse = null; try { final URI uri = URI.create(urlString.trim()); httpRequest = new HttpPost(uri); final ByteArrayInputStream bis = new ByteArrayInputStream(content); final HttpEntity requestEntity = new InputStreamEntity(bis, content.length); httpRequest.setEntity(requestEntity); if (contentType != null) { httpRequest.setHeader(CONTENT_TYPE, contentType); } httpResponse = super.getHttpResponse(httpRequest, urlString); returnedBytes = readHttpResponse(urlString, httpResponse); if (returnedBytes.length != 0) { final File cacheFile = getCacheFile(cacheFileName); DSSUtils.saveToFile(returnedBytes, cacheFile); } } finally { if (httpRequest != null) { httpRequest.releaseConnection(); } if (httpResponse != null) { EntityUtils.consumeQuietly(httpResponse.getEntity()); } } return returnedBytes; } }