I have multiple provider classes (Provider1 and Provider2), how do I decide what bean I use depending on the input parameter in the Processor class?
public class Processor{
private Provider provider;
public void process(String providerName) throws Exception {
// What should I do here to invoke either provider1 or provider2 depending on the providerName?
provider.doOperation();
}
}
public class Provider1 {
public void doOperation(Exchange exchange) throws Exception {
//Code
}
}
public class Provider2 {
public void doOperation(Exchange exchange) throws Exception {
//Code
}
}
This is the case of Factory pattern. You can create a (ProviderFactory) class, register all the providers and get provider based on value, e.g.:
class ProviderFactory(){
private List<Provider> providers = new ArrayList<>();
public Provider getProvider(String input){
if(input.equals("test1")){
//Find based on criteria
return provider1;
}else if(input.equals("test2")){
//Find based on criteria
return provider2;
}
}
public void registerProvider(Provider provider){
providers.add(provider);
}
}
You can call registerProvider method on application startup and add as many providers as you want. Once that is initialised, you can call getProvider method and return appropriate instance based on some criteria.
Please note that providers doesn't necessarily need to be a list, it can be any data structure. It depends on which structure suits your criteria the best.
Here's documentation/more examples for Factory pattern.
What about somthing like this?
1# into your processor class :
public class Processor{
private Map<Provider> providers;
public void process(String providerName) throws Exception {
Provider provider = providers.get(providerName);
provider.doOperation();
}
}
2# in your spring config:
<bean id="provider1" class="xx.yy.zz.Provider1"/>
<bean id="provider2" class="xx.yy.zz.Provider2"/>
<bean id="processor" class="xx.yy.zz.Processor">
<property name="providers">
<map>
<entry key="provider1" value-ref="provider1" />
<entry key="provider2" value-ref="provider2" />
</map>
</property>
</bean>
now for example if you call processor.process("provider1") it will call provider1.doOperation()
Related
I want to be able to store a Set of fully qualified Class names as a property of a Node. Given this Node:
#NodeEntity
public TestNode {
Set<Class<?>> classSet;
//getters and setters here
}
And the following custom converters:
public class ClassToStringConverter implements Converter<Class<?>, String> {
#Override
public String convert(final Class<?> source) {
return source.getName();
}
}
public class StringToClassConverter implements Converter<String, Class<?>> {
#Override
public String convert(final String source) {
Class<?> returnVal = null;
try {
returnVal = Class.forName(source);
} catch (ClassNotFoundException e) { }
return returnVal;
}
}
I register the converters with Spring context as such:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="my.package.ClassToStringConverter"/>
<bean class="my.package.StringToClassConverter "/>
</set>
</property>
</bean>
Then using my repository, I can properly save and retrieve the Node, and it stores the fully qualified class name as expected using my custom converters. However, I would like to be able to query by a Class name as such in my repository:
#Query("MATCH (m:TestNode) where {0} in m.classSet return m;")
public findByClassInClassSet(Class<?> clazz);
However, this seems to convert the Class using Class.toString() instead of using my Converter. So it is searching for the String "class my.package.TestNode" instead of what the Converter correctly stored as "my.package.TestNode".
Am I missing something here or doing something wrong? How can I benefit from these converters if I can't query using the Class type?
NOTE: Please excuse any typos - this code is on a disconnected network so I couldn't copy paste. If there are any typos, I assure you that is not the problem on my actual code.
Should be fixed in the next milestone release for derived finders.
For your annotated query-method, SDN cannot know what you are referring to with your parameter, so it will not be able to convert it, ever.
I am wondering how to implement batch operations with my insert statements using MyBatis 3 & Spring 3?
For example, here is what is currently being done:
spring.xml:
<bean id="jndiTemplateDatasource" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">${context.factory}</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplateDatasource"/>
<property name="jndiName" value="${connectionpool.jndi}"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test" />
</bean>
MyService.xml:
<insert id="insertMyRecord" parameterType="com.test.MyRecord" >
insert into ... // code removed
</insert>
MyService.java:
public interface MyService {
public void insertMyRecord (MyRecord);
}
MyController.java:
#Controller
public class MyController {
#Autowired
private MyService myService;
#Transactional
#RequestMapping( .... )
public void bulkUpload (#RequestBody List<MyRecord> myRecords) {
for (MyRecord record : myRecords) {
myService.insertMyRecord(record);
}
}
}
Disclaimer: That is just pseudo code for demonstration purposes
So what can I do to turn that into a batch process?
Ideally I want to be able to do it with least "intrusion" into code, i.e. use annotations more preferred, but if not possible what is the next best thing?
Also, this needs to be configured just for this one service, not for everything in the project.
The accepted answer above doesn't actually get you batch mode for MyBatis. You need to choose the proper Executor via ExecutorType.BATCH. That is either passed as a parameter to SqlSession.openSession in standard MyBatis API or, if using MyBatis-Spring, as an option to the SqlSessionTemplate. That is done via:
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<constructor-arg index="1" value="BATCH" />
</bean>
There is nothing else that needs to be done.
This is running and tested example ...
Update multiple rows using batch (ibatis + java )
In this ex. I am updating attending count from table with respective to partyid.
public static int updateBatch(List<MyModel> attendingUsrList) {
SqlSession session = ConnectionBuilderAction.getSqlSession();
PartyDao partyDao = session.getMapper(PartyDao.class);
try {
if (attendingUsrList.size() > 0) {
partyDao.updateAttendingCountForParties(attendingUsrList);
}
session.commit();
} catch (Throwable t) {
session.rollback();
logger.error("Exception occurred during updateBatch : ", t);
throw new PersistenceException(t);
} finally {
session.close();
}
}
Model class where variable is defined :
public class MyModel {
private long attending_count;
private String eid;
public String getEid() {
return eid;
}
public void setEid(String eid) {
this.eid = eid;
}
public long getAttending_count() {
return attending_count;
}
public void setAttending_count(long attending_count) {
this.attending_count = attending_count;
}
}
party.xml code
Actual query where batch execute
<foreach collection="attendingUsrList" item="model" separator=";">
UPDATE parties SET attending_user_count = #{model.attending_count}
WHERE fb_party_id = #{model.eid}
</foreach>
Interface code here
public interface PartyDao {
int updateAttendingCountForParties (#Param("attendingUsrList") List<FBEventModel>attendingUsrList);
}
Here is my batch session code
public static synchronized SqlSession getSqlBatchSession() {
ConnectionBuilderAction connection = new ConnectionBuilderAction();
sf = connection.getConnection();
SqlSession session = sf.openSession(ExecutorType.BATCH);
return session;
}
SqlSession session = ConnectionBuilderAction.getSqlSession();
I'm not sure I understand the question fully correct but I will try to give you my thoughts.
For making the single service I would recommend to generify the service interface:
public void bulkUpload (#RequestBody List<T> myRecords)
Then you can check the type of the object and call the propper mapper repository.
Then you can generify it more by creating a common interface:
public interface Creator<T> {
void create(T object);
}
and extend it by your mapper interface:
public interface MyService extends Creator<MyRecord>{}
Now the most complicated step: you get the object of a particular type, see what exact mapper implements the Creator interface for this class (using java reflection API) and invoke the particular method.
Now I give you the code I use in one of my projects:
package com.mydomain.repository;
//imports ...
import org.reflections.Reflections;
#Repository(value = "dao")
public class MyBatisDao {
private static final Reflections REFLECTIONS = new Reflections("com.mydomain");
#Autowired
public SqlSessionManager sqlSessionManager;
public void create(Object o) {
Creator creator = getSpecialMapper(Creator.class, o);
creator.create(o);
}
// other CRUD methods
#SuppressWarnings("unchecked")
private <T> T getSpecialMapper(Class<T> specialClass, Object parameterObject) {
Class parameterClass = parameterObject.getClass();
Class<T> mapperClass = getSubInterfaceParametrizedWith(specialClass, parameterClass);
return sqlSessionManager.getMapper(mapperClass);
}
private static <T, P> Class<? extends T> getSubInterfaceParametrizedWith(Class<T> superInterface, Class<P> parameterType) {
Set<Class<? extends T>> subInterfaces = REFLECTIONS.getSubTypesOf(superInterface);
for (Class<? extends T> subInterface: subInterfaces) {
for (Type genericInterface : subInterface.getGenericInterfaces()) {
if (!(genericInterface instanceof ParameterizedType)) continue;
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
Type rawType = parameterizedType.getRawType();
if (rawType instanceof Class<?> && ((Class<?>) rawType).isAssignableFrom(superInterface)) {
for (Type type: parameterizedType.getActualTypeArguments()) {
if (type instanceof Class<?> && ((Class<?>) type).isAssignableFrom(parameterType)) {
return subInterface;
}
}
}
}
}
throw new IllegalStateException(String.format("No extension of %s found for parametrized type %s ", superInterface, parameterType));
}
}
Warning! This approach can have bad performance impact so use it in non-performance-critical actions
If you want bulk insert I would recommend to use mybatis foreach for bulk insert as described here.
If you think you don't want to write sql for every type of objects you better use Hibernate or any other advanced ORM. MyBatis is just an SQL mapping interface.
I would like to secure my services layer using Spring Security. As explained in the documentation, I need to use a MethodSecurityInterceptor that will check if the method invocation is allowed.
To decide if a service method invocation is allowed for a given user, affecting a required role to the invoked method (using MethodSecurityMetadataSource) is not enough for me since it also depends on the parameters passed to the method. As suggested in the documentation, I can write a custom AccessDecisionVoter and access the arguments though the secured object (MethodInvocation in this case).
But, my authorization logic is different across the methods. For example, the arguments may be different between multiple methods and the authorization logic will also be different.
I see two options:
I can use conditional logic in the AccessDecisionVoter to determine the invoked method and the authorization logic to use, but it seems to be an ugly solution.
I can define one MethodSecurityInterceptor per method to secure. According to the Spring documentation, a MethodSecurityInterceptor is used to secure many methods, so it makes me thinking there is another way.
The same question exists for access decision after method invocation (using AfterInvocationProvider).
What are the alternatives?
I achieved that by implementing my own AccessDecisionManager that delegates access decisions to my special interface AccessDecisionStrategy:
public interface AccessDecisionStrategy {
void decide(Authentication authentication, MethodInvocation methodInvocation, ConfigAttribute configAttribute);
}
Each access decision strategy represents different way of making access decision.
You can easily implement your own strategy (even in other language - for instance Scala):
public class SomeStrategy implements AccessDecisionStrategy { ...
As you can see, my AccessDecisionManager has a map of strategies. Strategy used by manager is based on annotation argument.
public class MethodSecurityAccessDecisionManager implements AccessDecisionManager {
private Map<String, AccessDecisionStrategy> strategyMap;
public MethodSecurityAccessDecisionManager(Map<String, AccessDecisionStrategy> strategyMap) {
this.strategyMap = strategyMap;
}
#Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
ConfigAttribute configAttribute = getSingleConfigAttribute(configAttributes);
AccessDecisionStrategy accessDecisionStrategy = strategyMap.get(configAttribute.getAttribute());
if (accessDecisionStrategy == null) {
throw new IllegalStateException("AccessDecisionStrategy with name "
+ configAttribute.getAttribute() + " was not found!");
}
try {
accessDecisionStrategy.decide(authentication, (MethodInvocation) object, configAttribute);
} catch (ClassCastException e) {
throw new IllegalStateException();
}
}
private ConfigAttribute getSingleConfigAttribute(Collection<ConfigAttribute> configAttributes) {
if (configAttributes == null || configAttributes.size() != 1) {
throw new IllegalStateException("Invalid config attribute configuration");
}
return configAttributes.iterator().next();
}
#Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
#Override
public boolean supports(Class<?> clazz) {
return clazz.equals(MethodInvocation.class);
}
}
Now when I want to protect my method I put #Secured annotation with argument that is name of the strategy:
#Secured("GetByOwner")
FlightSpotting getFlightSpotting(Long id);
You can implement and configure as many strategies as you want:
<bean id="methodSecurityAccessDecisionManager"
class="some.package.MethodSecurityAccessDecisionManager">
<constructor-arg>
<map>
<entry key="GetByOwner">
<bean class="some.package.GetByOwnerStrategy"/>
</entry>
<entry key="SomeOther">
<bean class="some.package.SomeOtherStrategy"/>
</entry>
</map>
</constructor-arg>
</bean>
To inject that access decision manager you type:
<sec:global-method-security secured-annotations="enabled"
access-decision-manager-ref="methodSecurityAccessDecisionManager">
</sec:global-method-security>
I also implemented helper class to handle MethodInvocation arguments:
import org.aopalliance.intercept.MethodInvocation;
public class MethodInvocationExtractor<ArgumentType> {
private MethodInvocation methodInvocation;
public MethodInvocationExtractor(MethodInvocation methodInvocation) {
this.methodInvocation = methodInvocation;
}
public ArgumentType getArg(int num) {
try {
Object[] arguments = methodInvocation.getArguments();
return (ArgumentType) arguments[num];
} catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
throw new IllegalStateException();
}
}
}
Now you can easily extract interesting arguments in the code of your strategy to make decision:
Let's say I want to get argument number 0 that is of type Long:
MethodInvocationExtractor<Long> extractor = new MethodInvocationExtractor<>(methodInvocation);
Long id = extractor.getArg(0);
You can implement your own method security annotations based on Spring #PreAuthorize("") construction.
To fetch extra information about the method(beyond method argument values) to SpEL evaluation context you can implement your own MethodSecurityExpressionHandler
#Service
public class MySecurityExpressionHandler extends
DefaultMethodSecurityExpressionHandler {
#Override
public StandardEvaluationContext createEvaluationContextInternal(
Authentication auth, MethodInvocation mi) {
StandardEvaluationContext evaluationContext = super
.createEvaluationContextInternal(auth, mi);
SomeMethodInfoData methodInfoData = mi.getMethod(). ...;
evaluationContext.setVariable("someData", <value computed based on method info data>);
}
return evaluationContext;
}
and register it in your global-method-security declaration
<security:global-method-security
pre-post-annotations="enabled">
<security:expression-handler
ref="mySecurityExpressionHandler" />
</security:global-method-security>
Now you can create custom security annotations(and extra process annotation data in MySecurityExpressionHandler if required)
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("#<someData>")
public #interface CustomSecurityAnnotation { ... }
for example you can create a custom annotation to check user roles without messing with strings:
#MyUserRoleCheck(MyAppRole.Admin)
public void someMethod()
I have written a factory bean that creates a cache manager based on the properties that are configured in a application specific properties file.
The concept is that multiple implementations can be chosen, each using other configuration properties.
For example:
noop cache, without parameters,
ehcache with #max objects
memcache with multiple ips and ports configured.
I think it is nice to not specify all cache-application specific parameters in the application-context.xml, but read them from the existing properties sources.
My attempt was using a EnvironementAware interface to get access to the Environement. But it seems that the property file that is configured using <context:property-placeholder> is not contained in the PropertiesSources.
example.properties
cache.implementation=memcached
cache.memcached.servers=server1:11211,server2:11211
application-context.xml
<context:property-placeholder location="example.properties"/>
<bean id="cacheManager" class="com.example.CacheManagerFactory"/>
In CacheManagerFactory.java
public class CacheManagerFactory implements FactoryBean<CacheManager>, EnvironmentAware {
private Environement env;
#Override
public CacheManager getObject() throws Exception {
String impl = env.getRequiredProperty("cache.implementation"); // this fails
//Do something based on impl, which requires more properties.
}
#Override
public void setEnvironment(Environment env) {
this.env = env;
}
#Override
public Class<?> getObjectType() {
return CacheManager.class;
}
#Override
public boolean isSingleton() {
return true;
}
}
In config file like this :
<context:property-placeholder location="classpath:your.properties" ignore-unresolvable="true"/>
...
<property name="email" value="${property1.email}"/>
<!-- or -->
<property name="email">
<value>${property1.email}</value>
</property>
or in code :
#Value("${cities}")
private String cities;
where the your.properties contains this :
cities = my test string
property1.email = answer#stackvoerflow.com
How to conditionally initialization a class via spring?
If some condtion is true then i want one argument to be passed else some other
argument
<bean id="myFactory" class="Factory">
if something then
<constructor-arg>
<util:map>
<!-- configure your map here, or reference it as a separate bean -->
<entry key="java.lang.String" value="key">....</entry>
</util:map>
</constructor-arg>
else
<constructor-arg>
<util:map>
<!-- configure your map here, or reference it as a separate bean -->
<entry key="java.lang.String" value="key">....</entry>
</util:map>
</constructor-arg>
</bean>
How?
Spring Expression Language might do the trick for you. link
You can do it exactly the way that you have specified. Define a FactoryBean this way, say for eg. For generating a Customer Bean:
public class CustomFactoryBean implements FactoryBean<Customer>{
private int customProperty;
public int getCustomProperty() {
return customProperty;
}
public void setCustomProperty(int customProperty) {
this.customProperty = customProperty;
}
#Override
public Customer getObject() throws Exception {
if (customProperty==1)
return new Customer("1", "One");
return new Customer("999", "Generic");
}
#Override
public Class<?> getObjectType() {
return Customer.class;
}
#Override
public boolean isSingleton() {
return true;
}
}
That is basically it, now based on how you inject in th properties of the factory bean, the actual bean instantiation can be controlled in the getObject method above