/* * Copyright (C) 2012 The Android Open Source Project * * 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.motorolamobility.studio.android.certmanager.core; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import com.motorola.studio.android.common.log.StudioLogger; import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView; /** * Saves the state of the {@link KeystoreManagerView} with: * - the keystores mapped * - the last backup date from a keystore */ class SaveStateManager { private static final String FILE_COMMENT = "-- Signing and keys view persistence --"; private static final String STATE_FILENAME = "state.properties"; private final File persistenceFile = new File(System.getProperty("user.home") + File.separator + "." + CertificateManagerActivator.PLUGIN_ID, STATE_FILENAME); private static final String KEYSTORE_TYPE = "keystore_type="; private static final String BACKUP_DATE = "backup_date="; protected class ViewStateEntry { private final File keystoreFile; private String keystoreType; private Date backupDate; public ViewStateEntry(File keystoreFile) { this.keystoreFile = keystoreFile; } public ViewStateEntry(File keystoreFile, String keystoreType) { this.keystoreFile = keystoreFile; this.keystoreType = keystoreType; } /** * @return the backupDate */ public Date getBackupDate() { return backupDate; } /** * @param backupDate the backupDate to set */ public void setBackupDate(Date backupDate) { this.backupDate = backupDate; } /** * @return the keystoreType */ public String getKeystoreType() { return keystoreType; } /** * @param keystoreType the keystoreType to set */ public void setKeystoreType(String keystoreType) { this.keystoreType = keystoreType; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "ViewStateEntry [keystoreFile=" + keystoreFile + ", keystoreType=" + keystoreType + ", backupDate=" + backupDate + "]"; } /** * @return the keystoreFile */ protected File getKeystoreFile() { return keystoreFile; } } private static SaveStateManager _instance; /** * This class is a singleton. * @return The unique instance of this class. * */ public synchronized static SaveStateManager getInstance() throws IOException { if (_instance == null) { _instance = new SaveStateManager(); } return _instance; } private SaveStateManager() throws IOException { //create folder if it does not exist if (!persistenceFile.getParentFile().exists()) { persistenceFile.getParentFile().mkdirs(); } if (!persistenceFile.exists()) { //init file persistenceFile.createNewFile(); store(new Properties()); } } private String write(ViewStateEntry entry) { StringBuffer buffer = new StringBuffer(); if (entry.getKeystoreType() != null) { buffer.append(KEYSTORE_TYPE + entry.getKeystoreType() + File.pathSeparator); } if (entry.getBackupDate() != null) { buffer.append(BACKUP_DATE + entry.getBackupDate().getTime()); } return buffer.toString(); } /** * List all mapped keystores. * @throws IOException If there are problems loading the persistence file. */ public Set<File> getMappedKeystores() throws IOException { Set<File> mappedKeystores = new HashSet<File>(); Properties properties = load(); Enumeration<Object> enumeration = properties.keys(); while (enumeration.hasMoreElements()) { Object k = enumeration.nextElement(); if (k instanceof String) { String key = (String) k; File keystoreFile = new File(key); mappedKeystores.add(keystoreFile); } } return mappedKeystores; } /** * Get a representation of the entry saved in the persistence. * @param keystoreFile The file that will have its state retrieved. * @return * @throws IOException If there are problems loading the persistence file. */ public ViewStateEntry getEntry(File keystoreFile) throws IOException { Properties properties = load(); Object v = properties.get(keystoreFile.getAbsolutePath()); ViewStateEntry entry = null; if (v instanceof String) { String value = (String) v; StringTokenizer stringTokenizer = new StringTokenizer(value, File.pathSeparator); entry = new ViewStateEntry(keystoreFile); while (stringTokenizer.hasMoreTokens()) { String token = stringTokenizer.nextToken(); if (token.contains(KEYSTORE_TYPE)) { token = token.substring(KEYSTORE_TYPE.length()); entry.setKeystoreType(token); } else if (token.contains(BACKUP_DATE)) { token = token.substring(BACKUP_DATE.length()); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(Long.parseLong(token)); Date date = calendar.getTime(); entry.setBackupDate(date); } } } return entry; } /** * Check if a keystore is mapped on the persistence mechanism. * @param keystoreFile The keystore to be checked. * @return true if keystore mapped, false otherwise * @throws IOException If there are problems loading the persistence file. */ public boolean isKeystoreMapped(File keystoreFile) throws IOException { Properties properties = load(); return properties.containsKey(keystoreFile.getAbsolutePath()); } /** * Adds (maps) a keystore. * @param keystoreFile The keystore to be added to the persistence mechanism. * @param keystoreType The type of the keystore. * @throws IOException If there are problems loading the persistence file. */ public void addEntry(File keystoreFile, String keystoreType) throws IOException { ViewStateEntry stateEntry = new ViewStateEntry(keystoreFile, keystoreType); addEntry(keystoreFile, stateEntry); } private void addEntry(File keystoreFile, ViewStateEntry stateEntry) throws IOException { Properties prop = load(); prop.setProperty(keystoreFile.getAbsolutePath(), write(stateEntry)); store(prop); } /** * Removes a keystore from the persistence mechanism. * @param keystoreFile * @throws IOException */ public void removeEntry(File keystoreFile) throws IOException { Properties properties = load(); properties.remove(keystoreFile.getAbsolutePath()); store(properties); } /** * Sets backup date from a keystore * @param keystoreFile The keystore file. * @param backupDate The date of the backup. * @throws IOException If there are problems loading the persistence file. */ public void setBackupDate(File keystoreFile, Date backupDate) throws IOException { ViewStateEntry entry = getEntry(keystoreFile); entry.setBackupDate(backupDate); addEntry(keystoreFile, entry); } private Properties load() throws IOException { FileInputStream in = null; Properties props = new Properties(); try { in = new FileInputStream(persistenceFile); props.loadFromXML(in); } finally { if (in != null) { in.close(); } } return props; } private void store(Properties prop) throws IOException { FileOutputStream out = null; try { out = new FileOutputStream(persistenceFile); prop.storeToXML(out, FILE_COMMENT); } finally { if (out != null) { try { out.close(); } catch (IOException e) { StudioLogger.error("Could not close stream while saving properties. " + e.getMessage()); } } } } }