18
18
*/
19
19
package org .apache .felix .log ;
20
20
21
+ import java .lang .reflect .Constructor ;
22
+ import java .lang .reflect .InvocationTargetException ;
23
+ import java .lang .reflect .Method ;
21
24
import java .util .Enumeration ;
25
+ import java .util .HashMap ;
26
+ import java .util .Map ;
27
+ import java .util .concurrent .atomic .AtomicReference ;
22
28
29
+ import org .osgi .annotation .bundle .Requirement ;
23
30
import org .osgi .framework .Bundle ;
31
+ import org .osgi .framework .BundleContext ;
24
32
import org .osgi .framework .BundleEvent ;
25
33
import org .osgi .framework .BundleListener ;
34
+ import org .osgi .framework .Constants ;
26
35
import org .osgi .framework .FrameworkEvent ;
27
36
import org .osgi .framework .FrameworkListener ;
28
37
import org .osgi .framework .ServiceEvent ;
29
38
import org .osgi .framework .ServiceListener ;
30
39
import org .osgi .framework .ServiceReference ;
40
+ import org .osgi .namespace .implementation .ImplementationNamespace ;
41
+ import org .osgi .service .event .EventConstants ;
31
42
import org .osgi .service .log .LogEntry ;
32
43
import org .osgi .service .log .LogLevel ;
33
44
import org .osgi .service .log .LogListener ;
45
+ import org .osgi .util .tracker .ServiceTracker ;
46
+ import org .osgi .util .tracker .ServiceTrackerCustomizer ;
34
47
35
48
/**
36
49
* Class used to represent the log. This class is used by the implementations
39
52
* @see org.osgi.service.log.LogService
40
53
* @see org.osgi.service.log.LogReaderService
41
54
*/
55
+ @ Requirement (namespace = ImplementationNamespace .IMPLEMENTATION_NAMESPACE ,
56
+ name = EventConstants .EVENT_ADMIN_IMPLEMENTATION ,
57
+ version = EventConstants .EVENT_ADMIN_SPECIFICATION_VERSION ,
58
+ resolution = Requirement .Resolution .OPTIONAL )
42
59
final class Log implements BundleListener , FrameworkListener , ServiceListener
43
60
{
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
+
44
65
/** The first log entry. */
45
66
private volatile LogNode m_head ;
46
67
/** The last log entry. */
@@ -55,16 +76,111 @@ final class Log implements BundleListener, FrameworkListener, ServiceListener
55
76
private final boolean m_storeDebug ;
56
77
/** Active flag */
57
78
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
+ }
58
170
59
171
/**
60
172
* Create a new instance.
61
173
* @param maxSize the maximum size for the log
62
174
* @param storeDebug whether or not to store debug messages
63
175
*/
64
- Log (final int maxSize , final boolean storeDebug )
176
+ Log (final BundleContext context , final int maxSize , final boolean storeDebug )
65
177
{
178
+ this .m_context = context ;
66
179
this .m_maxSize = maxSize ;
67
180
this .m_storeDebug = storeDebug ;
181
+ this .m_eventAdminTracker = new ServiceTracker <>(context , EVENT_ADMIN_CLASS ,
182
+ new EAProxyServiceTrackerCustomizer ());
183
+ this .m_eventAdminTracker .open ();
68
184
}
69
185
70
186
/**
@@ -78,6 +194,7 @@ synchronized void close()
78
194
listenerThread .shutdown ();
79
195
listenerThread = null ;
80
196
}
197
+ m_eventAdminTracker .close ();
81
198
82
199
m_head = null ;
83
200
m_tail = null ;
@@ -151,6 +268,12 @@ synchronized void addEntry(final LogEntry entry)
151
268
{
152
269
listenerThread .addEntry (entry );
153
270
}
271
+
272
+ final EAProxy eaProxy = this .m_eventAdminTracker .getService ();
273
+ if (eaProxy != null )
274
+ {
275
+ eaProxy .postEvent (entry );
276
+ }
154
277
}
155
278
156
279
/**
@@ -330,4 +453,21 @@ public void serviceChanged(final ServiceEvent event)
330
453
message ,
331
454
null );
332
455
}
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
+ }
333
473
}
0 commit comments