I have a boolean flag propertyplaceholder that I'm trying to override in one of my unit tests but it's not working.
<cm:property-placeholder id="id" persistent-id="persistent-id>
<cm:default-properties>
<cm:property name="flag" value="true" />
</cm:default-properties>
</cm:property-placeholder>
This flag gets use in a bean:
<bean id="myBean" class="com.myBean">
<property name="flag" value="${flag}" />
</bean>
I'd like to override the property to be false when doing unit testing so I implemented the useOverridePropertiesWithPropertiesComponent() method:
#Override
protected Properties useOverridePropertiesWithPropertiesComponent() {
Properties prop = new Properties();
prop.put("errorQueue", "mock:error");
prop.put("flag", false);
return prop;
}
My errorQueue property is working fine and error messages are going to "mock:error" but the flag isn't overridden property. Does anyone know why this is?
You cannot do those overrides when its <bean>s
eg the following ${flag} is 100% controlled by OSGi blueprint:
<bean id="myBean" class="com.myBean">
<property name="flag" value="${flag}" />
</bean>
And the useOverridePropertiesWithPropertiesComponent is for the Camel properties component for Camel property placeholders, eg the {{ }} syntax that Camel uses.
http://camel.apache.org/using-propertyplaceholder.html
I am not sure, but I think that your value is not accepted.
Javadoc for Properties states:
The Properties class represents a persistent set of properties. The Properties can be saved to a stream or loaded from a stream. Each key and its corresponding value in the property list is a string.
You are using a boolean, try with
prop.put("flag", "false");
In general key-values for property-placeholder are strings and converted to the appropriate type at runtime.
Related
I create ValidateInterceptor in below path and created bean in custombackoffice-backoffice-spring.xml
C:\hybris\bin\custom\custombackoffice\backoffice\src\com\custom\backoffice\interceptor\CustomAppeasementUserValidateInterceptor.java
bean is as below
<bean id="customAppeasementUserValidateInterceptor" class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="customAppeasementUserValidateInterceptor" />
<property name="typeCode" value="Appeasement" />
</bean>
when I modify particular model in backoffice and click on the save button, debugger never goes to interceptor it directly saves the model.
NOTE :- I can't write this interceptor in customcore because we can not import below services in custom core
import com.hybris.cockpitng.core.user.AuthorityGroupService;
import com.hybris.cockpitng.core.user.impl.AuthorityGroup;
Why the interceptor is not getting triggered?
The bean-id and the mapper bean-id are the same. Change either one. Ideally, it should be like-
<bean id="customAppeasementUserValidateInterceptorMapping" class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="customAppeasementUserValidateInterceptor" />
<property name="typeCode" value="Appeasement" />
</bean>
Notice the new id for the mapping bean i.e. customAppeasementUserValidateInterceptorMapping.
I want to use a SimpleRegistry to store properties (as global variables). The property is changed with setProperty in a route with a jms endpoint. The camel documentation changed last week and has many dead links, also the Registry page. I did not found any samples that describe the use of the simpleRegistry.
I used the camel-example-servlet-tomcat as base. I do not use Fuse or the patched camel wildfly, because is to huge for our simple module.
<beans .... >
.
.
.
<bean id="simpleRegistry" class="org.apache.camel.support.SimpleRegistry" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties" location="ref:simpleRegistry" />
<route id="storeConfig">
<from id="myTopic" uri="jms:topic:myTopic?selector=Configuration %3D 'xyz'" />
<log id="printHeader2" message="Received header: ${headers}" />
<log id="logToken" message="Received token: ${headers[myToken]}" />
<setProperty id="setMyToken" name="myProperty">
<simple>${headers[myToken]}</simple>
</setProperty>
</route>
<route id="externalIncomingDataRoute">
<from uri="servlet:hello" />
<transform>
<simple>The Token is: {{myProperty}}</simple>
</transform>
</route>
</camelContext>
</beans>
With the camel context deined like above, I got a java.io.FileNotFoundException Properties simpleRegistry not found in registry.
When I use <propertyPlaceholder id="properties" location="classpath:test.properties" /> and create a test.properties file, everything works fine but I cannot change the property. The operation in the setProperty tag is ignored.
The reason why I need a global variable is, I send a dynamic configuration (the myToken) via a jms topic to the camel context. A single route should store this configuration globaly. If an other route is called via an rest component, this route need the token to make a choice.
Alternatively you can achieve the same result following the below approach which uses the PropertiesComponent
<bean id="applicationProperties" class="java.util.Properties"/>
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="location" value="classpath:application.properties"/>
<property name="overrideProperties" ref="applicationProperties" />
</bean>
Define the property place holder in the camel context:
<propertyPlaceholder id="propertiesRef" location="ref:applicationProperties" />
Set a property as shown below :
<bean ref="applicationProperties" method="setProperty(token, 'Test'})" />
And to fetch the property : ${properties:token}
OK, there are multiple subjects in your question.
You write you want to use Camel SimpleRegistry, but you obviously have a Spring application.
If you got Spring available, the Camel Registry automatically uses the Spring bean registry. The Camel Registry is just a thin wrapper or provider interface that uses whenever possible an available registry of another framework.
The Camel SimpleRegistry is only used when nothing else is available. This is basically an in-memory registry based on a Map.
You want to set an application property with <setProperty>.
<setProperty> sets an Exchange property, NOT an application property. With this you can save values in the Exchange of a message.
You want to use "global variables".
You could perhaps use a Spring singleton bean that is a Map. You could then autowire it where you need it, it would be like an application wide available map.
However, think twice why you need this kind of variable. This could also be a symptom of a design problem.
My system is based on camel and use Apache QPID 0.37.0 to consume messages from a remote AMQPS sever. Our system authenticates via a client certificate. Thus I have this piece of configuration:
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg name="remoteURI" value="amqps://some-location:5671?transport.keyStoreLocation=/very/long/path/nnn-openssl.p12&transport.keyStorePassword=*******&transport.trustStoreLocation=/very/long/path/server.keystore&transport.trustStorePassword=*******"/>
</bean>
This is just working fine. However, configuring key/trust store this way (i.e. in the URI) has several drawbacks:
First, it is not easy to read and maintain.
Some components log the URI, so the paths (I can live with it) and the passwords (ouch...) get logged.
I know it's possible to configure via a system property (javax.net.ssl.keyStore, and son on), but it's not an option because different modules may use different key and trust store, and we want to keep them in separate files.
Is there a way to configure those transport properties of JmsConnectionFactory in a different way ?
Something like:
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg name="remoteURI" value="amqps://some-location:5671"/>
<property name="transport.keyStoreLocation" value="/very/long/path/nnn-openssl.p12"/>
...
</bean>
Note that this factory is used in a JMSConfig, which in turn is used within an AMQPComponent:
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration" >
<property name="connectionFactory" ref="jmsConnectionFactory" />
...
</bean>
<bean id="amqp" class="org.apache.camel.component.amqp.AMQPComponent">
<property name="testConnectionOnStartup" value="true"/>
<property name="configuration" ref="jmsConfig" />
...
</bean>
The short answer is no, that's all that class supports. However you could write a configuration bean which has the properties you require, and have that create the bean. Off the top of my head, something like this:
#Configuration
public class QpidConfiguration {
// Add setters for these
private String host;
private int port = 5671;
private String keyStore;
private String keyStorePassword;
private String trustStoreLocation;
private String trustStorePassword;
#Bean
public JmsConnectionFactory createConnectionFactory() {
return new JmsConnectionFactory("amqps://" + host" + ":" + port + "?transport.keyStoreLocation=" + keyStoreLocation + "&transport.keyStorePassword=" + keyStorePassword + "&transport.trustStoreLocation=" + trustStoreLocation + "&transport.trustStorePassword=" + trustStorePassword);
}
}
You probably want to add some parameter validation in there to be safe.
You can then define the bean using more convenient properties.
<bean id="jmsConnectionFactory" class="com.example.QpidConfiguration">
<property name="host" value="some-location"/>
<property name="keyStoreLocation" value="/very/long/path/nnn-openssl.p12"/>
...
</bean>
You can also leverage encrypted property placeholders, if your heart so desires.
As per the documentation - https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Failover#JAX-RSFailover-Code.1, I tried running the following code along with associated configurations, but the circuit breaker mechanism is not opening up once the threshold count for connectivity failures have exceeded. As the circuit stays closed, the invocation attempts are still being accepted which is against expected behaviour.
public class CustomerRestClient {
private CustomerRestClientFactory customerRestClientFactory;
public List<Customer> filterByFirstName(String firstName) {
List<Customer> filteredCustomers = new ArrayList<>();
CircuitBreakerFailoverFeature cbFailoverFeature = new CircuitBreakerFailoverFeature(4, 180000L);
SequentialStrategy strategy = new SequentialStrategy();
cbFailoverFeature.setStrategy(strategy);
List<Feature> featureList = new ArrayList<Feature>();
featureList.add(cbFailoverFeature);
WebClient client = customerRestClientFactory.getClient(featureList).path("/");
// Call service to get all customers
List<Customer> customers = client.get(new GenericType<List<Customer>>() {});
return filteredCustomers;
}
public void setCustomerRestClientFactory(CustomerRestClientFactory customerRestClientFactory) {
this.customerRestClientFactory = customerRestClientFactory;
}
}
public class CustomerRestClientFactory implements InitializingBean {
private List providerList; // Value is injected by Spring
private String serviceUrl; // Value is injected by Spring
public WebClient getClient(List<? extends Feature> featureList) {
if (featureList == null || featureList.isEmpty()) {
throw new IllegalArgumentException("featureList is not initialized.");
}
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
bean.setAddress(serviceUrl);
bean.setServiceClass(WebClient.class);
bean.setProviders(providerList);
bean.setFeatures(featureList);
return bean.createWebClient();
}
}
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd'T'HH:mm:ss"/>
</bean>
</property>
<property name="serializationInclusion">
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
<bean id="jsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider">
<property name="mapper" ref="objectMapper"/>
</bean>
<util:list id="providerList">
<ref bean="jsonProvider" />
<bean name="exceptionHandler" class="com.mycompany.refapp.exception.AppExceptionHandler" />
</util:list>
<bean id="customerRestClientFactory" class="com.mycompany.refapp.client.CustomerRestClientFactory">
<property name="providerList" ref="providerList" />
<property name="serviceUrl" value="${customer.rest.service.url}" />
</bean>
Log containing stack traces (available here).
After a lot of debugging, I came to an understanding that the counter for connection failures never exceeds the threshold limit because the state of the data (including the counter) is specific to each of the WebClient objects, instantiated for each call. I assumed that if the same instance of a WebClient is used across multiple calls that fail, then the counter would have been updated and eventually open the circuit. Please find attached screenshot for details.
I would like to get a second opinion on whether my understanding is correct.
You have opened issue https://issues.apache.org/jira/browse/CXF-7663 in parallel, so I share the response from Colm here:
If you want to use the Circuit-Breaker feature then you need to use
the same Webclient instance for all of the invocations - it won't work
if you are creating a new WebClient per-call. Here's a test that shows
how it works:
https://github.com/coheigea/testcases/blob/218044e3126cff9339e27a69cd8d3c5f3fe308ea/apache/cxf/cxf-failover/src/test/java/org/apache/coheigea/cxf/failover/feature/FailoverTest.java#L90
I have the following scenario:
I have an OSGI bundle that has a service reference defined in the blueprint XML that references an interface in a remote bundle, and a bean that uses one of the impl's methods to populate a Properties object.
Relevant snippet from Bundle #1's XML (the consumer):
...
<!-- other bean definitions, namespace stuff, etc -->
<!-- reference to the fetching service -->
<reference id="fetchingService" interface="company.path.to.fetching.bundle.FetchingService" />
<!-- bean to hold the actual Properties object: the getConfigProperties method is one of the overridden interface methods -->
<bean id="fetchedProperties" class="java.util.Properties" factory-ref="fetchingService" factory-method="getProperties" />
<camelContext id="contextThatNeedsProperties" xmlns="http://camel.apache.org/schema/blueprint">
<propertyPlaceholder id="properties" location="ref:fetchedProperties" />
...
<!-- the rest of the context stuff - routes and so on -->
</camelContext>
Remote Bundle's blueprint.xml:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<cm:property-placeholder id="config-properties" persistent-id="company.path.configfetcher" />
<bean id="fetchingService" class="company.path.to.fetching.bundle.impl.FetchingServiceImpl" scope="singleton" init-method="createLoader" depends-on="config-properties">
<property name="environment" value="${environment}" />
<property name="pathToRestService" value="${restPath}" />
</bean>
<service ref="fetchingService" interface="company.path.to.fetching.bundle.FetchingService" />
<!-- END TESTING -->
</blueprint>
From Impl Class:
public synchronized Properties getProperties() {
if(!IS_RUNNING) {
// timer task that regularly calls the REST api to check for updates
timer.schedule(updateTimerTask, 0, pollInterval);
IS_RUNNING = true;
}
//Map<String, Properties> to return matching object if it's there
if(PROPERTIES_BY_KEY.containsKey(environment)) {
return PROPERTIES_BY_KEY.get(environment);
}
/* if nothing, return an empty Properties object - if this is the case, then whatever bundle is relying on these
* properties is going to fail and we'll see it in the logs
*/
return new Properties();
}
The issue:
I have a test class (extending CamelBlueprintTestSupport) and there are a lot of moving parts such that I can't really change the order of things. Unfortunately, the properties bean method gets called before the CamelContext is started. Not that big a deal because in the test environment there is no config file to read the necessary properties from so the retrieval fails and we get back an empty properties object [note: we're overriding the properties component with fakes since it's not that class being tested], but in a perfect world, I'd like to be able to do two things:
1) replace the service with a new Impl()
2) intercept calls to the getProperties method OR tie the bean to the new service so that the calls return the properties from the fake impl
Thoughts?
Edit #1:
Here's one of the things I'm doing as a workaround right now:
try {
ServiceReference sr = this.getBundleContext().getServiceReference(FetchingService.class);
if(sr != null) {
((FetchingServiceImpl)this.getBundleContext().getService(sr)).setEnvironment(env);
((FetchingServiceImpl)this.getBundleContext().getService(sr)).setPath(path);
}
} catch(Exception e) {
log.error("Error getting Fetching service: {}", e.getMessage());
}
The biggest problem here is that I have to wait until the createCamelContext is called for a BundleContext to exist; therefore, the getProperties call has already happened once. As I said, since in the testing environment no config for the FetchingService class exists to provide the environment and path strings, that first call will fail (resulting in an empty Properties object). The second time around, the code above has set the properties in the impl class and we're off to the races. This is not a question about something that isn't working. Rather, it is about a better, more elegant solution that can be applied in other scenarios.
Oh, and for clarification before anyone asks, the point of this service is so that we don't have to have a .cfg file for every OSGI bundle deployed to our Servicemix instance - this central service will go and fetch the configs that the other bundles need and the only .cfg file that need exist is for the Fetcher.
Other pertinent details:
Camel 2.13.2 - wish it was 2.14 because they've added more property-placeholder tools to that version that would probably make this easier
Servicemix - 5.3.1
Have you tried overriding CamelBlueprintTestSupport's addServicesOnStartup in your test (see "Adding services on startup" http://camel.apache.org/blueprint-testing.html)?
In your case something like:
#Override
protected void addServicesOnStartup(Map<String, KeyValueHolder<Object, Dictionary>> services) {
services.put(FetchingService.class.getName(), asService(new FetchServiceImpl(), null));
}