I am working in Scout and need SmartField. For this I need to set up lookup for suggestions.
I see the example with creating Lookup Call and than implement in Lookup Service getConfiguredSqlSelect
but I use Hibernate to work with classes, so my question is how to connect Smart field with Hibernate object filled service?
create a new lookup call according to [1] with the following differences:
don't select AbstractSqlLookupService as a lookup servic super type, but AbstractLookupService
in the associated lookup service you now need to implement getDataByAll, getDataByKey, and getDataByText
to illustrate the following snippet should help:
public class TeamLookupService extends AbstractLookupService<String> implements ITeamLookupService {
private List<ILookupRow<String>> m_values = new ArrayList<>();
public TeamLookupService() {
m_values.add(new LookupRow<String>("CRC", "Costa Rica"));
m_values.add(new LookupRow<String>("HON", "Honduras"));
m_values.add(new LookupRow<String>("MEX", "Mexico"));
m_values.add(new LookupRow<String>("USA", "USA"));
}
#Override
public List<? extends ILookupRow<String>> getDataByAll(ILookupCall<String> call) throws ProcessingException {
return m_values;
}
#Override
public List<? extends ILookupRow<String>> getDataByKey(ILookupCall<String> call) throws ProcessingException {
List<ILookupRow<String>> result = new ArrayList<>();
for (ILookupRow<String> row : m_values) {
if (row.getKey().equals(call.getKey())) {
result.add(row);
}
}
return result;
}
...
[1] https://wiki.eclipse.org/Scout/Tutorial/4.0/Minicrm/Lookup_Calls_and_Lookup_Services#Create_Company_Lookup_Call
Related
To make things short I'm trying to implement a custom FilterInvocationSecurityMetadataSource in order to secure/authorize certain parts/URL endpoints dynamically in my web app using spring security 5.0.6 and Spring Boot 2.0.3.
The issue is that no matter what Role I use it always gives me the forbidden page.
I have tried several things with different role names and (believe me) I have searched the whole internet even on spring security 5.0.6 books but nothing seems to work.
This issue may be similar to this: Spring Security issue with securing URLs dynamically
Below the relevant parts of the custom FilterInvocationSecurityMetadataSource
public class DbFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
FilterInvocation fi=(FilterInvocation)object;
String url=fi.getRequestUrl();
System.out.println("URL requested: " + url);
String[] stockArr = new String[]{"ROLE_ADMIN"};
return SecurityConfig.createList(stockArr);
}
Below the relevant parts of the custom implementation of securitywebconfigAdapter
#Configuration
public class Security extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
FilterInvocationSecurityMetadataSource newSource = new DbFilterInvocationSecurityMetadataSource();
fsi.setSecurityMetadataSource(newSource);
return fsi;
}
})
.and()
.formLogin()
.permitAll();
}
Below the relevant parts for custom userDetails authorities.
The user has the role: ROLE_ADMIN in database.
public class CustomUserDetails extends User implements UserDetails {
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<String> dbRoles=new ArrayList<String>();
for (Role userRole : super.getRoles()) {
dbRoles.add(userRole.getType());
}
List<SimpleGrantedAuthority> authorities=new ArrayList<SimpleGrantedAuthority>();
for (String role : dbRoles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
What am I doing wrong??
If more code is needed just comment below.
If you have even good books where I can learn this dynamic part of Spring security authorization comment below.
Thanks!
I managed to get into the security flow by debugging and it seems that by creating ConfigAttributes of this SecurityConfig class is the 'culprit'
return SecurityConfig.createList(stockArr);
public static List<ConfigAttribute> createList(String... attributeNames) {
Assert.notNull(attributeNames, "You must supply an array of attribute names");
List<ConfigAttribute> attributes = new ArrayList(attributeNames.length);
String[] var2 = attributeNames;
int var3 = attributeNames.length;
for(int var4 = 0; var4 < var3; ++var4) {
String attribute = var2[var4];
attributes.add(new SecurityConfig(attribute.trim()));
}
return attributes;
}
Above is the actual implementation of the method where you can see
attributes.add(new SecurityConfig(attribute.trim()));
And this always creates an instance of SecurityConfig type.
And below you can actually see where and how the decision is being made.
private WebExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
Iterator var2 = attributes.iterator();
ConfigAttribute attribute;
do {
if (!var2.hasNext()) {
return null;
}
attribute = (ConfigAttribute)var2.next();
} while(!(attribute instanceof WebExpressionConfigAttribute));
return (WebExpressionConfigAttribute)attribute;
}
So in order for it to actually return a configattribute for checking it must be of type WebExpressionConfigAttribute which is never going to be the case because of this
attributes.add(new SecurityConfig(attribute.trim()));
So the way I fixed it is to create my own accessDecisionManager the following way
public class MyAccessDecisionManager implements AccessDecisionManager {
#Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if(configAttributes == null){
return ;
}
Iterator<ConfigAttribute> ite = configAttributes.iterator();
while(ite.hasNext()){
ConfigAttribute ca = ite.next();
String needRole = ((SecurityConfig)ca).getAttribute();
for(GrantedAuthority grantedAuthority : authentication.getAuthorities()){
if(needRole.trim().equals(grantedAuthority.getAuthority().trim())){
return;
}
}
}
throw new AccessDeniedException("Access is denied");
}
And registering as above now setting the accessdecisionManager with my custom one
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
FilterInvocationSecurityMetadataSource newSource = new DbFilterInvocationSecurityMetadataSource();
fsi.setSecurityMetadataSource(newSource);
fsi.setAccessDecisionManager(new MyAccessDecisionManager());
return fsi;
}
I am using a ResourceProcessor to add additional links to my resource object when listed in a collection or fetched individually. However, when I apply a projection (or an excerpt project) to my repository, the ResourceProcessor does not get run and thus my links for that resource do not get created. Is there a means to allow my custom resource links to be added to a resource regardless of how the resource content is projected?
I think this issue is describing your case:
https://jira.spring.io/browse/DATAREST-713
Currently, spring-data-rest does not offer functionality to solve your problem.
We are using a little workaround that still needs a separate ResourceProcessor for each projection but we do not need to duplicate the link logic:
We have a base class that is able to get the underlying Entity for a Projection and invokes the Entity's ResourceProcessor and applies the links to the Projection.
Entity is a common interface for all our JPA entities - but I think you could also use org.springframework.data.domain.Persistable or org.springframework.hateoas.Identifiable.
/**
* Projections need their own resource processors in spring-data-rest.
* To avoid code duplication the ProjectionResourceProcessor delegates the link creation to
* the resource processor of the underlying entity.
* #param <E> entity type the projection is associated with
* #param <T> the resource type that this ResourceProcessor is for
*/
public class ProjectionResourceProcessor<E extends Entity, T> implements ResourceProcessor<Resource<T>> {
private final ResourceProcessor<Resource<E>> entityResourceProcessor;
public ProjectionResourceProcessor(ResourceProcessor<Resource<E>> entityResourceProcessor) {
this.entityResourceProcessor = entityResourceProcessor;
}
#SuppressWarnings("unchecked")
#Override
public Resource<T> process(Resource<T> resource) {
if (resource.getContent() instanceof TargetAware) {
TargetAware targetAware = (TargetAware) resource.getContent();
if (targetAware != null
&& targetAware.getTarget() != null
&& targetAware.getTarget() instanceof Entity) {
E target = (E) targetAware.getTarget();
resource.add(entityResourceProcessor.process(new Resource<>(target)).getLinks());
}
}
return resource;
}
}
An implementation of such a resource processor would look like this:
#Component
public class MyProjectionResourceProcessor extends ProjectionResourceProcessor<MyEntity, MyProjection> {
#Autowired
public MyProjectionResourceProcessor(EntityResourceProcessor resourceProcessor) {
super(resourceProcessor);
}
}
The implementation itself just passes the ResourceProcessor that can handle the entity class and passes it to our ProjectionResourceProcessor. It does not contain any link creation logic.
Here is a generic solution:
#Component
public class ProjectionProcessor implements RepresentationModelProcessor<EntityModel<TargetAware>> {
private final RepresentationModelProcessorInvoker processorInvoker;
public ProjectionProcessor(#Lazy RepresentationModelProcessorInvoker processorInvoker) {
this.processorInvoker = processorInvoker;
}
#Override
public EntityModel<TargetAware> process(EntityModel<TargetAware> entityModel) {
TargetAware content = entityModel.getContent();
if (content != null) {
entityModel.add(processorInvoker.invokeProcessorsFor(EntityModel.of(content.getTarget())).getLinks());
}
return entityModel;
}
}
It gets links for original entities and adds them to corrseponding projections.
Let's assume we have a simple payment feature on an online shop. We want to manage different transactions with different processors of transactions:
A transaction can be a payment or a refund.
A processor of transactions can be Paypal or Payplug.
So we have the following classes:
class PaymentTransaction implements Transaction {
}
class RefundTransaction implements Transaction {
}
class PaypalProcessor implements Processor {
}
class PayplugProcessor implements Processor {
}
As suggested in this answer, we could use the following class which uses Strategy and polymorphism.
class PaymentProcessor {
private Processor processor;
private Transaction transaction;
public PaymentProcessor(Processor processor, Transaction transaction) {
this.processor = processor;
this.transaction = transaction;
}
public void processPayment() {
processor.process(transaction);
}
}
We assume the processor and the transaction to use are given from the database. I wonder how to create the PaymentProcessor object.
It seems that an abstract factory class with only one method is still a valid Abstract Factory pattern. So, in this case I wonder if using Abstract Factory would be relevant.
If yes, how to implement it?
If no, should we use Factory Method pattern with a PaymentProcessorFactory class to create PaymentProcessor with his two attributes according the details given from the database?
What is a best practice to use a factory in this case?
We assume the processor and the transaction to use are given from the database. I wonder how to create the PaymentProcessor object.
I would define an interface that I can adapt to the database result or any other source that can provide the data needed to create a PaymentProcessor. This is also useful for unittests.
public interface PaymentProcessorFactoryArgs {
String getProcessorType();
String getTransactionType();
}
and then implement a factory like this.
public class PaymentProcessorFactory {
private Map<String, Processor> processorMap = new HashMap<>();
private Map<String, Transaction> transactionMap = new HashMap<>();
public PaymentProcessorFactory() {
processorMap.put("paypal", new PaypalProcessor());
processorMap.put("payplug", new PayplugProcessor());
transactionMap.put("refund", new RefundTransaction());
transactionMap.put("payment", new PaymentTransaction());
}
public PaymentProcessor create(PaymentProcessorFactoryArgs factoryArgs) {
String processorType = factoryArgs.getProcessorType();
Processor processor = processorMap.get(processorType);
if(processor == null){
throw new IllegalArgumentException("Unknown processor type " + processorType);
}
String transactionType = factoryArgs.getTransactionType();
Transaction transaction = transactionMap.get(transactionType);
if(transaction == null){
throw new IllegalArgumentException("Unknown transaction type " + processorType);
}
return new PaymentProcessor(processor, transaction);
}
}
This is just a quick example. It would be better if you can register Processors and Transactions. E.g.
public void register(String processorType, Processor processor){
...
}
public void register(String transactionType, Transaction transaction){
...
}
You also might want to use anther type then String for the keys, maybe an enum.
In this example the Processor and Transaction objects are re-used every time a PaymentProcessor is created. If you want to create new objects for each PaymentProcessor, you can replace the Maps type
private Map<String, Factory<Processor>> processorMap = new HashMap<>();
private Map<String, Factory<Transaction>> transactionMap = new HashMap<>();
with anther factory interface. E.g.
public interface Factory<T> {
public T newInstance();
}
Maybe you can use the builder pattern. In the builder pattern there is a class called the director, which knows the algorithm of creating a complex object. To create the components the complex object is build of the director uses a builder. Like this you can change specific components to build up the whole complex object.
In your case the PaymentProcessor (the complex object) is composed out of a Payment and a Processor, so the algorithm is to inject them into a PaymentProcessor. The builder should build the parts. To build a paypal-refund combination you should create a builder which returns a PaypalProcessor and a RefundTransaction. When you want to create a payplug-payment the builder should return a PaymentTransaction and a PayPlugProcessor.
public interface PaymentProcessorBuilder {
public Transaction buildTransaction();
public Processor buildProcessor();
}
public class PaypalRefundProcessorBuilder implements PaymentProcessorBuilder {
public Transaction buildTransaction {
return new RefundTransaction();
}
public Processor buildProcessor {
return new PayPalProcessor();
}
}
public class PayPlugPaymentProcessorBuilder implements PaymentProcessorBuilder {
public Transaction buildTransaction {
return PaymentTransaction();
}
public Processor buildProcessor {
return new PayPlugProcessor();
}
}
Now the Director can use the builder to compose the PaymentProcessor:
publi PaymentProcessorDirector {
public PaymentProcessor createPaymentProcessor(PaymentProcessorBuilder builder) {
PaymentProcessor paymentProcessor = new PaymentProcessor();
paymentProcessor.setTransaction(builder.buildTransaction());
paymentProcessor.setProcessor(builder.buildProcessor());
return paymentProcessor;
}
}
The created PaymentProcessor depends now on the passed Builder:
...
PaymentProcessorDirector director = new PaymentProcessorDirector();
PaymentProcessorBuilder builder = new PaypalRefundProcessorBuilder();
PaymentProcessor paymentProcessor = director.createPaymentProcessor(builder);
...
For each combination you can create a builder. If you pass the right builder to the director you get the wanted PaymentProcessor back.
Now the question how could you get the right builder. Therefore you can use a factory, that takes some event arguments and decides then which builder has to be made. This builder you pass in the director an get the wanted PaymentProcessor.
CAUTION: This is only one possible solution for this problem. Every solution has is advantages and disadvantages. To find the right solution you to balance the good and the bad things.
PS: Hope the syntax is correct. Im not a java developer.
EDIT:
You could interprete the director of the builder pattern as a PaymentProcessorFactory with the builder itself as strategy for building the parts of the PaymentProcessor
Following is my code isolation.
Interactable Interface.
public interface Interactable <E extends Interactable> {
List<Person> personsInteracting = new ArrayList<>();
List<Person> personsWaiting = new ArrayList<>();
long INTERACTION_TIME = 5 * 60;
default int getNumberOfPeopleInteracting () {
return personsInteracting.size();
}
default int getNumberOfPeopleWaiting () {
return personsWaiting.size();
}
boolean isMultipleActionsAllowed ();
boolean isFurtherActionsAllowed ();
public abstract boolean tryOccupiedBy (final Person person, final Interactions interaction)
throws InteractionNotPossibleException;
E getObject ();
EnumSet<Interactions> getInteractions ();
}
InteractiveObject Abstract Class
public abstract class InteractiveObject implements Interactable {
protected final String name;
protected int numberOfSimultaneousInteractions;
protected Interactions currentInteraction;
public InteractiveObject (final String name) {
this.name = name;
}
#Override
public boolean isMultipleActionsAllowed () {
return numberOfSimultaneousInteractions > 1;
}
#Override
public boolean isFurtherActionsAllowed () {
return personsInteracting.isEmpty() ||
(getNumberOfPeopleInteracting() > numberOfSimultaneousInteractions);
}
#Override
public boolean tryOccupiedBy (final Person person, final Interactions interaction)
throws InteractionNotPossibleException {
boolean isOccupied = false;
if (!isFurtherActionsAllowed()) {
throw new InteractionNotPossibleException(this + " is already in use by some other " +
"person.");
}
personsInteracting.add(person);
currentInteraction = interaction;
return isOccupied;
}
#Override
public String toString () {
return name;
}
public int getNumberOfSimultaneousInteractions () {
return numberOfSimultaneousInteractions;
}
}
Chair (One of the child class)
public class Chair extends InteractiveObject {
private final EnumSet<Interactions> INTERACTIONS = EnumSet.copyOf(Arrays.asList(
new Interactions[] {Interactions.DRAG, Interactions.SIT}));
public Chair (final String objectName) {
super(objectName);
super.numberOfSimultaneousInteractions = 1;
}
#Override
public Interactable getObject () {
return this;
}
#Override
public EnumSet<Interactions> getInteractions () {
return INTERACTIONS;
}
}
Here is the piece of code that executes and brings the problem, this question is asked for.
final InteractiveObject chair1 = new Chair("Chair1");
final Person person1 = new Person("Person1");
final Room room = new Room("Room1", 2, 2);
room.personEnters(person1);
room.putObject(chair1);
person1.tryOccupying(chair1);
Above piece of code, successfully occupies the chair object. Now,
final InteractiveObject chair2 = new Chair("Chair2");
final Person person2 = new Person("Person2");
final Room room2 = new Room("Room2", 2, 2);
room2.personEnters(person2);
room2.putObject(chair2);
person2.tryOccupying(chair2);
This piece of code doesn't let the person2 occupy since my code states that 1 person is already interacting with chair2, where as no one is interacting with it.
Solution of my problem:
I moved my List of personInteracting to InteractiveObject and function tryOccupiedBy to each child class and everything works fine.
Questions:
I put personsInteracting in Interactable interface since I believe that every future implementation of Interactable will have it. Developers won't have to implement themselves. (But perhaps this idea seems to be wrong)
If tryOccupiedBy function has same implementation, what is the purpose of whole OOP?
I now know that the isolation was wrong and I know where to place the pieces to get the results. But can someone kindly point me out about some OOP concept which I did not understand and should be implemented in a much better way?
The default keyword was not added to the Java language to do the kind of thing which you seem to be trying to achieve. Data defined in an interface is intended to be constant - the modifiers 'public static' are automatically applied to any field definitions in an interface. If you create a default method in the interface then it must either be stateless or act directly only on purely statically available state. Default methods can call other interface methods to modify instance state, .
By placing personsInteracting field in the interface, you made the same instance common to every object implementing that interface, and so your tryOccupying method was acting on purely global state.
So, the purpose of having default methods in the Java language is to support adding new methods to interfaces in a backwards compatible fashion, nothing more. You shouldn't reuse it as a generic form of code re-use - it was never intended for that and you'll get (as you did) weird behaviour.
You didn't have to put tryOccupiedBy in the child classes, however, so you didn't have to have a load of duplicated code. You could still declare the method signature in the interface (which is what interfaces are generally supposed to do) and then implement the common method in your abstract base class. By putting the data fields in the base class, you make them instance fields and so they are not shared between objects.
public interface Interactable <E extends Interactable> {
...
boolean tryOccupiedBy (final Person person, final Interactions interaction)
throws InteractionNotPossibleException;
...
}
public abstract class InteractiveObject implements Interactable {
private final List<Person> personsInteracting = new ArrayList<>();
private final List<Person> personsWaiting = new ArrayList<>();
...
#Override
public final boolean tryOccupiedBy (final Person person, final Interactions interaction)
throws InteractionNotPossibleException {
boolean isOccupied = false;
if (!isFurtherActionsAllowed()) {
throw new InteractionNotPossibleException(this + " is already in use by some other " +
"person.");
}
personsInteracting.add(person);
currentInteraction = interaction;
return isOccupied;
}
...
}
I am using Hazelcast 3.6.1 to read from a Map. The object class stored in the map is called Schedule.
I have configured a custom serializer on the client side like this.
ClientConfig config = new ClientConfig();
SerializationConfig sc = config.getSerializationConfig();
sc.addSerializerConfig(add(new ScheduleSerializer(), Schedule.class));
...
private SerializerConfig add(Serializer serializer, Class<? extends Serializable> clazz) {
SerializerConfig sc = new SerializerConfig();
sc.setImplementation(serializer).setTypeClass(clazz);
return sc;
}
The map is created like this
private final IMap<String, Schedule> map = client.getMap("schedule");
If I get from the map using schedule id as key, the map returns the correct value e.g.
return map.get("zx81");
If I try to use an SQL predicate e.g.
return new ArrayList<>(map.values(new SqlPredicate("statusActive")));
then I get the following error
Exception in thread "main" com.hazelcast.nio.serialization.HazelcastSerializationException: There is no suitable de-serializer for type 2. This exception is likely to be caused by differences in the serialization configuration between members or between clients and members.
The custom serializer is using Kryo to serialize (based on this blog http://blog.hazelcast.com/comparing-serialization-methods/)
public class ScheduleSerializer extends CommonSerializer<Schedule> {
#Override
public int getTypeId() {
return 2;
}
#Override
protected Class<Schedule> getClassToSerialize() {
return Schedule.class;
}
}
The CommonSerializer is defined as
public abstract class CommonSerializer<T> implements StreamSerializer<T> {
protected abstract Class<T> getClassToSerialize();
#Override
public void write(ObjectDataOutput objectDataOutput, T object) {
Output output = new Output((OutputStream) objectDataOutput);
Kryo kryo = KryoInstances.get();
kryo.writeObject(output, object);
output.flush(); // do not close!
KryoInstances.release(kryo);
}
#Override
public T read(ObjectDataInput objectDataInput) {
Input input = new Input((InputStream) objectDataInput);
Kryo kryo = KryoInstances.get();
T result = kryo.readObject(input, getClassToSerialize());
input.close();
KryoInstances.release(kryo);
return result;
}
#Override
public void destroy() {
// empty
}
}
Do I need to do any configuration on the server side? I thought that the client config would be enough.
I am using Hazelcast client 3.6.1 and have one node/member running.
Queries require the nodes to know about the classes as the bytestream has to be deserialized to access the attributes and query them. This means that when you want to query on objects you have to deploy the model classes (and serializers) on the server side as well.
Whereas when you use key-based access we do not need to look into the values (neither into the keys as we compare the byte-arrays of the key) and just send the result. That way neither model classes nor serializers have to be available on the Hazelcast nodes.
I hope that makes sense.