001 package org.cumulus4j.store; 002 003 import java.util.HashMap; 004 import java.util.Map; 005 006 import javax.jdo.FetchPlan; 007 import javax.jdo.PersistenceManager; 008 009 import org.cumulus4j.crypto.CryptoRegistry; 010 import org.cumulus4j.store.model.EncryptionCoordinateSet; 011 import org.cumulus4j.store.model.EncryptionCoordinateSetDAO; 012 013 /** 014 * <p> 015 * Manager for {@link EncryptionCoordinateSet} instances. 016 * </p><p> 017 * There exists one <code>EncryptionCoordinateSetManager</code> instance per {@link Cumulus4jStoreManager}. 018 * The <code>EncryptionCoordinateSet</code>s held by this manager are detached (with all properties) 019 * and thus kept across all transactions. 020 * </p> 021 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 022 */ 023 public class EncryptionCoordinateSetManager 024 { 025 private Map<Integer, EncryptionCoordinateSet> encryptionCoordinateSetID2EncryptionCoordinateSet = new HashMap<Integer, EncryptionCoordinateSet>(); 026 027 private Map<String, EncryptionCoordinateSet> encryptionCoordinateString2EncryptionCoordinateSet = new HashMap<String, EncryptionCoordinateSet>(); 028 029 private static String getEncryptionCoordinateString(String cipherTransformation, String macAlgorithm) 030 { 031 return cipherTransformation + "::" + macAlgorithm; 032 } 033 private static String getEncryptionCoordinateString(EncryptionCoordinateSet encryptionCoordinateSet) 034 { 035 return getEncryptionCoordinateString(encryptionCoordinateSet.getCipherTransformation(), encryptionCoordinateSet.getMACAlgorithm()); 036 } 037 038 /** 039 * Create an instance. 040 */ 041 public EncryptionCoordinateSetManager() { } 042 043 /** 044 * Get the {@link EncryptionCoordinateSet} identified by the given <code>encryptionCoordinateSetID</code>. 045 * If no such <code>EncryptionCoordinateSet</code> exists, <code>null</code> is returned. 046 * @param persistenceManagerConnection the connection to the underlying datastore(s). 047 * @param encryptionCoordinateSetID {@link EncryptionCoordinateSet#getEncryptionCoordinateSetID() identifier} of the 048 * <code>EncryptionCoordinateSet</code> to be retrieved. 049 * @return the {@link EncryptionCoordinateSet} identified by the given <code>encryptionCoordinateSetID</code> or <code>null</code>. 050 */ 051 public synchronized EncryptionCoordinateSet getEncryptionCoordinateSet(PersistenceManagerConnection persistenceManagerConnection, int encryptionCoordinateSetID) 052 { 053 EncryptionCoordinateSet encryptionCoordinateSet = encryptionCoordinateSetID2EncryptionCoordinateSet.get(encryptionCoordinateSetID); 054 if (encryptionCoordinateSet == null) { 055 PersistenceManager pm = persistenceManagerConnection.getDataPM(); 056 encryptionCoordinateSet = new EncryptionCoordinateSetDAO(pm).getEncryptionCoordinateSet(encryptionCoordinateSetID); 057 if (encryptionCoordinateSet != null) { 058 pm.getFetchPlan().setMaxFetchDepth(-1); 059 pm.getFetchPlan().setGroup(FetchPlan.ALL); 060 encryptionCoordinateSet = pm.detachCopy(encryptionCoordinateSet); 061 encryptionCoordinateSetID2EncryptionCoordinateSet.put( 062 encryptionCoordinateSet.getEncryptionCoordinateSetID(), encryptionCoordinateSet 063 ); 064 encryptionCoordinateString2EncryptionCoordinateSet.put( 065 getEncryptionCoordinateString(encryptionCoordinateSet), encryptionCoordinateSet 066 ); 067 } 068 } 069 return encryptionCoordinateSet; 070 } 071 072 /** 073 * <p> 074 * Get the {@link EncryptionCoordinateSet} identified by the given properties. 075 * </p><p> 076 * If it does not yet exist in the in-memory-cache, 077 * it is looked up in the datastore. If it is found there, it is detached, cached and returned. If it does not exist in the 078 * datastore either, it is - if <code>create == true</code> - created, persisted, detached, cached and returned; if 079 * <code>create == false</code>, <code>null</code> is returned instead. 080 * </p><p> 081 * The <code>EncryptionCoordinateSet</code> instances are only held in the 082 * {@link PersistenceManagerConnection#getDataPM() data-datastore} (not in the index-datastore). This might change in the future 083 * (in case replication becomes necessary). 084 * </p> 085 * 086 * @param create whether to create a new instance, if it does not yet exist. If <code>true</code>, a new instance 087 * will be created, persisted, detached, cached and returned, if it does not yet exist. If <code>false</code>, <code>null</code> 088 * will be returned instead. 089 * @param persistenceManagerConnection the connection to the underlying datastore(s). 090 * @param cipherTransformation the transformation (as passed to {@link CryptoRegistry#createCipher(String)}) used to encrypt and 091 * decrypt the persistent data (or index). 092 * @param macAlgorithm the <a target="_blank" href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a> algorithm (as passed to {@link CryptoRegistry#createMACCalculator(String, boolean)}) 093 * used to verify peristent records for integrity. Might be {@link EncryptionCoordinateSet#MAC_ALGORITHM_NONE} to deactivate 094 * the MAC calculation. 095 * @return the <code>EncryptionCoordinateSet</code> (detached) matching the given properties. If <code>create == true</code>, this 096 * is never <code>null</code>. If <code>create == false</code> and there does not yet exist an appropriate 097 * <code>EncryptionCoordinateSet</code>, this is <code>null</code>. 098 */ 099 protected EncryptionCoordinateSet _createOrGetEncryptionCoordinateSet(boolean create, PersistenceManagerConnection persistenceManagerConnection, String cipherTransformation, String macAlgorithm) 100 { 101 String encryptionCoordinateString = getEncryptionCoordinateString(cipherTransformation, macAlgorithm); 102 EncryptionCoordinateSet encryptionCoordinateSet = encryptionCoordinateString2EncryptionCoordinateSet.get(encryptionCoordinateString); 103 if (encryptionCoordinateSet == null) { 104 PersistenceManager pm = persistenceManagerConnection.getDataPM(); 105 106 if (create) 107 encryptionCoordinateSet = new EncryptionCoordinateSetDAO(pm).createEncryptionCoordinateSet(cipherTransformation, macAlgorithm); 108 else 109 encryptionCoordinateSet = new EncryptionCoordinateSetDAO(pm).getEncryptionCoordinateSet(cipherTransformation, macAlgorithm); 110 111 if (encryptionCoordinateSet != null) { 112 pm.getFetchPlan().setMaxFetchDepth(-1); 113 pm.getFetchPlan().setGroup(FetchPlan.ALL); 114 encryptionCoordinateSet = pm.detachCopy(encryptionCoordinateSet); 115 encryptionCoordinateSetID2EncryptionCoordinateSet.put( 116 encryptionCoordinateSet.getEncryptionCoordinateSetID(), encryptionCoordinateSet 117 ); 118 encryptionCoordinateString2EncryptionCoordinateSet.put( 119 getEncryptionCoordinateString(encryptionCoordinateSet), encryptionCoordinateSet 120 ); 121 } 122 } 123 return encryptionCoordinateSet; 124 } 125 126 /** 127 * <p> 128 * Get the {@link EncryptionCoordinateSet} identified by the given properties. 129 * </p><p> 130 * If there is no appropriate <code>EncryptionCoordinateSet</code> (neither in the in-memory-cache nor in the datastore), 131 * <code>null</code> is returned. 132 * </p><p> 133 * This method delegates to {@link #_createOrGetEncryptionCoordinateSet(boolean, PersistenceManagerConnection, String, String)} with 134 * <code>create == false</code>. 135 * </p> 136 * 137 * @param persistenceManagerConnection the connection to the underlying datastore(s). 138 * @param cipherTransformation the transformation (as passed to {@link CryptoRegistry#createCipher(String)}) used to encrypt and 139 * decrypt the persistent data (or index). 140 * @param macAlgorithm the <a target="_blank" href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a> algorithm (as passed to {@link CryptoRegistry#createMACCalculator(String, boolean)}) 141 * used to verify peristent records for integrity. Might be {@link EncryptionCoordinateSet#MAC_ALGORITHM_NONE} to deactivate 142 * the MAC calculation. 143 * @return the <code>EncryptionCoordinateSet</code> (detached) matching the given properties or <code>null</code>. 144 */ 145 public synchronized EncryptionCoordinateSet getEncryptionCoordinateSet(PersistenceManagerConnection persistenceManagerConnection, String cipherTransformation, String macAlgorithm) 146 { 147 return _createOrGetEncryptionCoordinateSet(false, persistenceManagerConnection, cipherTransformation, macAlgorithm); 148 } 149 150 /** 151 * <p> 152 * Get the {@link EncryptionCoordinateSet} identified by the given properties. 153 * </p><p> 154 * If there is no appropriate <code>EncryptionCoordinateSet</code> (neither in the in-memory-cache nor in the datastore), 155 * it is created and persisted. 156 * </p><p> 157 * This method delegates to {@link #_createOrGetEncryptionCoordinateSet(boolean, PersistenceManagerConnection, String, String)} with 158 * <code>create == true</code>. 159 * </p> 160 * 161 * @param persistenceManagerConnection the connection to the underlying datastore(s). 162 * @param cipherTransformation the transformation (as passed to {@link CryptoRegistry#createCipher(String)}) used to encrypt and 163 * decrypt the persistent data (or index). 164 * @param macAlgorithm the <a target="_blank" href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a> algorithm (as passed to {@link CryptoRegistry#createMACCalculator(String, boolean)}) 165 * used to verify peristent records for integrity. Might be {@link EncryptionCoordinateSet#MAC_ALGORITHM_NONE} to deactivate 166 * the MAC calculation. 167 * @return the <code>EncryptionCoordinateSet</code> (detached) matching the given properties; never <code>null</code>. 168 */ 169 public synchronized EncryptionCoordinateSet createEncryptionCoordinateSet(PersistenceManagerConnection persistenceManagerConnection, String cipherTransformation, String macAlgorithm) 170 { 171 return _createOrGetEncryptionCoordinateSet(true, persistenceManagerConnection, cipherTransformation, macAlgorithm); 172 } 173 }