You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _appnotes/dtos.md
+24-22
Original file line number
Diff line number
Diff line change
@@ -185,30 +185,32 @@ example, in Java you can click on a field and ask who references it, something t
185
185
186
186
For example, the OSGi enRoute REST service was designed with DTOs in mind. This is all you have to write (really, no further setup) to create a REST API on `/rest/bundle/:id`.
187
187
188
-
@Component
189
-
public class MyManager implements REST {
190
-
BundleContext context;
191
-
192
-
@Activate
193
-
void activate(BundleContext context) {
194
-
this.context = context;
195
-
}
196
-
197
-
public List<BundleDTO> getBundle() {
198
-
return Stream.of(context.getBundles())
199
-
.map( this::toDTO )
200
-
.collect(Collectors.toList());
201
-
}
202
-
203
-
public BundleDTO getBundle(long id) {
204
-
return toDTO(context.getBundle(id));
205
-
}
206
-
207
-
BundleDTO toDTO( Bundle b) {
208
-
return b.adapt( BundleDTO.class );
209
-
}
188
+
```java
189
+
@Component
190
+
publicclassMyManagerimplementsREST {
191
+
BundleContext context;
192
+
193
+
@Activate
194
+
voidactivate(BundleContextcontext) {
195
+
this.context = context;
210
196
}
211
197
198
+
publicList<BundleDTO>getBundle() {
199
+
returnStream.of(context.getBundles())
200
+
.map( this::toDTO )
201
+
.collect(Collectors.toList());
202
+
}
203
+
204
+
publicBundleDTOgetBundle(longid) {
205
+
return toDTO(context.getBundle(id));
206
+
}
207
+
208
+
BundleDTOtoDTO( Bundleb) {
209
+
return b.adapt( BundleDTO.class );
210
+
}
211
+
}
212
+
```
213
+
212
214
## DTOs Service
213
215
214
216
OSGi enRoute includes the [DTOs service][4]. This service is very useful in working with DTOs. It provides the following features:
Copy file name to clipboardExpand all lines: _doc/215-sos.md
+8-6
Original file line number
Diff line number
Diff line change
@@ -41,12 +41,14 @@ Components (diagram: parallelograms) can interact with external resources.
41
41
42
42
Though services can be created with several alternative systems, in OSGi enRoute Service Components are based on _Declarative Services_. A class that wants to become a Service Component can just add an @Component annotation:
43
43
44
-
package com.acme;
45
-
46
-
@Component
47
-
public class Foo {
48
-
@Activate void open() { System.out.println("Here I am!"); }
49
-
}
44
+
```java
45
+
packagecom.acme;
46
+
47
+
@Component
48
+
publicclassFoo {
49
+
@Activatevoidopen() { System.out.println("Here I am!"); }
50
+
}
51
+
```
50
52
51
53
Declarative services are extremely powerful and therefore have their own [introductory chapter](217-ds.html).
Copy file name to clipboardExpand all lines: _doc/217-ds.md
+103-73
Original file line number
Diff line number
Diff line change
@@ -30,26 +30,28 @@ The OSGi specifications are very cohesive and decoupled. Though this provides nu
30
30
31
31
The best advice is to start very simple and use defaults. This basically means the skeleton of your component is:
32
32
33
-
package com.acme;
34
-
@Component
35
-
public class Foo implements Bar {
33
+
```java
34
+
packagecom.acme;
35
+
@Component
36
+
publicclassFooimplementsBar {
36
37
37
-
@Reference
38
-
EventAdmin eventAdmin;
38
+
@Reference
39
+
EventAdmin eventAdmin;
39
40
40
-
@Reference
41
-
final List<Foo> foo = new CopyOnWriteArrayList<>();
41
+
@Reference
42
+
finalList<Foo> foo =newCopyOnWriteArrayList<>();
42
43
43
-
@interface Config {
44
-
int port();
45
-
}
44
+
@interfaceConfig {
45
+
intport();
46
+
}
46
47
47
-
@Activate void activate( Config config ) {
48
-
}
48
+
@Activatevoidactivate( Configconfig ) {
49
+
}
49
50
50
-
@Deactivate void close() {
51
-
}
51
+
@Deactivatevoidclose() {
52
52
}
53
+
}
54
+
```
53
55
54
56
This gives you a static component that can be be fully configured through the `com.acme.Foo` PID with Configuration Admin whatever _Management Agent_ you pick.
55
57
@@ -66,10 +68,12 @@ If that does not work, ask on a mailing list. Declarative Services are so widely
66
68
67
69
The core idea is the PID: an identifier that identifies the configuration for the a component _type_. For example, the following component has a PID of `com.acme.FooImpl`:
68
70
69
-
package com.acme;
71
+
```java
72
+
packagecom.acme;
70
73
71
-
@Component
72
-
public class FooImpl { }
74
+
@Component
75
+
publicclassFooImpl { }
76
+
```
73
77
74
78
## Default Configuration
75
79
@@ -79,28 +83,32 @@ Let’s forget Configuration Admin for a moment. If you run this component witho
79
83
80
84
If you want to create a service property to be registered (and provided to the `activate` method) then you can provide such a property in the @Component annotation:
Properties suck but are often a necessary evil. They do not refactor easily, are error prone in their spelling, require messy conversions to their desired Java types, require casting, and in general look awful in your code with their YELLING UPPER CASE (assuming you turn the keys into constants). How nice would it be if you could just use type safe constructs?
94
100
95
101
Well, you can. In the previous examples we used a `Map<String,Object>` to get the service properties in the `activate` method. However, we can also replace this map with any annotation type:
96
102
97
-
@interface Config {
98
-
String foo() default “bar”;
99
-
}
103
+
```java
104
+
@interfaceConfig {
105
+
Stringfoo() default "bar";
106
+
}
100
107
101
-
@Activate void activate( Foo.Config config ) {
102
-
assert “bar”equals( config.foo() );
103
-
}
108
+
@Activatevoid activate( Foo.Config config ) {
109
+
assert"bar"equals( config.foo() );
110
+
}
111
+
```
104
112
105
113
## Factory Configuration
106
114
@@ -118,10 +126,12 @@ This is where Configuration Admin comes in. Let’s ignore how we manage Configu
118
126
119
127
With this configuration the `com.acme.Foo` component will be instantiated twice. One component will get foo=one and the other will get foo=two
120
128
121
-
@Activate void activate( Foo.Config config) {
122
-
String foo = config.foo();
123
-
assert “one”.equals(foo) || “two”.equals(foo);
124
-
}
129
+
```java
130
+
@Activatevoid activate( Foo.Config config) {
131
+
String foo = config.foo();
132
+
assert"one".equals(foo) ||"two".equals(foo);
133
+
}
134
+
```
125
135
126
136
## Singleton Configuration
127
137
@@ -134,17 +144,21 @@ Assume that there is a singleton Configuration for the ‘com.acme.Foo’ PID:
134
144
135
145
If we now run our system, the activate method gets called with `foo=singleton`
136
146
137
-
@Activate void activate( Foo.Config config) {
138
-
assert “singleton”.equals( config.foo() );
139
-
}
147
+
```java
148
+
@Activatevoid activate( Foo.Config config) {
149
+
assert"singleton".equals( config.foo() );
150
+
}
151
+
```
140
152
141
153
## Mandatory Configuration
142
154
143
155
Maybe you’ve noticed, but factories now have a rather strange life cycle. If there is no configuration for the given PID, then the component gets instantiated once with the service properties defined in the @Component annotation. If you then create a factory configuration for that PID, the default component is deleted and the factory configuration is used to instantiate a new component. The consequence of this is that you cannot have zero components, there will always be at least one. Though a default instance is sometimes handy, in general it does not make sense. In that case you can make the configuration mandatory: only if the configuration is set (either singleton or factory) will the component be instantiated.
With a mandatory configuration the component is only instantiated when there is a Configuration for the corresponding PID. The following table shows how the configuration interacts with this policy:
150
164
@@ -158,8 +172,10 @@ With a mandatory configuration the component is only instantiated when there is
158
172
159
173
PIDs are public API since external parties will be aware of them when they configure your component. For this reason it is sometimes better to create a name that can be kept constant over time even if implementations change.
160
174
161
-
@Component( name = “com.acme.foo” )
162
-
public class FooImpl { }
175
+
```java
176
+
@Component( name="com.acme.foo" )
177
+
publicclassFooImpl { }
178
+
```
163
179
164
180
## Management Agent
165
181
@@ -180,15 +196,18 @@ Using the annotation types significantly cleaned up our code. However, with File
180
196
181
197
So how do we link our annotation type to a metatype? Though the metatypes are defined in XML there are fortunately (build) annotations for it.
182
198
183
-
@ObjectClassDefinition
184
-
@interface Config {
185
-
@AttributeDefinition
186
-
String foo();
187
-
}
199
+
```java
200
+
@ObjectClassDefinition
201
+
@interfaceConfig {
202
+
@AttributeDefinition
203
+
Stringfoo();
204
+
}
188
205
189
-
@Designate( ocd = Config.class, factory=true )
190
-
@Component
191
-
public class Foo {}
206
+
@Designate( ocd=Config.class, factory=true )
207
+
@Component
208
+
publicclassFoo {}
209
+
210
+
```
192
211
193
212
The` @ObjectClassDefinition` and `@AttributeDefinition` can describe the ‘properties’ and provide additional information to control the user interface. The `@Designate` annotation links a configuration type (or as we call it: an Object Class Definition or ocd) to a component’s PID. This will create the proper XML for the Metatype service to link it all together.
194
213
@@ -197,21 +216,26 @@ The` @ObjectClassDefinition` and `@AttributeDefinition` can describe the ‘prop
197
216
Services are linked to each other by their object classes. I.e. one component requires an instance of the Foo service type. You create that dependency with the `@Reference` annotation. A `@Component` annotated type can then register this service. However, sometimes you cannot avoid but make the _wiring_ of the services more complicated. Sometimes you really need to ensure that a component Bar is really wired to a specific instance of Foo.
198
217
199
218
This can be done with the `target` field in the `@Reference` annotation.
200
-
201
-
@Reference( target=“(foo=bar)” )
202
-
Foo foo;
219
+
```java
220
+
@Reference( target="(foo=bar)" )
221
+
Foo foo;
222
+
```
203
223
204
224
A component Foo can then register its service with a number of properties under Configuration Admin control.
205
225
206
-
@Component public class FooImpl implements Foo {
207
-
}
226
+
```java
227
+
@ComponentpublicclassFooImplimplementsFoo {
228
+
}
229
+
```
208
230
209
231
Another component can depend on this property.
210
232
211
-
@Component public class Bar {
212
-
@Reference( target=“(foo=bar)” )
213
-
Foo foo;
214
-
}
233
+
```java
234
+
@ComponentpublicclassBar {
235
+
@Reference( target="(foo=bar)" )
236
+
Foo foo;
237
+
}
238
+
```
215
239
216
240
We can now create a configuration for FooImpl
217
241
@@ -236,26 +260,32 @@ One of the rare cases where this is necessary is when you have to wait for a con
236
260
237
261
To register a service manually you require a `BundleContext` object. You can get that objectvia the activate method, just declare a Bundle Context in its arguments and it is automatically injected:
238
262
239
-
@Activate
240
-
void activate( BundleContext context) {
241
-
this.context = context;
242
-
}
263
+
```java
264
+
@Activate
265
+
void activate( BundleContext context) {
266
+
this.context = context;
267
+
}
268
+
```
243
269
244
270
You can now register a service with the bundle context:
245
271
246
-
void register(MyService service) {
247
-
Hashtable<String,Object> properties = new Hashtable<>();
However, you now have the responsibility to unregister this service in your deactivate. If you do not clean up this service then your _component_ might be deactivated while your service still floats around. Your service is _unmanaged_. (Although when the _bundle_ is stopped it will be cleaned up.)
253
281
254
-
@Deactivate
255
-
void deactivate() {
256
-
if ( this.registration != null)
257
-
this.registration.unregister();
258
-
}
282
+
```java
283
+
@Deactivate
284
+
void deactivate() {
285
+
if ( this.registration !=null)
286
+
this.registration.unregister();
287
+
}
288
+
```
259
289
260
290
If you create the service is a call back or background thread then you obviously have to handle the concurrency issues. You must ensure that there is no race condition that you register a service while the deactivate method has finished.
0 commit comments