Remove _class from mongodb document - java

We all know if we are trying to add a document via spring-mvc to mongodb, spring adds _class to track & facilitate future marshalling/unmarshalling of the document. In cases in becomes a overhead and one might want not to include _class in mongodb. The following simple spring config helps to avoid adding the _class in mongodb.
<bean id="defaultTypeMapper"
class="org.springframework.data.mongodb.core.convert.DefaultTypeMapper">
<property name="typeKey"><null/></property>
</bean>
<bean id="defaultMongoConverter"
class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mappingContext" />
<property name="typeMapper" ref="defaultTypeMapper"></property>
</bean>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mongoConverter" ref="defaultMongoConverter" />
<property name="writeResultChecking" value="EXCEPTION" />
</bean>
One can easily find the config for mongodbFactory and mappingContext. So I have not added it here. Note the way I have included typeKey.

The question is: how to suppress the _class entry that the spring framework adds to MongoDB objects to support polymorphism. If you don't need polymorphism support, _class wastes spaces and introduces issues if you refactor your POJO / model classes to different packages.
The above example was close, but has a few errors (e.g. DefaultTypeMapper should be DefaultMongoTypeMapper and typeKey is a constructor-arg, not set as a property).
The following works for me...
<mongo:mongo host="hostname" port="27017">
<mongo:options
...options...
</mongo:mongo>
<mongo:db-factory dbname="blee" username="blee" password="blee" mongo-ref="mongo"/>
<bean id="mongoTypeMapper" class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper">
<constructor-arg name="typeKey"><null/></constructor-arg>
</bean>
<bean id="mongoMappingContext" class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
<bean id="mongoConverter" class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mongoMappingContext" />
<property name="typeMapper" ref="mongoTypeMapper"></property>
</bean>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mongoConverter" />
<property name="writeResultChecking" value="EXCEPTION" />
</bean>

Related

Spring SAML cant read property from properties file

So this one stumps me. I have been using properties files for years now, but I have never seen this.
I am using Spring MVC with SAML authentication. my context xml has this in it:
<context:property-placeholder location="file:/opt/saml.properties" />
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="file:/opt/mySamlKeystore.jks"/>
<constructor-arg type="java.lang.String" value="${keystore.password}"/>
<constructor-arg>
<map>
<entry key="${privateKey.alias}" value="${key.password}"/>
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="${privateKey.alias}"/>
</bean>
I am getting this error:
java.security.UnrecoverableKeyException: Cannot recover key
I so some SO research and they all say basically that I have the wrong password, which im sure I don't. So to test that it's reading the right file, I go and replace all the properties %{} and hard code them. Everything then works fine.
I am trying to figure this out, when I noticed that some of the other properties from that file are working! In fact, I can even do this:
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="file:/opt/myKeystore.jks"/>
<constructor-arg type="java.lang.String" value="${keystore.password}"/>
<constructor-arg>
<map>
<entry key="${privateKey.alias}" value="password"/>
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="${privateKey.alias}"/>
</bean>
So spring is getting ${keystore.password} and ${privateKey.alias} (Along with others needed like entityID, metadataProvider, etc...) from the properties file, but not ${key.password} !!!
here is the saml.properties
#keystore stuff
keystore.password=password
key.password=password
privateKey.alias=mysaml
#SP stuff (aka, my side of things)
entity.id=mycompany:me:me:me1
entity.base.url=https://mycompany.com
#IDP stuff (aka, the SAML server)
metadata.provider=https://saml.mycompany.com/FederationMetadata/2007-06/FederationMetadata.xml
This is all working when I hard coded the key password, but not when I use the ${key.password} property. What is going on here?
you have two more slash after file
For example
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="file:///opt/myKeystore.jks"/>
<constructor-arg type="java.lang.String" value="${keystore.password}"/>
<constructor-arg>
<map>
<entry key="${privateKey.alias}" value="password"/>
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="${privateKey.alias}"/>
</bean>

How can I inject Mongo options while initializing MongoClient in Spring core without annotation?

