/* * This file is part of Applied Energistics 2. * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. * * Applied Energistics 2 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 3 of the License, or * (at your option) any later version. * * Applied Energistics 2 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 Applied Energistics 2. If not, see . */ package appeng.me; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import appeng.api.networking.IGridNode; import appeng.api.networking.events.MENetworkEvent; import appeng.api.networking.events.MENetworkEventSubscribe; import appeng.core.AELog; public class NetworkEventBus { private static final Collection READ_CLASSES = new HashSet(); private static final Map, Map> EVENTS = new HashMap, Map>(); void readClass( final Class listAs, final Class c ) { if( READ_CLASSES.contains( c ) ) { return; } READ_CLASSES.add( c ); try { for( final Method m : c.getMethods() ) { final MENetworkEventSubscribe s = m.getAnnotation( MENetworkEventSubscribe.class ); if( s != null ) { final Class[] types = m.getParameterTypes(); if( types.length == 1 ) { if( MENetworkEvent.class.isAssignableFrom( types[0] ) ) { Map classEvents = EVENTS.get( types[0] ); if( classEvents == null ) { EVENTS.put( types[0], classEvents = new HashMap() ); } MENetworkEventInfo thisEvent = classEvents.get( listAs ); if( thisEvent == null ) { thisEvent = new MENetworkEventInfo(); } thisEvent.Add( types[0], c, m ); classEvents.put( listAs, thisEvent ); } else { throw new IllegalStateException( "Invalid ME Network Event Subscriber, " + m.getName() + "s Parameter must extend MENetworkEvent." ); } } else { throw new IllegalStateException( "Invalid ME Network Event Subscriber, " + m.getName() + " must have exactly 1 parameter." ); } } } } catch( final Throwable t ) { throw new IllegalStateException( "Error while adding " + c.getName() + " to event bus", t ); } } MENetworkEvent postEvent( final Grid g, final MENetworkEvent e ) { final Map subscribers = EVENTS.get( e.getClass() ); int x = 0; try { if( subscribers != null ) { for( final Entry subscriber : subscribers.entrySet() ) { final MENetworkEventInfo target = subscriber.getValue(); final GridCacheWrapper cache = g.getCaches().get( subscriber.getKey() ); if( cache != null ) { x++; target.invoke( cache.getCache(), e ); } for( final IGridNode obj : g.getMachines( subscriber.getKey() ) ) { x++; target.invoke( obj.getMachine(), e ); } } } } catch( final NetworkEventDone done ) { // Early out. } e.setVisitedObjects( x ); return e; } MENetworkEvent postEventTo( final Grid grid, final GridNode node, final MENetworkEvent e ) { final Map subscribers = EVENTS.get( e.getClass() ); int x = 0; try { if( subscribers != null ) { final MENetworkEventInfo target = subscribers.get( node.getMachineClass() ); if( target != null ) { x++; target.invoke( node.getMachine(), e ); } } } catch( final NetworkEventDone done ) { // Early out. } e.setVisitedObjects( x ); return e; } private static class NetworkEventDone extends Throwable { private static final long serialVersionUID = -3079021487019171205L; } private class EventMethod { private final Class objClass; private final Method objMethod; private final Class objEvent; public EventMethod( final Class Event, final Class ObjClass, final Method ObjMethod ) { this.objClass = ObjClass; this.objMethod = ObjMethod; this.objEvent = Event; } private void invoke( final Object obj, final MENetworkEvent e ) throws NetworkEventDone { try { this.objMethod.invoke( obj, e ); } catch( final Throwable e1 ) { AELog.error( "[AppEng] Network Event caused exception:" ); AELog.error( "Class: %1s, Object: %2s", obj.getClass().getName(), obj.toString() ); AELog.info( e1 ); throw new IllegalStateException( e1 ); } if( e.isCanceled() ) { throw new NetworkEventDone(); } } } private class MENetworkEventInfo { private final List methods = new ArrayList(); private void Add( final Class Event, final Class ObjClass, final Method ObjMethod ) { this.methods.add( new EventMethod( Event, ObjClass, ObjMethod ) ); } private void invoke( final Object obj, final MENetworkEvent e ) throws NetworkEventDone { for( final EventMethod em : this.methods ) { em.invoke( obj, e ); } } } }