I have this component,
package com.path.http.impl;
import com.path.api.http.ClientManager;
import com.path.http.ConnectionManager;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import javax.ws.rs.client.Client;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Component
@Service
public final class DefaultClientManager implements ClientManager {
@Reference(cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
bind = "bindConnectionManager",
unbind = "unbindConnectionManager",
referenceInterface = ConnectionManager.class)
private final ConcurrentMap<String, Client> clients = new ConcurrentHashMap<>();
@Override
public Optional<Client> getClient(final String id) {
return Optional.ofNullable(this.clients.get(id));
}
protected void bindConnectionManager(final ConnectionManager connectionManager,
final Map<String, Object> properties) {
final Client client = connectionManager.getClient();
this.clients.put(
PropertiesUtil.toString(properties.get(DefaultConnectionManagerImpl.MANAGER_ID), ""),
client
);
}
protected void unbindConnectionManager(final ConnectionManager connectionManager,
final Map<String, Object> properties) {
this.clients.remove(
PropertiesUtil.toString(properties.get(DefaultConnectionManagerImpl.MANAGER_ID), "")
);
}
}
And I wanted to update it from the SCR annotations to the newer OSGI ones.
I wound up with something like:
package com.path.http.impl;
import com.path.http.ClientManager;
import com.path.http.ConnectionManager;
import com.path.http.impl.DefaultConnectionManagerImpl;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import jakarta.ws.rs.client.Client;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Component(service = ClientManager.class)
public final class DefaultClientManager implements ClientManager {
@Reference(cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
bind = "bindConnectionManager",
unbind = "unbindConnectionManager",
service = ConnectionManager.class)
private final ConcurrentMap<String, Client> clients = new ConcurrentHashMap<String, Client>();
@Override
public Optional<Client> getClient(final String id) {
return Optional.ofNullable(this.clients.get(id));
}
protected void bindConnectionManager(final ConnectionManager connectionManager,
final Map<String, Object> properties) {
this.clients
.put(PropertiesUtil.toString(properties.get(DefaultConnectionManagerImpl.MANAGER_ID),
""),
connectionManager.getClient());
}
protected void unbindConnectionManager(final ConnectionManager connectionManager,
final Map<String, Object> properties) {
this.clients
.remove(PropertiesUtil.toString(properties.get(DefaultConnectionManagerImpl.MANAGER_ID),
""));
}
}
Now, I still don't understand everything so there are some parts which make me uncertain (for example, can I expect my bind
and unbind
methods to still get passed a Map
of properties, with OSGI?).
But the primary issue I'm running into is these two errors from my Maven build:
[ERROR] …/src/main/java/com/path/http/impl/DefaultClientManager.java:[22,30] cannot find symbol
symbol: method bind()
location: @interface org.osgi.service.component.annotations.Reference
[ERROR] …/src/main/java/com/path/http/impl/DefaultClientManager.java:[20,5] annotation type not applicable to this kind of declaration
Removing bind
from the @Reference
annotation gets rid of the first error (though not what I want to do, in the end) but the second one always remains, even if I get rid of all optional elements.
Reading the JavaDocs, it does say, "Annotated field - There is no bind method name," but that's also in the context of what it defaults to if the optional element isn't provided so it's not clear to me whether bind
can be or cannot be used with a field, like this (unbind
has the same documentation wording but does not throw an error when I leave it).
As far as I can tell, I'm creating a 1-to-1 conversion of the original class, using the new annotations' and libraries' equivalents so I don't understand why this won't work.
Even if the @Reference
wouldn't work on deployment, I'm pretty certain that OSGI @Reference
s can be used for fields, still, so I don't understand why Maven is still complaining when I remove all optional elements from the annotation.
At a high level, I'd love to understand how to convert my old component into one which uses OSGI annotations. At a more specific level, I would happily settle to understand why my @Reference
annotation doesn't seem to want to work with the field, if I'm using any of the optional elements incorrectly.
My Maven dependencies, for the newer code, are:
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.service.component.annotations</artifactId>
<version>1.5.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.service.metatype.annotations</artifactId>
<version>1.4.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.commons.osgi</artifactId>
<version>2.4.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>3.1.1</version>
</dependency>
Java version is 8
; AEM version is 6.5.15
(though I am running into the Maven error before anything actually gets deployed to the running AEM instance).
And ClientManager
is just a simple interface
which looks like:
package com.path.http;
import jakarta.ws.rs.client.Client;
import java.util.Optional;
public interface ClientManager {
Optional<Client> getClient(final String id);
}