/** * Create an initial optimistic locking value according the {@link VersionType} * contract for the version property <b>if required</b> and inject it into * the snapshot state. * * @param fields The current snapshot state * @param versionProperty The index of the version property * @param versionType The version type * @param session The originating session * @return True if we injected a new version value into the fields array; false * otherwise. */ public static boolean seedVersion( Object[] fields, int versionProperty, VersionType versionType, SessionImplementor session) { final Object initialVersion = fields[versionProperty]; if ( initialVersion==null || // This next bit is to allow for both unsaved-value="negative" // and for "older" behavior where version number did not get // seeded if it was already set in the object // TODO: shift it into unsaved-value strategy ( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 ) ) { fields[versionProperty] = seed( versionType, session ); return true; } LOG.tracev( "Using initial version: {0}", initialVersion ); return false; }
/** * Create an initial optimisitc locking value according the {@link VersionType} * contract for the version property <b>if required</b> and inject it into * the snapshot state. * * @param fields The current snapshot state * @param versionProperty The index of the version property * @param versionType The version type * @param session The orginating session * @return True if we injected a new version value into the fields array; false * otherwise. */ public static boolean seedVersion( Object[] fields, int versionProperty, VersionType versionType, SessionImplementor session) { Object initialVersion = fields[versionProperty]; if ( initialVersion==null || // This next bit is to allow for both unsaved-value="negative" // and for "older" behavior where version number did not get // seeded if it was already set in the object // TODO: shift it into unsaved-value strategy ( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 ) ) { fields[versionProperty] = seed( versionType, session ); return true; } else { if ( log.isTraceEnabled() ) { log.trace( "using initial version: " + initialVersion ); } return false; } }
/** * Check the version of the object in the <tt>ResultSet</tt> against * the object version in the session cache, throwing an exception * if the version numbers are different */ private void checkVersion( final int i, final Loadable persister, final Serializable id, final Object entity, final ResultSet rs, final SessionImplementor session) throws HibernateException, SQLException { Object version = session.getPersistenceContext().getEntry( entity ).getVersion(); if ( version != null ) { //null version means the object is in the process of being loaded somewhere else in the ResultSet VersionType versionType = persister.getVersionType(); Object currentVersion = versionType.nullSafeGet( rs, getEntityAliases()[i].getSuffixedVersionAliases(), session, null ); if ( !versionType.isEqual(version, currentVersion) ) { if ( session.getFactory().getStatistics().isStatisticsEnabled() ) { session.getFactory().getStatisticsImplementor() .optimisticFailure( persister.getEntityName() ); } throw new StaleObjectStateException( persister.getEntityName(), id ); } } }
private void checkVersion( SessionImplementor session, ResultSet resultSet, EntityPersister persister, EntityAliases entityAliases, EntityKey entityKey, Object entityInstance) { final Object version = session.getPersistenceContext().getEntry( entityInstance ).getVersion(); if ( version != null ) { //null version means the object is in the process of being loaded somewhere else in the ResultSet VersionType versionType = persister.getVersionType(); final Object currentVersion; try { currentVersion = versionType.nullSafeGet( resultSet, entityAliases.getSuffixedVersionAliases(), session, null ); } catch (SQLException e) { throw session.getFactory().getJdbcServices().getSqlExceptionHelper().convert( e, "Could not read version value from result set" ); } if ( !versionType.isEqual( version, currentVersion ) ) { if ( session.getFactory().getStatistics().isStatisticsEnabled() ) { session.getFactory().getStatisticsImplementor().optimisticFailure( persister.getEntityName() ); } throw new StaleObjectStateException( persister.getEntityName(), entityKey.getIdentifier() ); } } }
/** * Generates a VersionProperty representation for an entity mapping given its * version mapping Property. * * @param property The version mapping Property. * @param lazyAvailable Is property lazy loading currently available. * @return The appropriate VersionProperty definition. */ public static VersionProperty buildVersionProperty( EntityPersister persister, SessionFactoryImplementor sessionFactory, int attributeNumber, Property property, boolean lazyAvailable) { String mappedUnsavedValue = ( (KeyValue) property.getValue() ).getNullValue(); VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue( mappedUnsavedValue, getGetter( property ), (VersionType) property.getType(), getConstructor( property.getPersistentClass() ) ); boolean lazy = lazyAvailable && property.isLazy(); return new VersionProperty( persister, sessionFactory, attributeNumber, property.getName(), property.getValue().getType(), new BaselineAttributeInformation.Builder() .setLazy( lazy ) .setInsertable( property.isInsertable() ) .setUpdateable( property.isUpdateable() ) .setValueGenerationStrategy( property.getValueGenerationStrategy() ) .setNullable( property.isOptional() ) .setDirtyCheckable( property.isUpdateable() && !lazy ) .setVersionable( property.isOptimisticLocked() ) .setCascadeStyle( property.getCascadeStyle() ) .createInformation(), unsavedValue ); }
/** * Generate the next increment in the optimistic locking value according * the {@link VersionType} contract for the version property. * * @param version The current version * @param versionType The version type * @param session The originating session * @return The incremented optimistic locking value. */ @SuppressWarnings("unchecked") public static Object increment(Object version, VersionType versionType, SessionImplementor session) { final Object next = versionType.next( version, session ); if ( LOG.isTraceEnabled() ) { LOG.tracef( "Incrementing: %s to %s", versionType.toLoggableString( version, session.getFactory() ), versionType.toLoggableString( next, session.getFactory() ) ); } return next; }
/** * Return an IdentifierValue for the specified unsaved-value. If none is specified, * guess the unsaved value by instantiating a test instance of the class and * reading it's version property value, or if that is not possible, using the java default * value for the type * * @param versionUnsavedValue The mapping defined unsaved value * @param versionGetter The version attribute getter * @param versionType The mapping type for the version * @param constructor The constructor for the entity * * @return The appropriate VersionValue */ public static VersionValue getUnsavedVersionValue( String versionUnsavedValue, Getter versionGetter, VersionType versionType, Constructor constructor) { if ( versionUnsavedValue == null ) { if ( constructor!=null ) { final Object defaultValue = versionGetter.get( instantiate( constructor ) ); // if the version of a newly instantiated object is not the same // as the version seed value, use that as the unsaved-value return versionType.isEqual( versionType.seed( null ), defaultValue ) ? VersionValue.UNDEFINED : new VersionValue( defaultValue ); } else { return VersionValue.UNDEFINED; } } else if ( "undefined".equals( versionUnsavedValue ) ) { return VersionValue.UNDEFINED; } else if ( "null".equals( versionUnsavedValue ) ) { return VersionValue.NULL; } else if ( "negative".equals( versionUnsavedValue ) ) { return VersionValue.NEGATIVE; } else { // this should not happen since the DTD prevents it throw new MappingException( "Could not parse version unsaved-value: " + versionUnsavedValue ); } }
/** * Builds a CacheDataDescriptionImpl from the mapping model of a collection * * @param model The mapping model. * * @return The constructed CacheDataDescriptionImpl */ public static CacheDataDescriptionImpl decode(Collection model) { return new CacheDataDescriptionImpl( model.isMutable(), model.getOwner().isVersioned(), model.getOwner().isVersioned() ? ( (VersionType) model.getOwner().getVersion().getType() ).getComparator() : null ); }
private static Comparator getVersionComparator(EntityBinding model ) { if ( model.isVersioned() ) { final VersionType versionType = (VersionType) model.getHierarchyDetails() .getVersioningAttributeBinding() .getHibernateTypeDescriptor() .getResolvedTypeMapping(); return versionType.getComparator(); } return null; }
/** * Generates a VersionProperty representation for an entity mapping given its * version mapping Property. * * @param property The version mapping Property. * @param lazyAvailable Is property lazy loading currently available. * @return The appropriate VersionProperty definition. */ public static VersionProperty buildVersionProperty(Property property, boolean lazyAvailable) { String mappedUnsavedValue = ( (KeyValue) property.getValue() ).getNullValue(); VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue( mappedUnsavedValue, getGetter( property ), (VersionType) property.getType(), getConstructor( property.getPersistentClass() ) ); boolean lazy = lazyAvailable && property.isLazy(); return new VersionProperty( property.getName(), property.getNodeName(), property.getValue().getType(), lazy, property.isInsertable(), property.isUpdateable(), property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS, property.getGeneration() == PropertyGeneration.ALWAYS, property.isOptional(), property.isUpdateable() && !lazy, property.isOptimisticLocked(), property.getCascadeStyle(), unsavedValue ); }
/** * Generate the next increment in the optimisitc locking value according * the {@link VersionType} contract for the version property. * * @param version The current version * @param versionType The version type * @param session The originating session * @return The incremented optimistic locking value. */ public static Object increment(Object version, VersionType versionType, SessionImplementor session) { Object next = versionType.next( version, session ); if ( log.isTraceEnabled() ) { log.trace( "Incrementing: " + versionType.toLoggableString( version, session.getFactory() ) + " to " + versionType.toLoggableString( next, session.getFactory() ) ); } return next; }
public static VersionValue getUnsavedVersionValue( String versionUnsavedValue, Getter versionGetter, VersionType versionType, Constructor constructor) { if ( versionUnsavedValue == null ) { if ( constructor!=null ) { Object defaultValue = versionGetter.get( instantiate(constructor) ); // if the version of a newly instantiated object is not the same // as the version seed value, use that as the unsaved-value return versionType.isEqual( versionType.seed( null ), defaultValue ) ? VersionValue.UNDEFINED : new VersionValue( defaultValue ); } else { return VersionValue.UNDEFINED; } } else if ( "undefined".equals( versionUnsavedValue ) ) { return VersionValue.UNDEFINED; } else if ( "null".equals( versionUnsavedValue ) ) { return VersionValue.NULL; } else if ( "negative".equals( versionUnsavedValue ) ) { return VersionValue.NEGATIVE; } else { // this should not happen since the DTD prevents it throw new MappingException( "Could not parse version unsaved-value: " + versionUnsavedValue ); } }
public VersionType getVersionType() { return ( VersionType ) locateVersionType(); }
/** * Builds a CacheDataDescriptionImpl from the mapping model of an entity class. * * @param model The mapping model. * * @return The constructed CacheDataDescriptionImpl */ public static CacheDataDescriptionImpl decode(PersistentClass model) { return new CacheDataDescriptionImpl( model.isMutable(), model.isVersioned(), model.isVersioned() ? ( (VersionType) model.getVersion().getType() ).getComparator() : null ); }
@Override protected void prepareVersioned(AST updateNode, AST versioned) throws SemanticException { UpdateStatement updateStatement = (UpdateStatement) updateNode; FromClause fromClause = updateStatement.getFromClause(); if ( versioned != null ) { // Make sure that the persister is versioned Queryable persister = fromClause.getFromElement().getQueryable(); if ( !persister.isVersioned() ) { throw new SemanticException( "increment option specified for update of non-versioned entity" ); } VersionType versionType = persister.getVersionType(); if ( versionType instanceof UserVersionType ) { throw new SemanticException( "user-defined version types not supported for increment option" ); } AST eq = getASTFactory().create( HqlSqlTokenTypes.EQ, "=" ); AST versionPropertyNode = generateVersionPropertyNode( persister ); eq.setFirstChild( versionPropertyNode ); AST versionIncrementNode = null; if ( isTimestampBasedVersion( versionType ) ) { versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" ); ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType ); ( (ParameterNode) versionIncrementNode ).setHqlParameterSpecification( paramSpec ); parameters.add( 0, paramSpec ); } else { // Not possible to simply re-use the versionPropertyNode here as it causes // OOM errors due to circularity :( versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PLUS, "+" ); versionIncrementNode.setFirstChild( generateVersionPropertyNode( persister ) ); versionIncrementNode.addChild( getASTFactory().create( HqlSqlTokenTypes.IDENT, "1" ) ); } eq.addChild( versionIncrementNode ); evaluateAssignment( eq, persister, 0 ); AST setClause = updateStatement.getSetClause(); AST currentFirstSetElement = setClause.getFirstChild(); setClause.setFirstChild( eq ); eq.setNextSibling( currentFirstSetElement ); } }
private boolean isTimestampBasedVersion(VersionType versionType) { final Class javaType = versionType.getReturnedClass(); return Date.class.isAssignableFrom( javaType ) || Calendar.class.isAssignableFrom( javaType ); }
@Override public VersionType getVersionType() { // TODO Auto-generated method stub return null; }
public VersionTypeSeedParameterSpecification(VersionType type) { this.type = type; }
public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) { throw new AssertionFailure("should not be called"); }
public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) { return false; }
public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) { return true; }
public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) { if (versionType==null) return true; //always overwrite nonversioned data return versionType.getComparator().compare(currentVersion, newVersion) <= 0; }
protected void prepareVersioned(AST updateNode, AST versioned) throws SemanticException { UpdateStatement updateStatement = ( UpdateStatement ) updateNode; FromClause fromClause = updateStatement.getFromClause(); if ( versioned != null ) { // Make sure that the persister is versioned Queryable persister = fromClause.getFromElement().getQueryable(); if ( !persister.isVersioned() ) { throw new SemanticException( "increment option specified for update of non-versioned entity" ); } VersionType versionType = persister.getVersionType(); if ( versionType instanceof UserVersionType ) { throw new SemanticException( "user-defined version types not supported for increment option" ); } AST eq = getASTFactory().create( HqlSqlTokenTypes.EQ, "=" ); AST versionPropertyNode = generateVersionPropertyNode( persister ); eq.setFirstChild( versionPropertyNode ); AST versionIncrementNode = null; if ( Date.class.isAssignableFrom( versionType.getReturnedClass() ) ) { versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" ); ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType ); ( ( ParameterNode ) versionIncrementNode ).setHqlParameterSpecification( paramSpec ); parameters.add( 0, paramSpec ); } else { // Not possible to simply re-use the versionPropertyNode here as it causes // OOM errors due to circularity :( versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PLUS, "+" ); versionIncrementNode.setFirstChild( generateVersionPropertyNode( persister ) ); versionIncrementNode.addChild( getASTFactory().create( HqlSqlTokenTypes.IDENT, "1" ) ); } eq.addChild( versionIncrementNode ); evaluateAssignment( eq, persister, 0 ); AST setClause = updateStatement.getSetClause(); AST currentFirstSetElement = setClause.getFirstChild(); setClause.setFirstChild( eq ); eq.setNextSibling( currentFirstSetElement ); } }
/** * @see EntityPersister#getVersionType() */ public VersionType getVersionType() { return null; }
/** * If {@link #isVersioned()}, then what is the type of the property * holding the locking value. * * @return The type of the version property; or null, if not versioned. */ public VersionType getVersionType();
/** * Constructs a version seed parameter bind specification. * * @param type The version type. */ public VersionTypeSeedParameterSpecification(VersionType type) { this.type = type; }
public abstract boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType);