| /* |
| * Copyright (c) 2009, Rickard Öberg. All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.qi4j.spi.entitystore; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.WeakHashMap; |
| import org.qi4j.api.entity.EntityReference; |
| import org.qi4j.api.injection.scope.This; |
| import org.qi4j.api.mixin.Mixins; |
| import org.qi4j.api.usecase.Usecase; |
| import org.qi4j.spi.entity.EntityState; |
| import org.qi4j.spi.entity.EntityStatus; |
| import org.qi4j.spi.module.ModuleSpi; |
| |
| /** |
| * Entity versions state. |
| */ |
| @Mixins( EntityStateVersions.EntityStateVersionsMixin.class ) |
| public interface EntityStateVersions |
| { |
| void forgetVersions( Iterable<EntityState> states ); |
| |
| void rememberVersion( EntityReference identity, String version ); |
| |
| void checkForConcurrentModification( Iterable<EntityState> loaded, ModuleSpi module, long currentTime ) |
| throws ConcurrentEntityStateModificationException; |
| |
| /** |
| * Entity versions state mixin. |
| */ |
| class EntityStateVersionsMixin |
| implements EntityStateVersions |
| { |
| @This |
| private EntityStore store; |
| |
| private final Map<EntityReference, String> versions = new WeakHashMap<>(); |
| |
| @Override |
| public synchronized void forgetVersions( Iterable<EntityState> states ) |
| { |
| for( EntityState state : states ) |
| { |
| versions.remove( state.identity() ); |
| } |
| } |
| |
| @Override |
| public synchronized void rememberVersion( EntityReference identity, String version ) |
| { |
| versions.put( identity, version ); |
| } |
| |
| @Override |
| public synchronized void checkForConcurrentModification( Iterable<EntityState> loaded, |
| ModuleSpi module, |
| long currentTime |
| ) |
| throws ConcurrentEntityStateModificationException |
| { |
| List<EntityReference> changed = null; |
| for( EntityState entityState : loaded ) |
| { |
| if( entityState.status().equals( EntityStatus.NEW ) ) |
| { |
| continue; |
| } |
| |
| String storeVersion = versions.get( entityState.identity() ); |
| if( storeVersion == null ) |
| { |
| EntityStoreUnitOfWork unitOfWork = store.newUnitOfWork( Usecase.DEFAULT, module, currentTime ); |
| EntityState state = unitOfWork.entityStateOf( module, entityState.identity() ); |
| storeVersion = state.version(); |
| unitOfWork.discard(); |
| } |
| |
| if( !entityState.version().equals( storeVersion ) ) |
| { |
| if( changed == null ) |
| { |
| changed = new ArrayList<>(); |
| } |
| changed.add( entityState.identity() ); |
| } |
| } |
| |
| if( changed != null ) |
| { |
| throw new ConcurrentEntityStateModificationException( changed ); |
| } |
| } |
| } |
| } |