I'm trying to configure the osgi-jax-rs-connector in my RAP application.
The README says to use the Configuration Admin Service for configuration.
ServiceReference caRef = context
.getServiceReference(ConfigurationAdmin.class.getName());
The code above always returns null for the ServiceReference.
What's the correct way to obtain a reference to the ConfigurationAdmin.
Does another bundle needs to be started before?
If you run Equinox please make sure that the Config Admin bundle (org.eclipse.equinox.cm) is installed and started.
Trying to get a ServiceReference this way is setting yourself up for disaster. This code can't handle 99% of the cases of what happens in OSGi: the config admin might not be there, the config admin bundle is started after you, the config admin bundle is in another start level, the config admin bundle is stopped, and the config admin is updated. The core OSGi API is very powerful, and is used by much middleware, but should not ever be used for application code since it requires way to much understanding of the underlying model and is very error prone.
By far the easiest and most reliable solution is to use Declarative Services (DS) with the annotations:
#Component
public class MyClass implements MyService {
ConfigurationAdmin ca;
#Reference void setCA(ConfigurationAdmin ca) { this.ca = ca; }
public void doMyService() {
// ... you can safely use ca
}
}
And Gunnar might be right, maybe have not installed a Configuration Admin service in the first place. However, with your current snippet your code is going to blow up anyway at another time.
Related
I have an interface which I have implemented. I have annoted the impl with #Component and #Service of the package org.apache.felix.scr.annotations.
I wrote a simple constructor for my impl
public MyImpl(){
LOG.info("New instance created!!");
}
I also added loggers in #activate and #deactivate method.
I expected to see "New instance created!!" only once BUT I can see activate and deactivate method being called per request I make on a page(This service is invoked by A Sling Model which is used in that page)
What I saw was "New instance created!!" logged several times.
This means the OSGi container create multiple instances of my Service and called the activate and deactivate method every time.
This shows that this is not a Singleton.
The Object should be discarded only when I uninstall my bundle.
Please help me understand what is going on here.
I WANT TO IMPLEMENT A TRUE SINGLETON IN AEM
I have implemented this in AEM 6.5 instance which uses Apache Felix.
Edit:
Adding Service properties:
aemRootUrl http://localhost:8080
api.http.connections_manager.timeout 60000
api.http.cookie_max.age 18000
api.http.max_connections 200
api.http.max_connections_per_host 20
api.http.timeout.connection 300000
api.http.timeout.socket 300000
api.server.ssl.trust_all_certs true
api.server.url https://10asdasdsad
api.server.username admin
component.id 3925
component.name com.example.foundation.core.connection.impl.HybrisConnectionImpl
non_akamai.api.server.url hadasdadasd
service.bundleid 585
Service PID com.example.foundation.core.connection.impl.HybrisConnectionImpl
service.scope bundle
Using Bundles com.example.dumb-foundation.core (585)
Values altered to hide client specific information
EDIT::
I've removed the SCR annotations and replaced them with OSGI annotations here I've explictly specified
#Component(service =HybrisConnection.class, immediate=true,scope = ServiceScope.SINGLETON)
But still is shows as scope=bundle.
Should I enforce Singleton and OSGi annotations on it's dependencies as well for this to be a proper Singleton?
In declarative services (which is what you use behind the scenes) there are some cases when a component (and its service) is unpublished.
By default a simple component with immediate=true will come up when the bundle starts and go down when it stops.
If your component has any mandatory service dependencies (#Reference) then it will only be active while all dependencies are present. So if at least one dependent service goes away the component will be deactivated.
In addition the component might get restarted when config is not present at start but added later. If you want to avoid this make the config required.
Every thing #Christian Schneider said is true.
They AEM services are Singletons but are deactivated/unpublished at times. This might be for various reasons.
I faced a horrible issue because of ConfigurationAdmin service. Using this services caused our OSGi config files to be bound to the wrong bundle i.e. SlingModels. bundle within AEM.
the only way to access this is by getting the service using configAdmin.getConfig(PID).setBundleLocation(null);
BUT Doing this causes the service that is linked to this configuration to restart.
So every time I did config.setBundleLocation(null) the service restarted.
The best and most awesome way to resolve this is use OCD to define configuration for OSGi Services linked to OSGi config.xmls
AND NEVER EVER EVER use configuration Admin
If you want to access properties of another service Say ServiceA want to read ServiceB's title property set in com.example.serivce.impl.ServiceB.xml
Then in ServiceB in the #activate method read the props from OCD config and set it in instance level and have ServiceA inject ServiceB as it's dependency and use the property needed.
eg.
class ServiceA{
#Reference
private ServiceB serviceB;
public void someMethod(){
serviceB.getTitle(); // Successfully read property of another service i.e.
ServiceB without using ConfigurationAdmin.
}
}
I am working with Spring and have information in my application.properties that I want to update from an HTML page
Myapplication.properties
...
spring.mail.host=smtp.gmail.com
spring.mail.port=587
...
Let say we need to change the port.
Is it possible to do something like that and what is the result if a user is logged in and we made a change?
I also read this post Update property in spring environment in java code is it the right solution.
I guess if I say that we need to rebuild the appplication.properties after changing some information.
Is it possible to do something like that and what is the result if a
user is logged in and we made a change?
if i understood it right, you want to change mail port in runtime? if so :
of course this is possible, but changing the value in property file alone wouldn't result in a actual change in your system, you should know that it is your responsibility to manage the reconstruction of a new mail sender instance in which you should also consider issues like multi-threading , race-condition , etc
I propose you to use application.properties in system startup to initialize your instance, and in case of change use something like this:
taking advatage of the Changing mail configuration in runtime and singleton pattern you should probabaly reach your aim :
#Component
public class MailSender{
#Value("${spring.mail.host}")
public static String host;
#Value("${spring.mail.port}")
private static Integer port
private static JavaMailSender instance;
public static synchronized JavaMailSender getInstance(Integer port) {
if (instance == null || port!= null) {
MailSender.port = port!=null ? port: MailSender.port;
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(MailSender.host);
mailSender.setPort(MailSender.port);
return instance;
}
}
The above code is an alteration of singleton pattern in which we check whether the mail instance is null or port has new value recreate the instance otherwise if instance has already a value use that, in this way you can change port run time.
please notice that by the code above I am trying to give you some insight into the problem and you may change it based on your design.
I hope I got your purpose correctly.
First of all, after changing configuration you have to reload beans dependent on changed variables.
I would recommend you to have a look at Spring Cloud Config project.
It has the following features:
Stores configs (and changes) in Git
Can change configuration properties at runtime, and force subscribed applications to reload their context (or even dependent beans only) automatically
Despite it is not direct answer to your question (it doesn't have an UI for configuration), but it is a good reason to search UI for Spring Cloud Config instead.
I have develop a new Connector. This connector requires to be configured with two parameters, lets say:
default_trip_timeout_milis
default_trip_threshold
Challenge is, I want read ${myValue_a} and ${myValue_a} from an API, using an HTTP call, not from a file or inline values.
Since this is a connector, I need to make this API call somewhere before connectors are initialized.
FlowVars aren't an option, since they are initialized with the Flows, and this is happening before in the Mule app life Cycle.
My idea is to create an Spring Bean implementing Initialisable, so it will be called before Connectors are init, and here, using any java based libs (Spring RestTemplate?) , call API, get values, and store them somewhere (context? objectStore?) , so the connector can access them.
Make sense? Any other ideas?
Thanks!
mmm you could make a class that will create the properties in the startup and in this class obtain the API properties via http request. Example below:
public class PropertyInit implements InitializingBean,FactoryBean {
private Properties props = new Properties();
#Override
public Object getObject() throws Exception {
return props;
}
#Override
public Class getObjectType() {
return Properties.class;
}
}
Now you should be able to load this property class with:
<context:property-placeholder properties-ref="propertyInit"/>
Hope you like this idea. I used this approach in a previous project.
I want to give you first a strong warning on doing this. If you go down this path then you risk breaking your application in very strange ways because if any other components depend on this component you are having dynamic components on startup, you will break them, and you should think if there are other ways to achieve this behaviour instead of using properties.
That said the way to do this would be to use a proxy pattern, which is a proxy for the component you recreate whenever its properties are changed. So you will need to create a class which extends Circuit Breaker, which encapsulates and instance of Circuit Breaker which is recreated whenever its properties change. These properties must not be used outside of the proxy class as other components may read these properties at startup and then not refresh, you must keep this in mind that anything which might directly or indirectly access these properties cannot do so in their initialisation phase or your application will break.
It's worth taking a look at SpringCloudConfig which allows for you to have a properties server and then all your applications can hot-reload those properties at runtime when they change. Not sure if you can take that path in Mule if SpringCloud is supported yet but it's a nice thing to know exists.
Neil Bartlett's article http://njbartlett.name/2010/07/19/factory-components-in-ds.html shows the way to set config for bundles without using managed service or managed factory.
Search for examples of actually setting the config for this method either point to felix file install or to examples using managed service.
In answer to the question OSGi Declarative Services vs. ManagedService for configuring service? Neil Bartlett states "Note that DS never actually creates a ManagedService or ManagedServiceFactory for your component. It works by listening to Config Admin with a ConfigurationListener. However the internal details are unimportant... simply create configs with PID/factoryPID matching the component.name and it "just works"
I think the technique involves placing a pid entry in the config dictionary but I have no idea how this would be used with config admin.
A guide or simple example of how to set the configuration using this method would be very helpful.
I know it is some time since the question was asked, but I ran into the same problem when trying to create a ManagedServiceFactory-like Component with Declarative Services. So I want to share my solution. Maybe others find it useful. My problem was like this:
I have defined a component (annotated with #Component). On each configuration I add using felix file-install, I want an instance of that component created with the given configuration and activated immediately.
First I tried messing with the properties factory and configurationPid of #Component, but all that is not needed and even returns wrong results (felix annotation processor in the maven plugin seems to have a bug when handling configurationPid).
The solution I came up with:
package com.example.my;
#Component(
name = MyExampleComponent.FACTORY_PID,
configurationPolicy = ConfigurationPolicy.REQUIRE,
property = {"abc=", "exampleProp="}
)
public class MyExampleComponent {
public static final String FACTORY_PID = "com.example.my.component";
#Activate
protected void activate(BundleContext context, Map<String,Object> map) {
// ...
}
}
Then I created a config file for felix file-install named com.example.my.component-test1.cfg:
abc = Hello World
exampleProp = 123
When deployed this automatically creates a folder structure in the configuration folder like com/example/my/component containing the files:
factory.config
contents:
factory.pid="com.example.my.component"
factory.pidList=[ \
"com.example.my.component.525ca4fb-2d43-46f3-b912-8765f639c46f", \
]
.
525ca4fb-2d43-46f3-b912-8765f639c46f.config
contents:
abc="Hello World"
exampleProp="123"
felix.fileinstall.filename="file:/..._.cfg"
service.factoryPid="com.example.my.component"
service.pid="com.example.my.component.525ca4fb-2d43-46f3-b912-8765f639c46f"
The 525ca4fb-2d43-46f3-b912-8765f639c46f seems to be some randomly generated ID (possibly UUID).
In my application I have a set of of DAOs which I inject into my application layer. For an acceptance test I'm writing, I want to preload the dev_server datastore with data, so I use the same Spring config in my JUnit test (using the #ContextConfiguration annotation) to inject an instance of the relevant DAO into my test. When I actually go to store some data eg:
dao.add(entity)
I get the dreaded "No API environment is registered for this thread."
Caused by: java.lang.NullPointerException: No API environment is registered for this thread.
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:108)
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:118)
....
This is probably because my test case hasn't read in the GAE application-web.xml with the app details (although I'm guessing here I could really be wrong); so it doesn't know to write to the same datastore that the app running on the dev_server is reading/writing to.
How can I get my test to "point" to the same datastore as the app? Is there some "datasource" mechanism that I can inject both into the app and the test? Is there a way to get my test to force the datastore api to read the needed config?
Here is a page that talks about how to do unit tests that connect to a dev datastore. Is this the kind of thing you're looking for? Basically it talks about two classes, LocalServiceTestHelper and LocalDatastoreServiceTestConfig that you can use to set up an environment for testing. While the example given is for unit tests, I believe it will also work for your situation.
You can then configure things like whether the dev datastore is written to disk or just kept in memory (for faster tests). If you want this data to go to the same place as your dev server, you will probably want to adjust this, as I think the default is the "in memory" option. If you look at the javadoc there is a "setBackingStoreLocation" method where you can point to whatever file you want.
I've found the solution!!!!
For some reason the Namespace, AppID and the AuthDomain fields of the test datastore have to match that of the dev_server, then the dev_server can see the entities inserted by the test.
You can see the values for the environment (dev_server or test code) with the following statements
System.out.println(NamespaceManager.get());
System.out.println(ApiProxy.getCurrentEnvironment().getAppId());
System.out.println(ApiProxy.getCurrentEnvironment().getAuthDomain());
In your instance of LocalServiceTestHelper (eg: gaeHelper), you can set the values for the test environment
// the NamespaceManager is thread local.
NamespaceManager.set(NamespaceManager.getGoogleAppsNamespace());
gaeHelper.setEnvAppId(<the name of your app in appengine-web.xml>);
gaeHelper.setEnvAuthDomain("gmail.com");
Then the dev_server will see your entities. However because of synchronisation issues, if the test writes to the datastore after the dev_server has been started the dev_server wont see it unless it can be forced to reread the file (which I haven't figured out yet). Else the server has to be restarted.
I've found a workaround, although it's not very nice because each test method doesn't clean up the Datastore, as explained in the article Local Unit Testing for Java, however, the Datastore starts clean each time the Test class is run, so it's not so bad, provided that you're careful about that.
The problem is, that when using SpringJUnit4ClassRunner, the spring environment is created before the #Before annotation can be run, the solution is use #BeforeClass and use a static variable for LocalServiceTestHelper, to have them created before the Spring Environment is set up.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:META-INF/spring/context-test.xml")
#Transactional
public class MyTest {
#Inject
private MyService myService;
private static final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
#BeforeClass
public static void beforeClass() {
helper.setUp();
}
#AfterClass
public static void afterClass() {
helper.tearDown();
}
If anyone has a better solution, I'll be glad to hear!