Ensure ordered shutdown of bundles in karaf - osgi

For a simple use-case, I have two bundles in Karaf as:
Bundle-Shared-Library
Bundle-My-Implementation -> depends on (1) Bundle-Shared-Library, mentioned in blueprint via depends-on attribute of the bean
Steps that I am following:
Load Bundle(1)
Load Bundle(2)
Shutdown karaf
It is evident that (2) is dependent on (1). While shutting down Karaf, Bundle(1) gets removed first, this results in the loss of in-flight messages as it cannot find its dependency and cannot process further.
I tried setting the start level of (1) both higher and lower than that of bundle(2). This did not help.
Also, I tried setting org.apache.aries.blueprint.preemptiveShutdown=false in etc/config.properties. This did not help as well.
Am I missing something here?
-- EDIT 1 --
After looking a bit over here and there, I found out that we can set a custom value for timeout in DefaultShutdownStrategy. So, as a workaround, I have done following:
<bean id="shutdownStrategy" class="org.apache.camel.impl.DefaultShutdownStrategy">
<property name="timeout" value="1" />
</bean>
I understand that this is not a clean and optimal way to do. For the time being, it somehow helps me from losing a lot of in-flight messages.
But, any suggestion or feedback would be great.
-- EDIT 2 -- Adding Blueprint File of Bundle 1
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.3.0"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 https://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
http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.3.0 http://aries.apache.org/schemas/blueprint-cm/blueprint-cm-1.3.0.xsd
">
<!-- persistent-id for shared context -->
<cm:property-placeholder persistent-id="xxx.shared" update-strategy="none" >
<cm:default-properties>
...
</cm:default-properties>
</cm:property-placeholder>
<!--jms broker connection-->
<reference id="jmsProducerConnectionFactory" interface="javax.jms.ConnectionFactory" filter="(osgi.jndi.service.name=jms/xxx.producer)" availability="mandatory" />
<bean id="xxx-producer" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsProducerConnectionFactory"/>
</bean>
<!-- Source DB Reference -->
<reference id="XDataSource" interface="javax.sql.DataSource" filter="(osgi.jndi.service.name=xxx-datasource)" availability="mandatory"/>
<!-- Datawarehouse DB Reference -->
<reference id="dw" interface="javax.sql.DataSource" filter="(osgi.jndi.service.name=xdb-datasource)" availability="mandatory"/>
<bean id="prs" class="org.apache.camel.component.sql.SqlComponent">
<property name="dataSource" ref="XDataSource"/>
</bean>
<bean id="timestamp" class="org.library.shared.TimestampImplementation" destroy-method="synchronize" depends-on="dw">
<argument index="0" ref="dw" />
<argument index="2" value="Orders" />
</bean>
<bean id="shutdownStrategy" class="org.apache.camel.impl.DefaultShutdownStrategy">
<property name="timeout" value="1" />
</bean>
<camelContext id="camel-context" xmlns="http://camel.apache.org/schema/blueprint" depends-on="timestamp">
<packageScan>
<package>org.xyz.orders.routing</package>
</packageScan>
</camelContext>
</blueprint>
The other bundle is simply a collection of few classes (a shared library), which I have included as a maven dependency. There is no blueprint file for that bundle.
Due to organizational issues, I have used dummy names at some places.

Related

Liferay 7 MessageListener osgi module

When I worked with the liferay 6.1 I created an application that received the message.
Java class:
public class MailMessageBus implements MessageListener
\src\main\webapp\WEB-INF\src\META-INF\messaging-spring.xml file:
<beans
default-destroy-method="destroy"
default-init-method="afterPropertiesSet"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="messagingConfigurator" class="com.liferay.portal.kernel.messaging.config.PluginMessagingConfigurator">
<property name="messageListeners">
<map key-type="java.lang.String" value-type="java.util.List">
<entry key="mail-send-message">
<list value-type="com.liferay.portal.kernel.messaging.MessageListener">
<ref bean="messageListener.mail_listener" />
</list>
</entry>
</map>
</property>
<property name="destinations">
<list>
<ref bean="destination.mail"/>
</list>
</property>
</bean>
<!-- Destination class -->
<bean id="destination.mail" class="com.liferay.portal.kernel.messaging.ParallelDestination">
<property name="name" value="mail-send-message" />
</bean>
<!-- Listener class -->
<bean id="messageListener.mail_listener" class="customportlet.AMessageBusListener.MailMessageBus" />
and \src\main\webapp\WEB-INF\web.xml file:
...
<context-param>
<param-name>portalContextConfigLocation</param-name>
<param-value>/WEB-INF/src/META-INF/messaging-spring.xml</param-value>
</context-param>
...
How can I do the same for liferay 7 in the OSGi module? OSGi module does not have a web.xml file.
Thank you very much!
I'm trying to accomplish the same thing, and based on what I've found so far the web.xml is unnecessary. OSGi modules seem to detect spring configuration automatically, according to this resource:
https://docs.spring.io/spring-osgi/docs/current/reference/html/app-deploy.html
Just put your configuration in xml files located at META-INF/spring

