/* * Copyright (c) 2010, Stanislav Muhametsin. 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.library.entityproxy; import org.qi4j.api.composite.TransientBuilder; import org.qi4j.api.composite.TransientBuilderFactory; import org.qi4j.api.entity.EntityComposite; import org.qi4j.api.entity.Lifecycle; import org.qi4j.api.entity.LifecycleException; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.This; import org.qi4j.api.mixin.Mixins; import org.qi4j.api.unitofwork.UnitOfWorkCallback; import org.qi4j.api.unitofwork.UnitOfWorkCompletionException; import org.qi4j.api.unitofwork.UnitOfWorkFactory; import org.qi4j.library.entityproxy.internal.EntityProxyCache; @Mixins({ProxyableEntity.ProxyableEntityMixin.class}) public interface ProxyableEntity { <ProxyType> ProxyType getProxy(Class<ProxyType> proxyClass); public abstract class ProxyableEntityMixin implements ProxyableEntity, Lifecycle { @Service private EntityProxyCache _proxyUtils; @Structure private UnitOfWorkFactory _uowf; @This private EntityComposite _meAsEntityComposite; @Structure private TransientBuilderFactory _tbf; @Override public <ProxyType> ProxyType getProxy( Class<ProxyType> proxyClass ) { String id = this._meAsEntityComposite.identity().get(); EntityProxy proxy = this._proxyUtils.getFromCache( id ); if (proxy == null) { proxy = this.createProxy( proxyClass ); this._proxyUtils.storeToCache( proxy ); } ProxyType result = proxyClass.cast( proxy ); return result; } private <ProxyType> EntityProxy createProxy(Class<ProxyType> proxyClass) { TransientBuilder<ProxyType> builder = this._tbf.newTransientBuilder(proxyClass); EntityProxy.EntityProxyState state = builder.prototypeFor(EntityProxy.EntityProxyState.class); Class<?> commonClass = this.doGetCommonType(proxyClass); if (commonClass == null) { throw new NoCommonClassFoundException("Did not find common class for entity of type: " + this._meAsEntityComposite.type() + " [proxyClass: " + proxyClass.getName() + "]."); } state.commonClass().set(commonClass); state.entityID().set(this._meAsEntityComposite.identity().get()); return EntityProxy.class.cast( builder.newInstance() ); } private Class<?> doGetCommonType(Class<?> clazz) { Class<?> result = null; MutualType commonType = clazz.getAnnotation(MutualType.class); if (commonType == null) { for (Class<?> sInterface : clazz.getInterfaces()) { result = this.doGetCommonType(sInterface); if (result != null) { break; } } if (result == null && clazz.getSuperclass() != null) { result = this.doGetCommonType(clazz.getSuperclass()); } } else { result = clazz; } return result; } @Override public void create() throws LifecycleException { } @Override public void remove() throws LifecycleException { final String id = this._meAsEntityComposite.identity().get(); this._uowf.currentUnitOfWork().addUnitOfWorkCallback( new UnitOfWorkCallback() { @Override public void beforeCompletion() throws UnitOfWorkCompletionException { // Nothing. } @Override public void afterCompletion( UnitOfWorkStatus status ) { if( status == UnitOfWorkStatus.COMPLETED ) { _proxyUtils.removeFromCache( id ); } } } ); } } }