libreccm-legacy/ccm-core/src/com/arsdigita/versioning/functions.java

213 lines
6.8 KiB
Java
Executable File

/*
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.versioning;
import com.arsdigita.db.Sequences;
import com.arsdigita.domain.DomainObject;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.metadata.ObjectType;
import com.arsdigita.persistence.metadata.Property;
import com.redhat.persistence.Event;
import com.redhat.persistence.ObjectEvent;
import com.arsdigita.developersupport.Debug;
import com.arsdigita.util.UncheckedWrapperException;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
// new versioning
/**
* Sundry small static methods.
*
* @author Vadim Nasardinov (vadimn@redhat.com)
* @since 2003-03-13
* @version $Revision: #13 $ $DateTime: 2004/08/16 18:10:38 $
**/
final class functions implements Constants {
private final static Logger s_log = Logger.getLogger(functions.class);
private final static String M_SSN = "m_ssn";
private final static String PRINTED_NULL = "null";
private final static String EMPTY_MAP = "<empty map>";
// The length of the decimal representation of the maximum long value.
private final static int LONG_WIDTH =
String.valueOf(Long.MAX_VALUE).length();
private final static ThreadLocal s_seqID = new ThreadLocal() {
public Object initialValue() {
return new MutableInteger();
}
};
private functions() {}
/**
* Retrieves a value from a db-backed sequence and wraps the useless checked
* SQLException.
**/
public static BigInteger nextSequenceValue() {
MutableInteger val = (MutableInteger) s_seqID.get();
val.increment();
s_seqID.set(val);
return val.bigIntegerValue();
}
/**
* <p>Retrieves a value from a db-backed sequence and wraps the useless
* checked SQLException. The value is meant to be used <em>exclusively</em>
* for creating Txn data objects.</p>
**/
public static BigInteger nextTxnID() {
try {
return Sequences.getNextValue("vcx_txns_id_seq").toBigInteger();
} catch (SQLException ex) {
throw new UncheckedWrapperException
("couldn't get the next key value out of a sequence", ex);
}
}
/**
* @return the object type of the container of the property for which this
* property event has been generated
**/
public static ObjectType getObjectType(Event ev) {
return ((DataObject) ev.getObject()).getObjectType();
}
/**
* @retrun the object type of the data object for which this object event
* has been generated.
**/
public static ObjectType getObjectType(ObjectEvent ev) {
return ((DataObject) ev.getObject()).getObjectType();
}
public static String prettyString(DataObject dobj) {
if ( dobj == null ) return PRINTED_NULL;
StringBuffer sb = new StringBuffer();
sb.append(dobj).append(LINE_SEP);
List props = new ArrayList();
for (Iterator ii=dobj.getObjectType().getProperties(); ii.hasNext(); ) {
Property prop = (Property) ii.next();
props.add(prop.getName());
}
Collections.sort(props);
for (Iterator ii=props.iterator(); ii.hasNext(); ) {
String prop = (String) ii.next();
sb.append(prop).append("=");
sb.append(dobj.get(prop)).append(LINE_SEP);
}
return sb.toString();
}
/**
* Converts the <code>map</code> to a pretty string representation of
* key-value pairs, sorted by keys.
*
**/
public static String prettyString(Map map) {
if ( map == null ) return PRINTED_NULL;
if ( map.size() == 0 ) return EMPTY_MAP;
List keys = new ArrayList(map.keySet());
Collections.sort(keys);
return prettyString(map, keys.iterator());
}
public static String prettyStringUnsorted(Map map) {
if ( map == null ) return PRINTED_NULL;
if ( map.size() == 0 ) return EMPTY_MAP;
return prettyString(map, map.keySet().iterator());
}
private static String prettyString(Map map, Iterator keys) {
StringBuffer sb = new StringBuffer();
while ( keys.hasNext() ) {
Object key = keys.next();
sb.append(key).append("=").append(map.get(key));
sb.append(LINE_SEP);
}
return sb.toString();
}
public static String prettyString(DomainObject obj) {
if ( obj == null ) return PRINTED_NULL;
DataObject dobj = (DataObject)
Debug.getPrivateField(DomainObject.class, obj, "m_dataObject");
return prettyString(dobj);
}
// This class is not synchronized
private static class MutableInteger {
private final static long BATCH_SIZE = 100;
private long m_int;
private long m_max;
public MutableInteger() {
fetchFromSequence();
}
private void fetchFromSequence() {
try {
long next = Sequences.getNextValue("vcx_id_seq").longValue();
if (Long.MAX_VALUE / BATCH_SIZE < next ) {
throw new VersioningException
("ran out of suitable sequence values");
}
m_int = next * BATCH_SIZE;
if ( Long.MAX_VALUE - BATCH_SIZE < m_int ) {
throw new VersioningException("ran out");
}
m_max = m_int + BATCH_SIZE;
} catch (SQLException ex) {
throw new UncheckedWrapperException
("couldn't get the next key value out of a sequence", ex);
}
}
public void increment() {
m_int++;
if ( m_int == m_max ) {
fetchFromSequence();
}
}
public BigInteger bigIntegerValue() {
return BigInteger.valueOf(m_int);
}
public String toString() {
return String.valueOf(m_int);
}
}
}