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.model; 019 020 import javax.jdo.annotations.Column; 021 import javax.jdo.annotations.IdentityType; 022 import javax.jdo.annotations.NullValue; 023 import javax.jdo.annotations.PersistenceCapable; 024 import javax.jdo.annotations.Persistent; 025 import javax.jdo.annotations.PrimaryKey; 026 027 import org.cumulus4j.store.Cumulus4jIncrementGenerator; 028 import org.cumulus4j.store.crypto.CryptoContext; 029 030 /** 031 * Persistent sequence entity used by {@link Cumulus4jIncrementGenerator}. 032 * <p> 033 * Objects are cached by DataNucleus via their primary key. Accessing an object via its OID therefore does not 034 * require any query, if the object is already cached. Therefore, this class encodes the 035 * {@link CryptoContext#getKeyStoreRefID() keyStoreRefID} and the <code>sequenceName</code> together in one 036 * single {@link #getSequenceID() sequenceID}, which is the (single-field) primary key for this class. 037 * <p> 038 * We do not use a composite primary key, because this is not supported by all underlying databases. The chosen 039 * strategy is thus the most portable and fastest. 040 * 041 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 042 * @since 1.1.0 043 */ 044 @PersistenceCapable(identityType=IdentityType.APPLICATION, detachable="true") 045 public class Sequence2 046 { 047 @PrimaryKey 048 @Persistent(nullValue=NullValue.EXCEPTION) 049 @Column(length=255) 050 private String sequenceID; 051 052 private long nextValue = 1; 053 054 /** 055 * Default constructor. Should never be used by actual code! It exists only to fulfill the JDO requirements. 056 */ 057 protected Sequence2() { } 058 059 protected static String createSequenceID(int keyStoreRefID, String sequenceName) { 060 return Integer.toString(keyStoreRefID) + '.' + sequenceName; 061 } 062 063 /** 064 * Constructor creating a <code>Sequence</code> with the given primary key. 065 * @param sequenceName the name of the sequence; must not be <code>null</code>. 066 */ 067 protected Sequence2(int keyStoreRefID, String sequenceName) 068 { 069 if (sequenceName == null) 070 throw new IllegalArgumentException("sequenceName == null"); 071 072 this.sequenceID = createSequenceID(keyStoreRefID, sequenceName); 073 } 074 075 public String getSequenceID() { 076 return sequenceID; 077 } 078 079 protected String[] splitSequenceID() { 080 int dotIndex = sequenceID.indexOf('.'); 081 if (dotIndex < 0) 082 throw new IllegalStateException(String.format("sequenceID \"%s\" does not contain a dot ('.')!", sequenceID)); 083 084 String[] result = new String[2]; 085 result[0] = sequenceID.substring(0, dotIndex); 086 result[1] = sequenceID.substring(dotIndex + 1); 087 return result; 088 } 089 090 public int getKeyStoreRefID() { 091 String keyStoreRefIDStr = splitSequenceID()[0]; 092 try { 093 int keyStoreRefID = Integer.parseInt(keyStoreRefIDStr); 094 return keyStoreRefID; 095 } catch (NumberFormatException x) { 096 throw new IllegalStateException( 097 String.format( 098 "First part of sequenceID \"%s\" is \"%s\", which is not a valid integer: %s", 099 sequenceID, keyStoreRefIDStr, x.toString() 100 ), 101 x 102 ); 103 } 104 } 105 106 /** 107 * Get the name of the sequence. 108 * @return the name of the sequence. 109 */ 110 public String getSequenceName() { 111 return splitSequenceID()[1]; 112 } 113 114 /** 115 * Get the next value (i.e. the first unused value) for this sequence. 116 * @return the next value (i.e. the first unused value) for this sequence. 117 */ 118 public long getNextValue() { 119 return nextValue; 120 } 121 122 /** 123 * Set the next value (i.e. the first unused value) for this sequence. 124 * @param nextValue the next value (i.e. the first unused value) for this sequence. 125 */ 126 public void setNextValue(long nextValue) { 127 this.nextValue = nextValue; 128 } 129 }