/* * Copyright 2008 Niclas Hedhman. 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.logging.trace.service; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.qi4j.api.Qi4j; import org.qi4j.api.composite.Composite; import org.qi4j.api.configuration.Configuration; import org.qi4j.api.entity.EntityBuilder; import org.qi4j.api.entity.EntityComposite; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.This; import org.qi4j.api.service.ServiceComposite; import org.qi4j.api.unitofwork.ConcurrentEntityModificationException; import org.qi4j.api.unitofwork.UnitOfWork; import org.qi4j.api.unitofwork.UnitOfWorkCompletionException; import org.qi4j.api.unitofwork.UnitOfWorkFactory; import org.qi4j.logging.trace.records.CompositeTraceRecordEntity; import org.qi4j.logging.trace.records.EntityTraceRecordEntity; import org.qi4j.logging.trace.records.ServiceTraceRecordEntity; import org.qi4j.logging.trace.records.TraceRecord; import static org.qi4j.functional.Iterables.first; public class TraceServiceMixin implements TraceService { @Structure private UnitOfWorkFactory uowf; @This private Configuration<TraceServiceConfiguration> configuration; private int counter; private Integer traceLevel; @Override public int traceLevel() { if( counter++ % 100 == 0 ) { counter = 0; traceLevel = configuration.get().traceLevel().get(); } return traceLevel; } @Override public void traceSuccess( Class compositeType, Composite object, Method method, Object[] args, Object result, long entryTime, long durationNano ) { UnitOfWork uow = uowf.newUnitOfWork(); try { createTraceRecord( uow, compositeType, object, method, args, entryTime, durationNano, null ); uow.complete(); } catch( ConcurrentEntityModificationException e ) { // ignore for now. Perhaps discard() and try again. } catch( UnitOfWorkCompletionException e ) { // ignore for now. Perhaps discard() and try again. } } @Override public void traceException( Class compositeType, Composite object, Method method, Object[] args, Throwable t, long entryTime, long durationNano ) { UnitOfWork uow = uowf.newUnitOfWork(); try { createTraceRecord( uow, compositeType, object, method, args, entryTime, durationNano, t ); uow.complete(); } catch( ConcurrentEntityModificationException e ) { // ignore for now. Perhaps discard() and try again. } catch( UnitOfWorkCompletionException e ) { // ignore for now. Perhaps discard() and try again. } } private void createTraceRecord( UnitOfWork uow, Class compositeType, Composite object, Method method, Object[] args, long entryTime, long durationNano, Throwable exception ) { if( object instanceof EntityComposite ) { EntityComposite entity = (EntityComposite) object; String identity = entity.identity().get(); EntityComposite source = (EntityComposite) uow.get( (Class<?>) first( Qi4j.FUNCTION_DESCRIPTOR_FOR.map( entity ).types() ), identity ); EntityBuilder<EntityTraceRecordEntity> builder = uow.newEntityBuilder( EntityTraceRecordEntity.class ); EntityTraceRecordEntity state = builder.instance(); setStandardStuff( compositeType, method, args, entryTime, durationNano, state, exception ); state.source().set( source ); EntityTraceRecordEntity etr = builder.newInstance(); // Record is created. } else if( object instanceof ServiceComposite ) { ServiceComposite service = (ServiceComposite) object; EntityBuilder<ServiceTraceRecordEntity> builder = uow.newEntityBuilder( ServiceTraceRecordEntity.class ); ServiceTraceRecordEntity state = builder.instance(); setStandardStuff( compositeType, method, args, entryTime, durationNano, state, exception ); state.source().set( service.toString() ); ServiceTraceRecordEntity str = builder.newInstance(); // Record is created. } else { EntityBuilder<CompositeTraceRecordEntity> builder = uow.newEntityBuilder( CompositeTraceRecordEntity.class ); CompositeTraceRecordEntity state = builder.instance(); state.source().set( object ); setStandardStuff( compositeType, method, args, entryTime, durationNano, state, exception ); CompositeTraceRecordEntity ctr = builder.newInstance(); // Record is created. } } private void setStandardStuff( Class compositeType, Method method, Object[] args, long entryTime, long durationNano, TraceRecord state, Throwable exception ) { state.duration().set( durationNano ); state.entryTime().set( entryTime ); state.methodName().set( method.getName() ); state.compositeTypeName().set( compositeType.getName() ); state.arguments().set( convertArguments( args ) ); state.threadName().set( Thread.currentThread().getName() ); state.exception().set( exception ); } private List<String> convertArguments( Object[] args ) { if( args == null ) { return new ArrayList<String>( 0 ); } List<String> result = new ArrayList<String>( args.length ); for( Object arg : args ) { if( arg == null ) { result.add( null ); } else { result.add( arg.toString() ); } } return result; } }