deployerConfigContext.xml has no effect

I tried to get a CAS-server up and running using https://github.com/apereo/cas-overlay-template for a side project (I'm a student), but I have never used maven or spring before.
I'm trying to hook my own IPersonAttributeDao into the CAS-server. However, when I put my deployerConfigContext.xml under src/main/webapp/WEB-INF/, nothing actually changed when I repackaged (using the build script) and deployed to tomcat8. (Yes, I did restart tomcat).
Below the contents of my deployerConfigContent.xml file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl">
<property name="credentialsToPrincipalResolvers">
<list>
<bean id="primaryPrincipalResolver"
class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver">
<property name="attributeRepository" ref="attributeRepository"/>
</bean>
<bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver">
<property name="attributeRepository" ref="attributeRepository"/>
</bean>
<bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver">
<property name="attributeRepository" ref="attributeRepository"/>
</bean>
</list>
</property>
<property name="authenticationHandlers">
<list>
<bean id="primaryAuthenticationHandler"
class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
<property name="users">
<map>
<!-- Login stays the default casuser:Mellon, no idea why -->
<entry key="test" value="1234"/>
</map>
</property>
</bean>
<!-- DO NOT EVER PUT THIS BEAN IN PRODUCTION!!! -->
<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler"/>
</list>
</property>
</bean>
<!-- <bean id="attributeRepository" class="class.i.am.trying.to.hook.in">
</bean>-->
<!-- This doesn't seem to work -->
<bean id="attributeRepository"
class="org.jasig.services.persondir.support.StubPersonAttributeDao">
<property name="backingMap">
<map>
<entry key="uid" value="uid" />
<entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
<entry key="groupMembership" value="groupMembership" />
</map>
</property>
</bean>
</beans>
What am I missing?
UPDATE:
I reread the documentation (https://apereo.github.io/cas/5.0.x/), and found that deployerConfigContext.xml was supposed to be in resources, and not in webapp/WEB-INF as I found on the internet. I moved it, and now I'm finally getting errors in the log (which means the file is being read).
Error below:
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.jasig.cas.authentication.PolicyBasedAuthenticationManager] for bean with name 'authenticationManager' defined in class path resource [deployerConfigContext.xml]
I found a reference to PolicyBasedAuthenticationManager in the docs, but trying that gave the same error (with the other classname ofcourse).
Bean classes of enabled beans must be deployed in bean archives.
A library jar, EJB jar, application client jar or rar archive is a
bean archive if it has a file named beans.xml in the META-INF
directory. The WEB-INF/classes directory of a war is a bean archive if
there is a file named beans.xml in the WEB-INF directory of the war. A
directory in the JVM classpath is a bean archive if it has a file
named beans.xml in the META-INF directory.
One suggestion, if you are using Spring, you can also set #Annotation to define beans.

Spring + RMI + transactions + weblogic

