Java tutorial
/* * Copyright (C) 2010-2013, Martin Goellnitz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301, USA */ package jfs.sync.meta; import java.io.EOFException; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.NoSuchPaddingException; import jfs.sync.encrypted.EncryptedFileStorageAccess; import jfs.sync.encryption.FileInfo; import jfs.sync.util.SecurityUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public abstract class AbstractMetaStorageAccess extends EncryptedFileStorageAccess { private static final Log LOG = LogFactory.getLog(AbstractMetaStorageAccess.class); private static final DateFormat FORMATTER = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.MEDIUM, SimpleDateFormat.MEDIUM); private final Map<String, Map<String, FileInfo>> directoryCache = new HashMap<>(); public AbstractMetaStorageAccess(String cipher, boolean shortenPaths) { super(cipher, shortenPaths); } // AbstractMetaStorageAccess() protected Map<String, FileInfo> getMetaData(String rootPath, String relativePath) { if (directoryCache.containsKey(relativePath)) { return directoryCache.get(relativePath); } // if Map<String, FileInfo> result = new HashMap<>(); ObjectInputStream ois = null; try { InputStream inputStream = getInputStream(rootPath, getMetaDataPath(relativePath)); byte[] credentials = getCredentials(relativePath); Cipher cipher = SecurityUtils.getCipher(getCipherSpec(), Cipher.DECRYPT_MODE, credentials); inputStream = new CipherInputStream(inputStream, cipher); if (LOG.isDebugEnabled()) { LOG.debug("getMetaData() reading infos for " + relativePath); } // if ois = new ObjectInputStream(inputStream); Object o; while ((o = ois.readObject()) != null) { if (o instanceof FileInfo) { FileInfo fi = (FileInfo) o; if (fi.isDirectory()) { String date; synchronized (FORMATTER) { date = FORMATTER.format(new Date(fi.getModificationDate())); } if (LOG.isDebugEnabled()) { LOG.debug( "getMetaData() " + relativePath + getSeparator() + fi.getName() + ": " + date); } // if } // if result.put(fi.getName(), fi); } // if } // while ois.close(); } catch (FileNotFoundException | EOFException e) { // empty directory or - who cares? } catch (Exception e) { if (LOG.isInfoEnabled()) { LOG.info("getMetaData() possible issue while reading infos " + e, e); } // if } finally { try { if (ois != null) { ois.close(); } // if } catch (Exception ex) { // who cares? } // try/catch } // try/catch directoryCache.put(relativePath, result); return result; } // getMetaData() protected abstract OutputStream getOutputStream(String rootPath, String relativePath, boolean forPayload) throws IOException; @Override public OutputStream getOutputStream(String rootPath, String relativePath) throws IOException { return getOutputStream(rootPath, relativePath, true); } // getOutputStream() /** * flushing listing as meta data info for pathAndName[0] in rootPath * * @param rootPath * @param pathAndName * path and name for the file and path for which this update takes place * @param listing */ public void flushMetaData(String rootPath, String[] pathAndName, Map<String, FileInfo> listing) { try { if (LOG.isDebugEnabled()) { LOG.debug("flushMetaData() flushing " + listing); } // if OutputStream os = getOutputStream(rootPath, getMetaDataPath(pathAndName[0]), false); try { byte[] credentials = getCredentials(pathAndName[0]); Cipher cipher = SecurityUtils.getCipher(getCipherSpec(), Cipher.ENCRYPT_MODE, credentials); os = new CipherOutputStream(os, cipher); } catch (InvalidKeyException e) { LOG.error("flushMetaData()", e); } catch (NoSuchAlgorithmException e) { LOG.error("flushMetaData()", e); } catch (NoSuchPaddingException e) { LOG.error("flushMetaData()", e); } // try/catch ObjectOutputStream oos = new ObjectOutputStream(os); for (FileInfo info : listing.values()) { if (LOG.isDebugEnabled()) { LOG.debug("flushMetaData() writing " + info.getName()); } // if oos.writeObject(info); } // for oos.flush(); os.close(); if (LOG.isDebugEnabled()) { Map<String, FileInfo> backtest = getMetaData(rootPath, pathAndName[0]); for (FileInfo info : backtest.values()) { LOG.debug("flushMetaData() reading " + info.getName()); } // for } // if } catch (IOException ioe) { LOG.error("flushMetaData() error writing meta data ", ioe); } // try/catch } // flushMetaData() public Map<String, FileInfo> getParentListing(String rootPath, String[] pathAndName) { Map<String, FileInfo> listing = getMetaData(rootPath, pathAndName[0]); if (LOG.isDebugEnabled()) { LOG.debug("getParentListing(" + pathAndName[0] + ") " + listing); } // if return listing; } // getParentListing() @Override public String[] list(String rootPath, String relativePath) { Map<String, FileInfo> listing = getMetaData(rootPath, relativePath); String[] result = new String[listing.size()]; int i = 0; for (String name : listing.keySet()) { result[i++] = name; } // for return result; } // list() @Override public void flush(String rootPath, FileInfo info) { String[] pathAndName = new String[2]; pathAndName[0] = info.getPath(); pathAndName[1] = info.getName(); Map<String, FileInfo> listing = getParentListing(rootPath, pathAndName); if (listing.containsKey(info.getName())) { listing.remove(info.getName()); } // if listing.put(info.getName(), info); if (LOG.isInfoEnabled()) { LOG.info("flush() flushing " + pathAndName[0] + "/" + pathAndName[1]); } // if flushMetaData(rootPath, pathAndName, listing); } // flush() } // AbstractMetaStorageAccess