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 }