001 /* 002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org 003 * Copyright (C) 2011 NightLabs Consulting GmbH 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 package org.cumulus4j.store; 019 020 import java.util.Properties; 021 022 import javax.jdo.PersistenceManager; 023 024 import org.cumulus4j.store.Cumulus4jConnectionFactory.Cumulus4jManagedConnection; 025 import org.cumulus4j.store.crypto.CryptoContext; 026 import org.cumulus4j.store.model.Sequence2; 027 import org.cumulus4j.store.model.Sequence2DAO; 028 import org.datanucleus.store.ExecutionContext; 029 import org.datanucleus.store.valuegenerator.AbstractDatastoreGenerator; 030 import org.datanucleus.store.valuegenerator.ValueGenerationBlock; 031 import org.datanucleus.store.valuegenerator.ValueGenerator; 032 033 /** 034 * {@link ValueGenerator} implementation generating values by incrementing a counter. 035 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 036 */ 037 public class Cumulus4jIncrementGenerator extends AbstractDatastoreGenerator 038 { 039 private String sequenceName; 040 041 /** 042 * Create an instance. This is called by DataNucleus. 043 * @param name symbolic name for the generator. 044 * @param props Properties controlling the behaviour of the generator. 045 */ 046 public Cumulus4jIncrementGenerator(String name, Properties props) { 047 super(name, props); 048 allocationSize = 5; 049 050 // TODO Check these names and what we want to use for Cumulus4j (classname or fieldname) 051 if (properties.getProperty("sequence-name") != null) { 052 // Specified sequence-name so use that 053 sequenceName = properties.getProperty("sequence-name"); 054 } 055 else if (properties.getProperty("field-name") != null) { 056 // Use field name as the sequence name so we have one sequence per field on the class 057 sequenceName = properties.getProperty("field-name"); 058 } 059 else { 060 // Use actual class name as the sequence name so we have one sequence per class 061 sequenceName = properties.getProperty("class-name"); 062 } 063 } 064 065 @Override 066 protected ValueGenerationBlock reserveBlock(long size) { 067 if (size > Integer.MAX_VALUE) 068 throw new IllegalStateException("Cannot reserve a block of more than " + Integer.MAX_VALUE + " values!"); 069 070 Long[] values = new Long[(int)size]; 071 Cumulus4jManagedConnection mconn = (Cumulus4jManagedConnection) connectionProvider.retrieveConnection(); 072 try { 073 PersistenceManagerConnection pmConn = (PersistenceManagerConnection)mconn.getConnection(); 074 PersistenceManager pm = pmConn.getDataPM(); 075 Cumulus4jStoreManager storeManager = (Cumulus4jStoreManager) storeMgr; 076 077 CryptoContext cryptoContext = new CryptoContext( 078 storeManager.getEncryptionCoordinateSetManager(), 079 storeManager.getKeyStoreRefManager(), 080 (ExecutionContext) mconn.getPoolKey(), // TODO find a better way! That this is the ExecutionContext is nowhere documented, but it works and unfortunately it is the only way to obtain it I found :-( 081 pmConn 082 ); 083 storeManager.getDatastoreVersionManager().applyOnce(cryptoContext); 084 085 pm.currentTransaction().setSerializeRead(true); 086 try { 087 Sequence2 sequence = new Sequence2DAO(pm, cryptoContext.getKeyStoreRefID()).createSequence2(sequenceName); 088 long nextValue = sequence.getNextValue(); 089 for (int idx = 0; idx < values.length; ++idx) { 090 values[idx] = nextValue++; 091 } 092 sequence.setNextValue(nextValue); 093 } finally { 094 pm.currentTransaction().setSerializeRead(false); 095 } 096 } finally { 097 connectionProvider.releaseConnection(); 098 } 099 return new ValueGenerationBlock(values); 100 } 101 }