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