We have developed two web services (A,B) with Spring 3, Hibernate 4 & JPA.
Inside a method of service A we need to call to an method of service B. The access is through RMI.
The problem is that the two of them need to be in the same transaction. I think we followed all of the rules dealing with transactions but we cannot rollback the method in service B when service A crashes after method in service B is called.
If an exception is thrown in service A after service B is called the data that service A has changed is rolled back, but not the data changed by service B. It seems that the transaction is renewed in service B and not included in that created in service B.
We use a jndi datasource created in weblogic.
The transactional methods are annotated with:
*#Transactional( readOnly = false, isolation=Isolation.SERIALIZABLE,
rollbackFor=Exception.class, propagation = Propagation.REQUIRED )*
Here is my configuration dealing with transactions:
spring-server.xml (the only data that differs from service to service is the persistence-unit name):
*<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="SAPOY/SANOT" />
</bean>
<bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="allowCustomIsolationLevels" value="true"/>
<property name="globalRollbackOnParticipationFailure" value="true" />
</bean>
<tx:annotation-driven transaction-manager="jtaTransactionManager" proxy-target-class="true" />
<!-- Servicio SAPOY.SANOT -->
<bean id="sanot" class="com.sems.sapoy.sanot.services.impl.Sanot">
<property name="sanotBiz" ref="sanotBiz" />
</bean>*
persistence.xml (the only data that differs from service to service is the persistence-unit name):
*<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="SAPOY/SANOT" transaction-type="JTA">
<description>Unidad de Persistencia del modulo SANOT</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/xaDS</jta-data-source>
<properties>
<!--
################################################################
HIBERNATE
################################################################
-->
<property name="hibernate.archive.autodetection" value="class" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.query.factory_class"
value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.autoReconnect" value="true" />
<property name="hibernate.autoReconnectForPools" value="true" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WeblogicTransactionManagerLookup" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
<!--
################################################################
CONNECTION
################################################################
-->
<property name="hibernate.connection.autocommit" value="false"/>
<!--
################################################################
CACHE
################################################################
-->
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.EhCacheRegionFactory" />
<property name="hibernate.cache.use_query_cache" value="true" />
</properties>
</persistence-unit>
</persistence>*
Your DataSource/TransactionManager configurations are just fine, the only problem is that you call your other service through RMI.
The global transactions must be coordinated from the same running Thread that may enlist one or more Resources (JDBC connections/JMS queues), but it cannot span over multiple threads.
The moment you call a RMI method, that call is going to be served by a RMI server which assigns a working thread to service your RMI request. Even if that method is #Transactional the transaction will be defined at the RMI working thread boundary.
Try removing the RMI call and it will work. Implementing it over multiple servers is not a trivial thing to do. You'd probably have to use something like the Command pattern, so that the Service A can call Service B to undo when Service A fails to commit. Like I said, this is not as trivial as a global XA transaction. It requires careful design and it may lead to inconsistencies to due undos happening after other transaction already used the already committed changes.
For that you need WS-Transactions and a Application server to support it. By itself JTA manages global transactions on a Thread basis. To span transactions over multiple Threads you need a higher-level protocol like WS-Transactions.

Load webserver context.xml using Spring