I want to initialize MongoDB cluster connection pool with replica set name so that in case my primary fails and other machine in cluster becomes primary then it should work, something like below :
MongoClientOptions options = MongoClientOptions.builder()
.requiredReplicaSetName("ReplicaSetName").
build();
ServerAddress serverAddress1 = new ServerAddress("192.168.5.5");
ServerAddress serverAddress2 = new ServerAddress("192.168.5.6"); List<ServerAddress> seeds = new ArrayList<>();
seeds.add(serverAddress1);seeds.add(serverAddress2);
MongoClient mongoClient = new MongoClient(seeds,options);
Above code works perfectly but I want to do the same in Spring context.xml.
Currently my application context look like this :
<bean id="mongoServerAddr1" class="com.mongodb.ServerAddress">
<constructor-arg name="host" value="${MONGO_CLUSTER1_HOST1}" />
<constructor-arg name="port" value="${MONGO_CLUSTER1_PORT1}" />
</bean>
<bean id="mongoServerAddr2" class="com.mongodb.ServerAddress">
<constructor-arg name="host" value="${MONGO_CLUSTER1_HOST2}" />
<constructor-arg name="port" value="${MONGO_CLUSTER1_PORT2}" />
</bean>
<util:list id="mongoHostList" value-type="com.mongodb.ServerAddress">
<ref bean="mongoServerAddr1" />
<ref bean="mongoServerAddr2" />
</util:list>
<bean id="mongoCredentialIDCluster1" class="com.mongodb.MongoCredential" factory-method="createScramSha1Credential">
<constructor-arg type="java.lang.String" name="userName" value="${MONGO_CLUSTER1_USER1}" />
<constructor-arg type="java.lang.String" name="source" value="${MONGO_CLUSTER1_SOURCE1}" />
<constructor-arg type="char[]" name="password" value="${MONGO_CLUSTER1_PASS1}" />
</bean>
<bean id="mongoCredentialIDCluster2" class="com.mongodb.MongoCredential" factory-method="createScramSha1Credential">
<constructor-arg type="java.lang.String" name="userName" value="${MONGO_CLUSTER1_USER2}" />
<constructor-arg type="java.lang.String" name="source" value="${MONGO_CLUSTER1_SOURCE2}" />
<constructor-arg type="char[]" name="password" value="${MONGO_CLUSTER1_PASS2}" />
</bean>
<util:list id="mongoCredentialList" value-type="com.mongodb.MongoCredential">
<ref bean="mongoCredentialIDCluster1" />
<ref bean="mongoCredentialIDCluster2" />
</util:list>
<bean id="mongoClient" class="com.mongodb.MongoClient">
<constructor-arg name="seeds" ref="mongoHostList" />
<constructor-arg name="credentialsList" ref="mongoCredentialList" />
</bean>
<bean id="mongoDao" class="com.dao.MongoDaoImpl">
<constructor-arg ref="mongoClient" />
</bean>
How can I achieve this ?
I have solve this problem with MongoClientURI class.
Config details:
MONGO_URI=mongodb://user:password#192.168.50.167:27017,192.168.50.169:27017/?authSource=admin&replicaSet=ReplicaSetName
This is my application context configuration:
<bean id="mongoURI" class="com.mongodb.MongoClientURI">
<constructor-arg name="uri" value="${MONGO_URI}" />
</bean>
<bean id="mongoCLIENT" class="com.mongodb.MongoClient">
<constructor-arg ref="mongoURI" />
</bean>
<bean id="mongoDao" class="com.dao.MongoDaoImpl">
<constructor-arg ref="mongoCLIENT" />
</bean>
A possible solution can be found here:
The example in the Spring Docs is:
Code
<beans>
<mongo:mongo-client host="localhost" port="27017">
<mongo:client-options connections-per-host="8"
threads-allowed-to-block-for-connection-multiplier="4"
connect-timeout="1000"
max-wait-time="1500}"
auto-connect-retry="true"
socket-keep-alive="true"
socket-timeout="1500"
slave-ok="true"
write-number="1"
write-timeout="0"
write-fsync="true"/>
</mongo:mongo-client>
</beans>
Replica Set XML Example
<mongo:mongo-client id="replicaSetMongo" replica-set="127.0.0.1:27017,localhost:27018"/>
Hope this helps.

