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 }