Fairly new to Spring, so I'm having some trouble with this. I'm trying to use LDAP security with Spring. I can use a properties file I created inside the webapp itself. But what I would like to do is load and read the context.xml file of the server (it has all the values I need for this and other applications).
This is what I have:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="searchContextAttributes" value="true"/>
<property name="contextOverride" value="true"/>
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>/WEB-INF/properties/dataUploadProperties.properties</value>
<value>/WEB-INF/properties/globalProperties.properties</value>
<value>context.xml</value>
</list>
</property>
</bean>
I'm able to load and read the 2 properties files, but the context.xml is not found. Does it need to be the absolute path on the server?
Thanks
Chris
So the first thing I would recommend is to use Spring Security. It has an already build in LDAP support.
but the context.xml is not found
Normally this (reading the context.xml directly) is not the way you should go.
Instead, define some properties and or JNDI resources in the context.xml and then use them in the spring configuration.
For example:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<!-- access via jndi -->
<jee:jndi-lookup id="jndiEmailSession"
jndi-name="java:comp/env/email/session/myEmailSession" />
<!-- direct access for properties required the SERVLET contect property
place older configurer, then it works like properties from normal
property files -->
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"> <property name="locations" value="classpath*:META-INF/spring/*.properties" /> </bean>
<bean class=Demo>
<property name="someString" value="${simpleValue}" />
</bean>
</beans>
context.xml:
<Resource name="email/session/myEmailSession"
type="javax.mail.Session"
auth="Container"
password="secret"
mail.debug="false"
mail.transport.protocol="smtp"
mail.smtp.auth="true"
mail.smtp.user="test#example.com"
mail.smtp.host="mail.example.com"
mail.smtp.from="test#example.com"/>
<Parameter name="simpleValue" value="any" override="false" />

Spring DB2 JPA Entity Manager Problem

I'm trying to configure Spring, JPA and DB2 in order to have the entity manager instance to be used in my spring controllers but according how I have configured Spring this not happens.
These are the two attempts of configuration of spring:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" />
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="em" />
</bean>
<bean id="em"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="fileUtility" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
<property name="database" value="DB2" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
the second is this:
<!-- Entity manager factory bean. -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="Sample" />
</bean>
<!-- Entity manager bean. -->
<bean id="em" factory-bean="entityManagerFactory"
factory-method="createEntityManager" />
and the entity manager is injected in this way:
<bean id="messageService" class="utilities.services.impl.MessageServiceImpl">
<property name="entityManager" ref="em" />
</bean>
but I have always this exception:
Caused by: java.lang.IllegalArgumentException: methods with same signature createEntityManager() but incompatible return types: [interface com.ibm.websphere.persistence.WsJpaEntityManager, interface org.apache.openjpa.persistence.OpenJPAEntityManagerSPI]
I don't know how can be fixed. Has anyone encountered this problem?
Thanks in advance.
[EDIT]
This is my persistence.xml:
<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<persistence-unit name="fileUtility"
transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<mapping-file>META-INF/mapping.xml</mapping-file>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:db2://localhost:50000/db2admin" />
<property name="openjpa.ConnectionDriverName" value="COM.ibm.db2.jdbc.app.DB2Driver" />
<property name="openjpa.ConnectionUserName" value="db2admin" />
<property name="openjpa.ConnectionPassword" value="XXXX" />
<property name="openjpa.FlushBeforeQueries" value="true"/>
<property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
</properties>
</persistence-unit>
<persistence-unit name="fileUtility2" transaction-type="JTA">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>file_ds</jta-data-source>
<mapping-file>META-INF/mapping.xml</mapping-file>
<properties>
<property name="openjpa.Log" value="SQL=TRACE"/>
<property name="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true, PrettyPrintLineLength=72"/>
</properties>
</persistence-unit>
</persistence>
WebSphere has a JPA implementation bundled. So no need to add openjpa to your lib. In fact, WebSphere is using OpenJPA, so you are not losing anything. Look here for more details
When using a jda-data-source, you need to have transaction-type="JTA". Also, you should not specify connection properties - they are specified in the datasource.
And get rid of the <provider> - the document I linked says:
If no JPA provider is configured in the element of the persistence.xml file within an EJB module, the default JPA provider that is currently configured for this server is used
I believe you're doing the wrong configuration, because you're configuring it "à la Tomcat". If you're using a Java EE application server, such as WAS, you should:
In Spring application context xml file
configure the DAO bean by a <bean> definition
configure the JNDI definition for the datasource created in the application server via a
<jee:jndi-lookup>
definition; the
name
attribute should be
persistence/XXX, where XXX shall match the
<persistence-unit name="XXX" transaction-type="JTA">
in persistence.xml file
The id attribute in the
<jee:jndi-lookup id=YYY> should point to the
name=YYY parameter of the Entity Manager definition in the DAO, this is to say,
#PersistenceContext(name=YYY) EntityManager em;
Specify
<tx:annotation-driven /> and
<tx:jta-transaction-manager />
In file
web.xml of your web app you should include a definition using the xml tag
<persistence-unit-ref> whose
<persistence-unit-ref-name> parameter shall be the
persistence/XXX JNDI name as specified in persistence.xml (shown above).
Finally, you should create a JNDI definition in the application server (AS dependant) that defines the JNDI name for the JDBC connection. This name should match the
<jta-data-source> xml tag in the persistence.xml file, and it is the only link between the JPA definition and the JDBC defined in the application server.
To round up:
Application Context Spring file
<bean class="DAO implementation class" />
<jee:jndi-lookup id="YYY" jndi-name="persistence/XXX" />
<tx:annotation-driven />
<tx:jta-transaction-manager />
persistence.xml file
<persistence-unit name="XXX" transaction-type="JTA">
<jta-data-source>jdbc/DSN</jta-data-source>
</persistence-unit>
web.xml file
...
<persistence-unit-ref>
<persistence-unit-ref-name>persistence/XXX</persistence-unit-ref-name>
</persistence-unit-ref>
...
DAO (only #PersistenceContext shown)
...
#PersistenceContext(name = "YYY")
EntityManager em;
...
Application Server: jdbc/DSN links to the connection definition, where the driver for the DBM is. Depends on both the AS and the DBM used.
Thus, you may see the connection between the DAO -> Spring Application Context file -> persistence.xml and web.xml files -> Application Server JNDI names. IF you're using a full Java EE application server (such as WAS, Weblogic or GlassFish) you don't have to use Spring interface modules; only defnitions in the app server (see Spring documentation, section 12.6.3).

Resources