/** * Copyright 2014 Microsoft Open Technologies Inc. * * Licensed 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.microsoftopentechnologies.intellij.helpers.aadauth; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.io.ByteStreams; import java.io.*; import java.net.HttpURLConnection; import java.net.URLConnection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutionException; public class FileCache { private String cacheBasePath; private Map<String, FileSource> fileSources; private static final String ETAG_FILE_NAME = "ad-interactive-auth_etag.txt"; LoadingCache<String, File> fileCache = CacheBuilder.newBuilder() .maximumSize(50) .build(new FileCacheLoader()); public FileCache(FileSource[] sources) { // default cache base path to temp folder cacheBasePath = System.getProperty("java.io.tmpdir"); // initialize file sources fileSources = new HashMap<String, FileSource>(sources.length); for(FileSource source : sources) { fileSources.put(source.getFileName(), source); } } public String getCacheBasePath() { return cacheBasePath; } public void setCacheBasePath(String cacheBasePath) { this.cacheBasePath = cacheBasePath; } public File getFile(String fileName) throws ExecutionException { if (!fileSources.containsKey(fileName)) { return null; } return fileCache.get(fileName); } private class FileCacheLoader extends CacheLoader<String, File> { @Override public File load(String key) throws Exception { FileSource source = fileSources.get(key); File file = new File(cacheBasePath, source.getFileName()); // load the current etag value if we already have a copy of the // jar cached locally File etagFile = new File(cacheBasePath, ETAG_FILE_NAME); String etag = null; if(etagFile.exists() && file.exists()) { FileInputStream is = new FileInputStream(etagFile); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); etag = reader.readLine(); reader.close(); } HttpURLConnection connection = (HttpURLConnection)source.getUrl().openConnection(); // if we have an etag cached then send that in the "If-None-Match" header if(etag != null) { connection.setRequestProperty("If-None-Match", etag); } int statusCode = connection.getResponseCode(); // if HTTP status is equal to 304 then our cached copy is still good to use if(statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) { return file; } // if HTTP status is not 200 then we bail if(statusCode != HttpURLConnection.HTTP_OK) { // TODO: Is IOException the right exception type to raise? throw new IOException("File cache: server URL returned HTTP status code " + Integer.toString(statusCode)); } // download and save the file file.createNewFile(); FileOutputStream output = new FileOutputStream(file); InputStream input = connection.getInputStream(); ByteStreams.copy(input, output); input.close(); output.close(); // save the etag to file String newEtag = connection.getHeaderField("ETag"); etagFile.createNewFile(); output = new FileOutputStream(etagFile); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output)); writer.write(newEtag); writer.close(); output.close(); return file; } } }