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.model.Sequence;
025    import org.datanucleus.store.connection.ManagedConnection;
026    import org.datanucleus.store.valuegenerator.AbstractDatastoreGenerator;
027    import org.datanucleus.store.valuegenerator.ValueGenerationBlock;
028    import org.datanucleus.store.valuegenerator.ValueGenerator;
029    
030    /**
031     * {@link ValueGenerator} implementation generating values by incrementing a counter.
032     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
033     */
034    public class Cumulus4jIncrementGenerator extends AbstractDatastoreGenerator
035    {
036            private String sequenceName;
037    
038            /**
039             * Create an instance. This is called by DataNucleus.
040             * @param name symbolic name for the generator.
041             * @param props Properties controlling the behaviour of the generator.
042             */
043            public Cumulus4jIncrementGenerator(String name, Properties props) {
044                    super(name, props);
045                    allocationSize = 5;
046    
047                    // TODO Check these names and what we want to use for Cumulus4j (classname or fieldname)
048                    if (properties.getProperty("sequence-name") != null) {
049                            // Specified sequence-name so use that
050                            sequenceName = properties.getProperty("sequence-name");
051                    }
052                    else if (properties.getProperty("field-name") != null) {
053                            // Use field name as the sequence name so we have one sequence per field on the class
054                            sequenceName = properties.getProperty("field-name");
055                    }
056                    else {
057                            // Use actual class name as the sequence name so we have one sequence per class
058                            sequenceName = properties.getProperty("class-name");
059                    }
060            }
061    
062            @Override
063            protected ValueGenerationBlock reserveBlock(long size) {
064                    if (size > Integer.MAX_VALUE)
065                            throw new IllegalStateException("Cannot reserve a block of more than " + Integer.MAX_VALUE + " values!");
066    
067                    Long[] values = new Long[(int)size];
068                    ManagedConnection mconn = connectionProvider.retrieveConnection();
069                    try {
070                            PersistenceManagerConnection pmConn = (PersistenceManagerConnection)mconn.getConnection();
071                            PersistenceManager pm = pmConn.getDataPM();
072                            pm.currentTransaction().setSerializeRead(true);
073                            try {
074                                    Sequence sequence = Sequence.createSequence(pm, sequenceName);
075                                    long nextValue = sequence.getNextValue();
076                                    for (int idx = 0; idx < values.length; ++idx) {
077                                            values[idx] = nextValue++;
078                                    }
079                                    sequence.setNextValue(nextValue);
080                            } finally {
081                                    pm.currentTransaction().setSerializeRead(false);
082                            }
083                    } finally {
084                            connectionProvider.releaseConnection();
085                    }
086                    return new ValueGenerationBlock(values);
087            }
088    }