Spring Batch - Erro Config XML job - Date

I have a procedure in sql waiting three parameters. The first 2 parameters are dates and last a cursor.
How do I configure the XML job Spring Batch
I tried so
<bean id="databaseItemReader" class="org.springframework.batch.item.database.StoredProcedureItemReader">
<property name="dataSource" ref="dataSource" />
<property name="procedureName" value="MyProcedureSQL" />
<property name="fetchSize" value="50" />
<property name="parameters">
<list>
<bean class="org.springframework.jdbc.core.SqlParameter">
<constructor-arg index="0" value="P_INICIO"/>
<constructor-arg index="1">
<util:constant static-field="java.sql.TYPES.Date"/>
</constructor-arg>
</bean>
<bean class="org.springframework.jdbc.core.SqlParameter">
<constructor-arg index="0" value="P_TERMINO"/>
<constructor-arg index="1">
<util:constant static-field="java.sql.TYPES.Date"/>
</constructor-arg>
</bean>
<bean class="org.springframework.jdbc.core.SqlParameter">
<constructor-arg index="0" value="P_RESULT"/>
<constructor-arg index="1">
<util:constant static-field="java.sql.Types.int"/>
</constructor-arg>
</bean>
</list>
</property>
<property name="rowMapper">
<bean class="main.java.br.com.util.DataEmployeeMapper" />
</property>
<property name="refCursorPosition" value="3"/>
<property name="preparedStatementSetter" ref="preparedStatementSetter" />
</bean>
It appears the error
Invocation of init method failed; nested exception is java.lang.NoSuchFieldException: Date
In this variation I have also tried
<util:constant static-field="java.sql.Date"/>
<util:constant static-field="java.sql.Types.timeStamp"/>
How do I set to send the two dates for procedure?
It may help to change use argument names instead of 'index' in the constructor-arg element, to debug this. e.g. change
<constructor-arg index="1">
<util:constant static-field="java.sql.TYPES.Date"/>
</constructor-arg>
to this
<constructor-arg name="sqlType">
<util:constant static-field="java.sql.TYPES.Date"/>
</constructor-arg>
I suspect you there may be some ambiguity around what constructor is called and how the argument types are interpreted

How to create and config an inner builder class with spring

I am trying to springify the following code snippet:
MongoClient mongoClient = new MongoClient("127.0.0.1", 27017);
DB db = mongoClient.getDB("jcr");
DocumentNodeStore ns = new DocumentMK.Builder().setMongoDB(db)
.getNodeStore();
Repository repo = new Jcr(new Oak(ns)).createRepository();
taken from Oak website : http://jackrabbit.apache.org/oak/docs/construct.html
The problem line is:
DocumentNodeStore ns = new DocumentMK.Builder().setMongoDB(db)
.getNodeStore();
Here is how I have configured it within the xml:
<bean id="builder" class="org.apache.jackrabbit.oak.plugins.document.DocumentMK$Builder">
</bean>
<bean factory-bean="builder" factory-method="setMongoDB" >
<constructor-arg name="db" value="#{mongoDbTags.getDb()}"/>
</bean>
I have configured a SimpleMongoDbFactory and obtaining the db to be injected into the builder bean calling the setMethod via factory method.
Please note this does not exist as an attribute under the builder Class but the method does exist.
here is my config file:
<bean id="mongo" class="com.mongodb.MongoClient">
<constructor-arg name="host" value="localhost" />
<constructor-arg name="port" value="27017" />
</bean>
<bean id="mongoDbTags" class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
<constructor-arg name="mongo" ref="mongo" />
<constructor-arg name="databaseName" value="jcr111" />
</bean>
<bean id="builder" class="org.apache.jackrabbit.oak.plugins.document.DocumentMK$Builder">
</bean>
<bean factory-bean="builder" factory-method="setMongoDB" >
<constructor-arg name="db" value="#{mongoDbTags.getDb()}"/>
</bean>
<bean id="documentMK" class="org.apache.jackrabbit.oak.plugins.document.DocumentMK">
<constructor-arg name="builder" ref="builder" />
</bean>
<bean id="oak" class="org.apache.jackrabbit.oak.Oak">
<constructor-arg name="store" value="#{builder.getNodeStore()}" />
</bean>
<bean id="jcr" class="org.apache.jackrabbit.oak.jcr.Jcr">
<constructor-arg name="oak" ref="oak" />
</bean>
<bean id="jcrSessionFactory"
class="org.springframework.extensions.jcr.JcrSessionFactory">
<property name="repository" value="#{jcr.createRepository()}" />
<property name="credentials">
<bean class="javax.jcr.SimpleCredentials">
<constructor-arg index="0" value="admin" />
<constructor-arg index="1" value="admin" />
</bean>
</property>
</bean>
<bean id="jcrTemplate" class="org.springframework.extensions.jcr.JcrTemplate">
<property name="sessionFactory" ref="jcrSessionFactory" />
<property name="allowCreate" value="true" />
</bean>
For others that get stuck in this I simply created a wrapper class which called the builder from within it's constructor

