I have an unsatisfied osgi service:
ls 142
Components in bundle A:
ID State Component Name Located in bundle
90 Unsatisfied ServiceA A(bid=142)
The reference to ServiceB is unsatisfied:
comp 90
Component[
name = ServiceA
activate = activate
deactivate = deactivate
modified =
configuration-policy = optional
factory = null
autoenable = true
immediate = false
implementation = ServiceA
state = Unsatisfied
properties =
serviceFactory = false
serviceInterface = [ServiceA]
references = {
Reference[name = ServiceB, interface = ServiceB, policy = static, cardinality = 1..1, target = null, bind = setServiceB, unbind = unsetServiceB]
}
located in bundle = B_2.12.0.qualifier [142]
]
Dynamic information :
*The component is NOT satisfied
The following references are not satisfied:
Reference[name = ServiceB, interface = ServiceB, policy = static, cardinality = 1..1, target = null, bind = setServiceB, unbind = unsetServiceB]
Component configurations :
Configuration properties:
component.name = ServiceA
component.id = 136
objectClass = String[ServiceA]
Instances:
Nevertheless, ServiceB is active:
ls 52
Components in bundle B:
ID State Component Name Located in bundle
14 Active ServiceB B(bid=52)
So why is the reference from ServiceA to ServiceB unsatisfied? A restart of bundle A (stop and start) doesn't help. Configuring the reference on a working ServiceC in bundle C makes ServiceC unsatisfied.
Update: ServiceB has been registered
The result of the "services" command in the osgi console contains the following nipped:
{ServiceB}={service.id=180}
Registered by bundle: Z_2.12.0.qualifier [123]
No bundles using service.
Additional information: configuration, initialization and registration of ServiceA and ServiceB
ServiceB is basically an apache cxf web service, that's implementing an interface. This interface has been generated out of a wsdl. The ServiceB is registered programmatically. ServiceA has a reference to the generated interface. This pattern works perfectly with another web service (lets say ServiceC and ServiceD).
And if it helps: This pattern even worked between ServiceA and ServiceB until we upgraded apache cxf. I didn't provide this information before because I feared it would make this problem too complicated 😕.
Update: configuration of the component ServiceB
There are two parts considering the configuration: The xml file and the registration. The xml file contains the implementation class "WebServiceConfigImpl", a provided interface "WebServiceConfig" and some properties. One of the properties is the webservice "ServiceB" - the name under that the service is registered programmatically later in the start procedure.
xml file:
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" deactivate="deactivate" name="ServiceB">
<implementation class="WebServiceConfigImpl"/>
<service>
<provide interface="WebServiceConfig"/>
</service>
<property name="webservice" type="String" value="ServiceB"/>
<property name="address" type="String" value="${adresse}"/>
<property name="username" type="String" value="${benutzer}"/>
<property name="password" type="String" value="${passwort}"/>
(...)
two references to other osgi services for resolving the web service configuration
</scr:component>
registration:
We are using our own org.osgi.util.tracker.ServiceTracker for this. This ServiceTracker is opened in the Activator of bundle Z. It calls the constructor of ServiceTracker with "WebServiceConfig" as parameter, so this ServiceTracker is notified if a Service providing the interface "WebServiceConfig" has been registered. Our implementation of the SeriveTracker now reads the property "webservice" and publishs the osgi service under this name:
context.registerService(serviceName, service, null);
After that, the service is available and activated in the osgi console.
Update: accessing ServiceB
After the registration through our ServiceTracker, ServiceB is available through the osgi console AND by source code:
ServiceTracker st = new ServiceTracker(bundleContext, "ServiceB", null);
st.open();
st.getService();
Update: accessing ServiceB 2
ServiceB is accessible via source code in bundle Z. But it cannot be accessed via source code from bundle A. Then the service object is null.
I found a workaround to get programmatically access to ServiceB:
ServiceTracker st = new ServiceTracker(context, ServiceB.class.getName(), null);
st.open(true);
st.getService()
The boolean parameter in the open method makes the difference.
Unfortunatelly I wasn't able to answer the question why some bundles have "direct" access to the ServiceB (no parameter in the open method needed) and some need the "true" parameter.
Related
I am writing client-server application on base of int-ip:tcp endpoints. Code written in Kotlin.
Application contains two tcp clienst which should make connection to server in sertain sequence,
one after each other, when first cleint already establised connection to server and made some initialisation.
As a solution for this synchronisation I suppose to use a SmartLifecycleRoleController to start group of endpoints of a dependent tcp client.
To that end in depended (second) client I add role="rcCluster" and auto-startup="false" attributes to tcp-outbound-channel-adapter and tcp-inbound-channel-adapter
<int-ip:tcp-connection-factory id="rcClientConnectionFactory"
type="client"
host="${tdirelay.host}"
port="${tdirelay.rcPort}"
single-use="false"
so-timeout="10000"
so-keep-alive="false"
serializer="rawSerializerDeserializer"
deserializer="rawSerializerDeserializer"
ssl-context-support="sslContext"/>
<int-ip:tcp-outbound-channel-adapter id="rcOutBoundAdapter"
channel="rcPacketQueueChannel"
phase="5000"
connection-factory="rcClientConnectionFactory"
role="rcCluster"
auto-startup="false"
/>
<int-ip:tcp-inbound-channel-adapter id="rcInboundAdapter"
channel="rcFromServer"
client-mode="true"
retry-interval="5000"
connection-factory="rcClientConnectionFactory"
role="rcCluster"
auto-startup="false"
/>
The leading (first) tcp client uses interceptor endpoint to make a prologue exhange with server in accordance with the protocol:
<bean id="dcInterceptorFactoryChain"
class="org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactoryChain">
<property name="interceptors">
<array>
<bean class="com.tcpclient.DirectCannel.DCConnectionInterceptorFactory">
</bean>
</array>
</property>
</bean>
<int-ip:tcp-connection-factory id="dcClientConnectionFactory"
type="client"
host="${tdirelay.host}"
port="${tdirelay.dcPort}"
single-use="false"
so-timeout="10000"
so-keep-alive="false"
interceptor-factory-chain="dcInterceptorFactoryChain"
serializer="rawSerializerDeserializer"
deserializer="rawSerializerDeserializer"
ssl-context-support="sslContext"
/>
I am planning to call startLifecyclesInRole(String role) and stopLifecyclesInRole(String role) methods of the SmartLifecycleRoleController inside my Interceptor class.
So, I added #Autowired private val roleController: SmartLifecycleRoleController to InterceptorFactory as explained in spring-integration/docs
My InterceptorFactory is:
class DCConnectionInterceptorFactory() : TcpConnectionInterceptorFactory, ApplicationEventPublisherAware {
#Autowired
private val roleController: SmartLifecycleRoleController? = null
#Volatile
private var applicationEventPublisher: ApplicationEventPublisher? = null
override fun setApplicationEventPublisher(applicationEventPublisher: ApplicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher
}
override fun getInterceptor(): TcpConnectionInterceptorSupport {
return DCConnectionInterceptor(this.applicationEventPublisher!!, roleController!!)
}
}
IntelliJ IDEA gives warning:
Could not autowire. No beans of 'SmartLifecycleRoleController' type found
And building gives error:
[task-scheduler-2] ERROR org.springframework.integration.ip.tcp.connection.ClientModeConnectionManager - Could not establish connection using dcClientConnectionFactory, host=localhost, port=9001
kotlin.KotlinNullPointerException
at com.tcpclient.DirectCannel.DCConnectionInterceptorFactory.getInterceptor(DCConnectionInterceptorFactory.kt:25)
I suppose that I need to define SmartLifecycleRoleController type bean in xml configuration file
(that is not mentioned in the docs: https://docs.spring.io/spring-integration/docs/4.3.4.RELEASE/reference/html/messaging-endpoints-chapter.html#endpoint-roles).
The constructor of this class has arguments:
public SmartLifecycleRoleController(List roles, List lifecycles)
which I do not know how to fill in my case in xml file:
If you know how to do this, please provide a live example of using bean of the SmartLifecycleRoleController class in the xml configuration file.
First of all it would be better do not use #Autowired there at all, since it isn't clear if an annotation configuration is enabled in your application context or not. Just because you show only XML config for Spring.
Therefore your DCConnectionInterceptorFactory should have a setter for that roleController property instead. Or what is the proper way to declare Java bean properties in Kotlin...
Then you need to use something like this in your XML config:
<bean class="com.tcpclient.DirectCannel.DCConnectionInterceptorFactory">
<property name="roleController" ref="integrationLifecycleRoleController"/>
</bean>
The Framework creates for your a SmartLifecycleRoleController automatically and registers it with the mentioned IntegrationContextUtils.INTEGRATION_LIFECYCLE_ROLE_CONTROLLER bean name.
Please, raise a JIRA on the matter to improve documentation to make since much cleaner.
Your approach, by the way, is correct.
I need to call Idempiere Business Modules (ex. Creating Purchase Order process) , not tables via a web services, Is there any way to do this without going through the source code of Idempiere, I don't want to use RESTful methods that will deal with tables directly
You are probably referring to improvements on iDempiere's Web Services where composite (master-detail) and CRUD actions are now possible. Complete description at the project wiki: http://wiki.idempiere.org/en/NF1.0_Web_Services_Improvements
Below I paste results of https://test.idempiere.org/ADInterface/services
Available SOAP services:
CompositeService
compositeOperation
Endpoint address: http://test.idempiere.org/ADInterface/services/compositeInterface
WSDL : {http://idempiere.org/ADInterface/1_0}compositeInterface
Target namespace: http://idempiere.org/ADInterface/1_0
ModelADService
setDocAction
createUpdateData
getList
readData
createData
runProcess
queryData
deleteData
updateData
Endpoint address: http://test.idempiere.org/ADInterface/services/ModelADService
WSDL : {http://idempiere.org/ADInterface/1_0}ModelADService
Target namespace: http://idempiere.org/ADInterface/1_0
Available RESTful services:
Endpoint address: http://test.idempiere.org/ADInterface/services/rest
WADL : http://test.idempiere.org/ADInterface/services/rest?_wadl
You can use create a provide service interface from org.adempiere.base plugin, invoke this service inside your code and invoke the constructor for class MOrder extends X_C_Order and for class MOrderLine extends X_C_OrderLine.
Here you have the example from IProcessFactory (you can create your factory like ICreateOrderFactory , or just IInsertFactory ( for a generic factory constructor you can set the table id ) :
This is a interface declaration
public interface IProcessFactory {
/**
* Create new process instance
* #param className
* #return new process instance
*/
public ProcessCall newProcessInstance(String className);
}
This is a evocation method
public class ProcessFactory implements IProcessFactory {
#Override
public ProcessCall newProcessInstance(String className) {
if (className.equals("com.com.nexus.webservice.client.process.IntegratorWS"))
return new IntegratorWS();
else
return null;
}
}
Now you need to create .xml of this factory like that : (pay attention in provided interface)
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.nexus.integrator.ProcessFactory">
<implementation class="com.nexus.webservice.client.process.ProcessFactory"/>
<property name="service.ranking" type="Integer" value="5"/>
<service>
<provide interface="org.adempiere.base.IProcessFactory"/>
</service>
</scr:component>
To use this in OSGI architecture, you need to configure your MANIFEST file to import this
Service-Component: ( I always use osgi-inf directory for my factories xml)
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: com.nexus.webservice.client
Bundle-SymbolicName: com.nexus.webservice.client;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: Macrosoftware
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.adempiere.base
Service-Component: OSGI-INF/ProcessFactory.xml
Import-Package: org.osgi.framework
You can do this , or you can use composite webservice .
I consider the second most safe and effective method
Is it possible to configure the queue names and corresponding receiver methods in Resources.groovy file? Will the jms plugin pick it up?
What will be the format of below code that can be added to Resources.groovy file?
Following is specified in Springs docs:
<jms:listener-container connection-factory="myConnectionFactory"
task-executor="myTaskExecutor"
destination-resolver="myDestinationResolver"
transaction-manager="myTransactionManager"
concurrency="10">
<jms:listener destination="queue.orders" ref="orderService" method="placeOrder"/>
<jms:listener destination="queue.confirmations" ref="confirmationLogger" method="log"/>
</jms:listener-container>
http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/jms.html
With "JMS plugin" this is not necessary. You can just use the annotation, like the plugin doc sample ("Topic Listener" session), in your consumer.
Sample (assuming that your factory was properly config in resources.groovy):
class ConsumerService {
boolean transactional = false
static exposes = ['jms']
#Subscriber(topic = "my.topic")
def onMessage(it) {
println "Topic ... $it"
}
}
I am new to Spring framework and confused how to load properties of a bean ( Instance variables of a bean ) dynamically . Spring expects to use xml based configuration for declaring all the beans and dependencies between beans .
For example ,
public class Bean1
{
int value;
public void setValue(int thisValue)
{
value = thisValue;
}
}
<bean id = "LibraryMgmtBean" class = "Bean1">
<property name = "value" Value = "SampleString"/> </bean>
But here we are mentioning all the properties of a bean statically . But , what if I want to supply these values dynamically . I mean , I may get values from a JSP page from weblayer and should pass to this bean . And as all beans are declard in XML this way , how Spring Injects dependecies of other beans when all bean properties are supplied dynamically ?
Found answers to my question from threads:
How to collect spring properties from multiple files for use on a single bean
Apply dynamic properties to a bean at runtime
Loading Properties with Spring (via System Properties)
I have following code inside my class
public void startListeners() throws Exception {
List<QueueConfiguration> queueConfigs = queueConfigResolver.getQueueConfigurations();
for(QueueConfiguration queueConfig : queueConfigs){
//TODO : work on this make it more testable
ICustomListener readerListener = new MyCustomListener(queueConfig);
readerListeners.add(readerListener);
readerListener.start();
}
}
I am using Spring for dependency injection(not in this case but overall). Now there two problems with this code.
I cannot put mock for each of the listeners created, while testing.
I dont want to use ApplicationContext.getBean() because it will have same affect. AFAIK spring cannot do this dynamically , but any other pointers?
As far as I can understand, you want to create a new bean instead of
ICustomListener readerListener = new MyCustomListener(queueConfig);
If that is the case, creating a factory for mycustomlistener and using
public abstract TestClient createTestClient();
to create your beans, and defining
<bean id="testClient" class="com.myproject.testbeans.TestClient" scope="prototype">
</bean>
<bean id="testClientFactory" class="com.myproject.testbeans.TestClientFactory">
<lookup-method name="createTestClient" bean="testClient" />
</bean>
in your context will solve your problem. This way, every time the createTestClient method of the factory is called, a new bean is created and given to your code. However, you have to give the config object via a setter instead of the constructor.