1818 */
1919package org .apache .felix .log ;
2020
21+ import java .lang .reflect .Constructor ;
22+ import java .lang .reflect .InvocationTargetException ;
23+ import java .lang .reflect .Method ;
2124import java .util .Enumeration ;
25+ import java .util .HashMap ;
26+ import java .util .Map ;
27+ import java .util .concurrent .atomic .AtomicReference ;
2228
29+ import org .osgi .annotation .bundle .Requirement ;
2330import org .osgi .framework .Bundle ;
31+ import org .osgi .framework .BundleContext ;
2432import org .osgi .framework .BundleEvent ;
2533import org .osgi .framework .BundleListener ;
34+ import org .osgi .framework .Constants ;
2635import org .osgi .framework .FrameworkEvent ;
2736import org .osgi .framework .FrameworkListener ;
2837import org .osgi .framework .ServiceEvent ;
2938import org .osgi .framework .ServiceListener ;
3039import org .osgi .framework .ServiceReference ;
40+ import org .osgi .namespace .implementation .ImplementationNamespace ;
41+ import org .osgi .service .event .EventConstants ;
3142import org .osgi .service .log .LogEntry ;
3243import org .osgi .service .log .LogLevel ;
3344import org .osgi .service .log .LogListener ;
45+ import org .osgi .util .tracker .ServiceTracker ;
46+ import org .osgi .util .tracker .ServiceTrackerCustomizer ;
3447
3548/**
3649 * Class used to represent the log. This class is used by the implementations
3952 * @see org.osgi.service.log.LogService
4053 * @see org.osgi.service.log.LogReaderService
4154 */
55+ @ Requirement (namespace = ImplementationNamespace .IMPLEMENTATION_NAMESPACE ,
56+ name = EventConstants .EVENT_ADMIN_IMPLEMENTATION ,
57+ version = EventConstants .EVENT_ADMIN_SPECIFICATION_VERSION ,
58+ resolution = Requirement .Resolution .OPTIONAL )
4259final class Log implements BundleListener , FrameworkListener , ServiceListener
4360{
61+ private static final String EVENT_ADMIN_CLASS = "org.osgi.service.event.EventAdmin" ;
62+ private static final String EVENT_CLASS = "org.osgi.service.event.Event" ;
63+ private static final String POST_EVENT_METHOD = "postEvent" ;
64+
4465 /** The first log entry. */
4566 private volatile LogNode m_head ;
4667 /** The last log entry. */
@@ -55,16 +76,111 @@ final class Log implements BundleListener, FrameworkListener, ServiceListener
5576 private final boolean m_storeDebug ;
5677 /** Active flag */
5778 private volatile boolean active = true ;
79+ /** Bundle context */
80+ private final BundleContext m_context ;
81+ /** Service tracker for EventAdmin */
82+ private final ServiceTracker <?, EAProxy > m_eventAdminTracker ;
83+
84+ static class EventAdminServiceInfo {
85+ final Constructor <?> m_eventClassCtor ;
86+ final Method m_postEventMethod ;
87+ final Object m_service ;
88+
89+ EventAdminServiceInfo (Constructor <?> eventClassCtor , Method postEventMethod , Object service ) {
90+ this .m_eventClassCtor = eventClassCtor ;
91+ this .m_postEventMethod = postEventMethod ;
92+ this .m_service = service ;
93+ }
94+ }
95+
96+ static class EAProxy {
97+ final AtomicReference <EventAdminServiceInfo > m_info = new AtomicReference <>();
98+
99+ public EAProxy (ServiceReference <?> reference , Object service ) {
100+ setServiceInfo (reference , service );
101+ }
102+
103+ final void setServiceInfo (ServiceReference <?> reference , Object service ) {
104+ final Bundle bundle = reference .getBundle ();
105+ try {
106+ Class <?> eventClass = bundle .loadClass (EVENT_CLASS );
107+ final Constructor <?> eventConstructor = eventClass .getConstructor (String .class , Map .class );
108+ Class <?> eventAdminClass = bundle .loadClass (EVENT_ADMIN_CLASS );
109+ final Method postMethod = eventAdminClass .getMethod (POST_EVENT_METHOD , eventClass );
110+ this .m_info .set (new EventAdminServiceInfo (eventConstructor , postMethod , service ));
111+ } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e ) {
112+ throw new IllegalStateException (
113+ "Failure reflecting over API from Event Admin service bundle" , e );
114+ }
115+ }
116+
117+ void resetServiceInfo () {
118+ this .m_info .set (null );
119+ }
120+
121+ void postEvent (LogEntry entry ) {
122+ final EventAdminServiceInfo eventAdminServiceInfo = this .m_info .get ();
123+ if (eventAdminServiceInfo == null ) {
124+ return ;
125+ }
126+
127+ try {
128+ final LogLevel logLevel = entry .getLogLevel ();
129+ final String topic ;
130+ if (logLevel == LogLevel .TRACE ) {
131+ topic = "org/osgi/service/log/LogEntry/LOG_OTHER" ;
132+ } else {
133+ topic = "org/osgi/service/log/LogEntry/LOG_" + logLevel .name ();
134+ }
135+ final Map <String , Object > props = new HashMap <>(10 );
136+ final Bundle bundle = entry .getBundle ();
137+ props .put (EventConstants .BUNDLE_ID , bundle .getBundleId ());
138+ props .put (EventConstants .BUNDLE_SYMBOLICNAME , bundle .getSymbolicName ());
139+ props .put (EventConstants .BUNDLE , bundle );
140+ props .put ("log.level" , entry .getLogLevel ());
141+ props .put ("log.loggername" , entry .getLoggerName ());
142+ props .put ("log.threadinfo" , entry .getThreadInfo ());
143+ props .put ("log.loglevel" , logLevel );
144+ props .put (EventConstants .MESSAGE , entry .getMessage ());
145+ props .put (EventConstants .TIMESTAMP , entry .getTime ());
146+ props .put ("log.entry" , entry );
147+ final Throwable exception = entry .getException ();
148+ if (exception != null ) {
149+ props .put (EventConstants .EXCEPTION_CLASS , exception .getClass ().getName ());
150+ props .put (EventConstants .EXCEPTION_MESSAGE , exception .getMessage ());
151+ props .put (EventConstants .EXCEPTION , exception );
152+ }
153+ final ServiceReference <?> serviceReference = entry .getServiceReference ();
154+ if (serviceReference != null ) {
155+ props .put (EventConstants .SERVICE , serviceReference );
156+ props .put (EventConstants .SERVICE_ID , serviceReference .getProperty (Constants .SERVICE_ID ));
157+ final Object servicePid = serviceReference .getProperty (Constants .SERVICE_PID );
158+ if (servicePid != null ) {
159+ props .put (EventConstants .SERVICE_PID , servicePid );
160+ }
161+ props .put (EventConstants .SERVICE_OBJECTCLASS , serviceReference .getProperty (Constants .OBJECTCLASS ));
162+ }
163+ final Object event = eventAdminServiceInfo .m_eventClassCtor .newInstance (topic , props );
164+ eventAdminServiceInfo .m_postEventMethod .invoke (eventAdminServiceInfo .m_service , event );
165+ } catch (IllegalAccessException | InvocationTargetException | InstantiationException e ) {
166+ throw new RuntimeException (e );
167+ }
168+ }
169+ }
58170
59171 /**
60172 * Create a new instance.
61173 * @param maxSize the maximum size for the log
62174 * @param storeDebug whether or not to store debug messages
63175 */
64- Log (final int maxSize , final boolean storeDebug )
176+ Log (final BundleContext context , final int maxSize , final boolean storeDebug )
65177 {
178+ this .m_context = context ;
66179 this .m_maxSize = maxSize ;
67180 this .m_storeDebug = storeDebug ;
181+ this .m_eventAdminTracker = new ServiceTracker <>(context , EVENT_ADMIN_CLASS ,
182+ new EAProxyServiceTrackerCustomizer ());
183+ this .m_eventAdminTracker .open ();
68184 }
69185
70186 /**
@@ -78,6 +194,7 @@ synchronized void close()
78194 listenerThread .shutdown ();
79195 listenerThread = null ;
80196 }
197+ m_eventAdminTracker .close ();
81198
82199 m_head = null ;
83200 m_tail = null ;
@@ -151,6 +268,12 @@ synchronized void addEntry(final LogEntry entry)
151268 {
152269 listenerThread .addEntry (entry );
153270 }
271+
272+ final EAProxy eaProxy = this .m_eventAdminTracker .getService ();
273+ if (eaProxy != null )
274+ {
275+ eaProxy .postEvent (entry );
276+ }
154277 }
155278
156279 /**
@@ -330,4 +453,21 @@ public void serviceChanged(final ServiceEvent event)
330453 message ,
331454 null );
332455 }
456+
457+ private class EAProxyServiceTrackerCustomizer implements ServiceTrackerCustomizer <Object , EAProxy > {
458+ @ Override
459+ public EAProxy addingService (ServiceReference <Object > reference ) {
460+ return new EAProxy (reference , m_context .getService (reference ));
461+ }
462+
463+ @ Override
464+ public void modifiedService (ServiceReference <Object > reference , EAProxy proxy ) {
465+ proxy .setServiceInfo (reference , m_context .getService (reference ));
466+ }
467+
468+ @ Override
469+ public void removedService (ServiceReference <Object > reference , EAProxy proxy ) {
470+ proxy .resetServiceInfo ();
471+ }
472+ }
333473}
0 commit comments