Transactions in Apache Jackrabbit and Spring

I want to run transactions on my Spring webapp which uses Apache Jackrabbit repository. JackRabbit then uses relational database (MySQL/PgSQL) for text data. Binary data are stored to FileSystem.
So far I have this functional configuration of Jackrabbit beans:
<bean id="sessionFactory" class="com.example.MyJcrSessionFactory">
<constructor-arg index="0" ref="repository"/>
<constructor-arg index="1" ref="jcrCredentials"/>
</bean>
<bean id="repository" class="org.apache.jackrabbit.core.RepositoryImpl">
<constructor-arg index="0" ref="config" />
</bean>
<bean id="config" class="org.apache.jackrabbit.core.config.RepositoryConfig" factory-method="create">
<constructor-arg index="0" type="java.io.InputStream" value="classpath:jackrabbit/repository.xml"/>
<constructor-arg index="1" type="java.lang.String" value="/tmp/repository" />
</bean>
<bean id="jcrCredentials" class="javax.jcr.SimpleCredentials">
<constructor-arg index="0" type="java.lang.String" value="..." />
<constructor-arg index="1" type="char[]" value="..." />
</bean>
And rest of Jackrabbit configuration in repository.xml file.
What do I have to do to successfully run transactions on JackRabbit repository? Which technology am I supposed to use?
I'm running Spring 3.1, Jackrabbit 2.3.3 on Tomcat/Glassfish. And I don't want to use obsolete spring modules.
We're using a similar setup (Jackrabbit, Spring, Tomcat) with Jencks as a JCA provider.
Here's an example config:
<bean id="txManagerJencks" class="org.jencks.factory.TransactionManagerFactoryBean" />
<bean id="pooledConnectionManagerJcr" class="org.jencks.factory.ConnectionManagerFactoryBean">
<property name="transactionManager">
<ref local="txManagerJencks" />
</property>
<property name="transaction" value="xa" />
<property name="poolMinSize" value="1"/>
<property name="poolMaxSize" value="5"/>
<property name="connectionMaxIdleMinutes" value="5" />
</bean>
<bean id="repositoryManagedConnectionFactory" class="org.apache.jackrabbit.jca.JCAManagedConnectionFactory" destroy-method="finalize">
<property name="homeDir" value="${jackrabbit.homeDir}/jackrabbit" />
<property name="configFile" value="classpath:repository.xml" />
</bean>
<bean id="repository"
class="org.springframework.jca.support.LocalConnectionFactoryBean" >
<property name="managedConnectionFactory">
<ref local="repositoryManagedConnectionFactory" />
</property>
<property name="connectionManager">
<ref local="pooledConnectionManagerJcr" />
</property>
</bean>

Categories